🧰 The platform (for whoever operates it)
Underneath the sections there's a platform layer that keeps everything running and audited. It's
managed from the command line with nocloud — every command below is listed with its flags in
the CLI reference.
Scheduled tasks (jobs)
Everything that runs on its own — refreshing quotes, recalculating the home screen, backups,
ingests — lives in a job registry (config/jobs.yaml) with its schedule, host, timeout and what
it produces.
nocloud jobs list # list jobs and their state
nocloud jobs status # last result per job
nocloud jobs run <id> # trigger one by hand
nocloud jobs history # recent runs (add an id to filter)
No hidden tasks in an unreadable crontab: the inventory is a single, versioned list. A job that is
already running is locked (a second run is refused while the first one's process is alive), and a
job that exceeds its timeout is stopped and recorded as timeout.
Events, auditing and triggers
Every relevant action emits an event (with severity, author, message and data) into an audit
stream with a fixed schema (config/events.yaml).
nocloud audit summary # summary of the event stream
nocloud audit list # latest audit entries
nocloud events # latest platform events (--limit N)
Events can also cause things: triggers (config/triggers.yaml) map an event kind — plus
optional field filters — to a job, so "a WhatsApp export finished ingesting" can automatically
queue "rebuild the messaging pages" without a human in between. The trigger engine tails the same
audit stream, so every automated reaction is itself audited.
Validated configuration
The instance's configuration is described by a schema (config/schema.yaml): the manager
validates known keys and masks secrets in any output.
nocloud config list # every key, its value (secrets masked) and status
nocloud config check # validate site.env against the schema
nocloud config set KEY VALUE # write a value (backs up site.env first)
Diagnostics: nocloud doctor
nocloud doctor # installation diagnostics (--json for automation)
doctor runs a battery of checks and reports each one individually: git and Python availability,
config/runtime.yaml and config/jobs.yaml, a non-empty job registry, config/site.env, the
configuration schema, the SQLite catalog (existence, integrity, schema version) and its seeded
sections, a known build directory, jobs with no recorded failures, module manifests, the backup
contract (both the live files it promises to copy and whether a fresh, intact snapshot actually
exists at the backup destination), orphaned journal operations, the audit event stream, the
upgrade lifecycle, the
integration adapters, and whether the local daemon (and, once a remote server is configured, its
own APIs) are actually answering. It exits non-zero if any check fails — see
Troubleshooting for what each failing check means.
The upgrade lifecycle
Upgrading isn't "copy and pray": it's a lifecycle with distinct phases and a point of no return.
preflight → backup → migrate → build → [deploy] → verify
nocloud upgrade run executes the phases in that order, but skips deploy unless you pass
--deploy — so the default run upgrades the workstation without touching the server. Use
nocloud upgrade plan to see every phase (including the dry-run-only rollback phase),
preflight to check readiness (a dirty git tree blocks it; --allow-dirty overrides), and
--dry-run to rehearse without changing anything. If a phase fails, the snapshot taken during
backup lets you roll back.
The daemon
A small daemon on the workstation (nocloud daemon, port 8765 on 127.0.0.1 by default)
serves the platform's state over a local read-only API — health, jobs and their history, events,
audit, upgrade status, integrations, configuration — plus one write endpoint: triggering a job on
demand (POST /api/jobs/<id>/run). That's what a Store connector's "refresh now" button calls.
Protect it with a bearer token by setting NOCLOUD_DAEMON_TOKEN. The full endpoint list is in
the CLI reference.
The "typing pause"
Heavy background work follows one courtesy rule on the workstation: intensive AI/curation tasks freeze while you're typing and resume once you stop, so they never compete with you for the machine while you're using it. This is handled by a small launchd agent (it suspends and resumes the worker processes on keyboard activity), independent of the daemon — jobs you trigger by hand run immediately.