Skip to main content

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>.yaml in the state directory) against what's actually running, and converges by 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 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). These are the daemon's own subcommands, separate from the cosmonic developer CLI that scaffolds and runs projects:

CommandWhat it does
cosmonicd runRun 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 pathsPrint 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 toolchain bundle [--triple <t> | --all-platforms] [--out <p>]Build an offline OCI bundle of the signed wash/wkg/wasm-tools build tools for an air-gapped install. Pair it with cosmonicd oci import.
cosmonicd mcp serveServe 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):

VariableEffect
COSMONIC_STATE_DIRRelocate the state directory (Workload specs, OCI cache, config stores).
COSMONIC_HTTP_ADDRBind the workload HTTP ingress elsewhere (default 127.0.0.1:8200).
COSMONIC_FLAG_<KEY> / COSMONIC_DRAFTPre-set feature flags (the toggles under Settings → Labs).
COSMONIC_TELEMETRY / COSMONIC_USAGEPre-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.