The cosmonicd Daemon
cosmonicd is a daemon that embeds the wasmCloud host. Cosmonic Desktop's graphical interface is a client; if the client is closed, workloads keep running, because the daemon is what's actually running them.
Overview
The cosmonicd daemon performs the following roles:
- Reconciles: continuously compares your declared Workload specs (plain YAML under
workloads/<namespace>/<name>.yamlin the state directory) against what's actually running, and converges—pulling, starting, stopping, and restarting with backoff. Permanent failures fail fast with the cause in the Logs view. - Pulls and verifies: fetches component images into a content-addressed OCI cache (browsable as the Local Registry), digest-pins them at apply time, and checks cosign signatures on every start.
- Resolves configuration and secrets: merges config sources and resolves secret references (keychain, 1Password, AWS Secrets Manager, environment) at workload start—values live in memory, injected into the component, and are zeroized after use.
- Serves ingress: one local HTTP listener (default
127.0.0.1:8200) routing to workloads by hostname. - Answers the API: JSON over a Unix socket (macOS/Linux) or per-user named pipe (Windows). No TCP listener and no tokens—the peer-checked socket is the trust boundary. The app, the tray, and the MCP server are all clients of this one API.
How it runs
The daemon is a per-user service, configured by the installer or the app's first run: a LaunchAgent on macOS, a systemd user service on Linux (with lingering on package installs, so workloads survive logout), and a login-started process on Windows. The install guides cover each platform's specifics, and Troubleshooting covers restarting it.
Daemon logs stream to the Logs view; on macOS they also land in ~/Library/Logs/Cosmonic/cosmonicd.log.
The cosmonicd CLI
The daemon binary is also a small CLI (where it lives per platform):
| Command | What it does |
|---|---|
cosmonicd run | Run the daemon in the foreground (what the service invokes). --mcp also enables and auto-registers the MCP server at boot; --telemetry opts this run into crash reporting. |
cosmonicd paths | Print the resolved state directory, socket/pipe, and runtime locations. |
cosmonicd oci export <image> <path> | Export an image (and its cosign signature, when available) from the local cache as an OCI image-layout directory or .tar—the outbound half of air-gap transfer. |
cosmonicd oci import <path> | Import an OCI layout or .tar into the local cache, so workloads can start with no registry access. |
cosmonicd mcp serve | Serve the Model Context Protocol over stdio—spawned by MCP clients, not run by hand. |
cosmonicd uninstall [--purge] | Deregister the daemon and tray login services and stop the tray; --purge also deletes the state directory. See Uninstall. |
Environment variables
Set these on the daemon process (for a service, in the unit/agent definition; for ad-hoc runs, in the shell):
| Variable | Effect |
|---|---|
COSMONIC_STATE_DIR | Relocate the state directory (Workload specs, OCI cache, config stores). |
COSMONIC_HTTP_ADDR | Bind the workload HTTP ingress elsewhere (default 127.0.0.1:8200). |
COSMONIC_FLAG_<KEY> / COSMONIC_DRAFT | Pre-set feature flags (the toggles under Settings → Labs). |
COSMONIC_TELEMETRY / COSMONIC_USAGE | Pre-decide the two telemetry consents and lock their toggles. |
Headless use
Nothing about the daemon requires the app: it starts workloads from specs on disk, serves the same API over the socket, and can be driven by an agent over MCP or by scripts. Here's a complete headless session—isolated daemon, deploy, call—using only curl and jq:
# 1. Start a daemon with isolated state and a custom ingress port.
# (Keep the state dir path short — the API socket lives inside it,
# and Unix socket paths have a ~100-character limit.)
export COSMONIC_STATE_DIR=/tmp/cosmonic COSMONIC_HTTP_ADDR=127.0.0.1:8210
cosmonicd run &
# 2. Draft a Workload from an image reference — the same synthesis the
# app's run flow performs, capability inference included.
curl -sS --unix-socket /tmp/cosmonic/cosmonicd.sock \
-X POST http://localhost/v1/synthesize \
-H 'content-type: application/json' \
-d '{"source":"ghcr.io/cosmonic-labs/control-demos/hello-world:0.1.2"}' \
| jq .workload > workload.json
# 3. Review workload.json (this is your approval step), then apply it.
curl -sS --unix-socket /tmp/cosmonic/cosmonicd.sock \
-X POST http://localhost/v1/workloads \
-H 'content-type: application/json' -d @workload.json
# 4. Watch it converge, then call it.
curl -sS --unix-socket /tmp/cosmonic/cosmonicd.sock http://localhost/v1/workloads \
| jq '.[0].status.state' # → "running"
curl -H 'Host: hello-world.localhost' http://127.0.0.1:8210/
# → Hello from Cosmonic Control!Combined with cosmonicd oci import, the same pattern runs fully air-gapped: import the artifact bundle first and the apply starts with no registry access. A standalone daemon binary for server use is available on request—and when you outgrow one machine, the same Workload specs run under Cosmonic Control on Kubernetes.