Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

cosmon

Noogram is an open system for running long AI-agent missions inside your own perimeter, keeping every step as plain files you own. Its kernel, cosmon, is a stateless CLI that gives each agent an identity, a lifecycle, and crash recovery.

The code lives at github.com/noogram/cosmon, open-core: the kernel, the CLI, and the runtime are AGPL-3.0-only, and the network SDK third parties link to talk to an instance over the wire is Apache-2.0 (LICENSE maps the split crate by crate). It is early-stage but functional — the core types, the cs CLI, state persistence, tmux transport, and the DAG engine all ship today, and the API is still moving, so expect breaking changes before 1.0.

  • A social organization of agents. A long mission becomes small tasks, each with a precise goal. Agents take them on side by side, wait on one another when one task depends on another, and cross-examine each other's findings — panels, reviews, counter-arguments — before anything reaches you. Work at scale, the way a good team organizes itself.
  • Runs inside your perimeter. The agent works on your corpus, on your machine. Every step, every decision, and every result is written to plain files on a disk you control. Only the model call leaves your machine — no server in the loop, no database, no Cosmon account.
  • You stay the judge. The agent hands you a draft on its own branch, with its reasoning and evidence alongside; what the gates couldn't verify is marked unverified, never silently accepted. Nothing lands until it passes your gates.
  • The story can't be quietly rewritten. Every mission leaves a complete, replayable work record. If anyone — human or agent — edits it after the fact without resealing it, cs verify notices. It catches a careless edit, not a determined forger.
  • A crash is a pause, not a loss. Everything the agents record lives in those same plain files, so a fresh worker picks up where a crashed one stopped.
  • A harness over the harnesses you already use: Claude Code, Codex, Aider, and other CLI agents; hosted APIs from Anthropic, OpenAI, Google Gemini, Mistral AI, Qwen, DeepSeek, GLM, Kimi, and more; or local models through llama.cpp and Ollama.
  • Federate (under construction). Several machines cooperating on one mission, with no central owner.
Long AI-agent missions run on your machine: a pilot drives a chain of agents that write every step to the .cosmon/ folder as plain files you own; only the model call leaves your machine.

noogram and its cosmon kernel

On a single machine, the tool you run is cosmon; its command is cs. You cs tackle a piece of work to start an agent on it, and cs done to close it out; the record of both lands under .cosmon/.

Noogram's ambition is a federated agentic system: many cosmon instances cooperating, each keeping its own record, with no single owner in the middle. The first brick is already here: the remote mode, where a cosmon-remote client talks to a cosmon-rpp-adapter service over HTTP(S) on another host. Broader peer-to-peer federation between instances is on the roadmap; the shape of that link is still being explored. That larger, cooperating whole is noogram; cosmon is its kernel. Today, run several agents in parallel on one machine and cosmon does that by itself, complete and standalone. See Noogram & the Cosmon kernel for the relationship, and Agent adapters for how a concrete agent or model plugs in.

Where to go next

This site is built by mdBook and rendered by the same pipeline that builds cosmon's own documentation.

Install cosmon

Cosmon ships as one binary, cs. There is no daemon to run, no service to register, no account to create: you put a single file on your PATH and you are done.

Pick whichever of the three routes below fits how you already manage tools. The first two install the same bytes — the release pipeline builds the tarballs once, signs them once, and Homebrew's formula is rendered from those very artifacts. The third compiles from source, for platforms outside the four release targets.

Already installed? Skip to Ten minutes to cosmon.

Works on macOS and Linux, on arm64 and x86_64:

curl -fsSL https://noogram.org/cosmon/install.sh | sh

Then confirm:

cs --version
cs --help

You should see the command groups (lifecycle, fleet, execution, …). If the shell cannot find cs, the installer printed the export PATH=… line you need — add it to your shell profile and re-open the terminal.

The same route, verifying the installer first

The installer is signed — every release publishes it as cosmon-install-<version>.sh with a .sig and a .pem beside it, keyless and Rekor-anchored like the binaries. But piping it into sh consumes it before anything could check that signature, so on the one-liner above the signature does no work. Reported by an external reader on issue #32, and correct: the bytes served at that URL are byte-identical to the signed asset today, which is exactly the property an attacker at the CDN or in the TLS path would change.

The convenience route stays. If you would rather check before you run — on a shared machine, in CI, or the first time you install cosmon anywhere — download the versioned asset, verify it, then run it:

ver=0.6.0                                   # the release you want
base="https://github.com/noogram/cosmon/releases/download/v${ver}"
curl -fsSLO "${base}/cosmon-install-${ver}.sh"
curl -fsSLO "${base}/cosmon-install-${ver}.sh.sig"
curl -fsSLO "${base}/cosmon-install-${ver}.sh.pem"

cosign verify-blob \
  --certificate-identity-regexp 'https://github.com/.*/cosmon/.github/workflows/release.yml@.*' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --signature  "cosmon-install-${ver}.sh.sig" \
  --certificate "cosmon-install-${ver}.sh.pem" \
  "cosmon-install-${ver}.sh" \
  && sh "cosmon-install-${ver}.sh"

cosign verify-blob exits non-zero on anything it cannot tie back to release.yml at a cosmon tag, and the && is what makes that exit status refuse to run the script. Everything after that is the same installer doing the same sha256 check on the same tarballs — you have only moved the trust boundary from the endpoint served me these bytes to this workflow, at this tag, produced them.

What that one line actually does

Piping a script from the internet into your shell deserves an explanation, so here is the whole of it. The installer:

  1. Detects your platform from uname -s and uname -m, and maps it to one of the four targets cosmon builds: macOS on arm64 or x86_64, Linux on x86_64 or arm64. Anything else is refused with a clear message rather than guessed at. To see what it resolves for your machine without installing anything: curl -fsSL https://noogram.org/cosmon/install.sh | sh -s -- --print-target.
  2. Downloads the release SHA256SUMS from the GitHub Releases of noogram/cosmon. That file is the source of truth for both the exact tarball name and its digest, which is how the installer can ask for latest without knowing the version string up front.
  3. Downloads the tarball for your target over HTTPS (--proto '=https' --tlsv1.2), using curl or wget, whichever you have.
  4. Verifies the sha256 of what it downloaded against SHA256SUMS. This leg is fail-closed: a mismatch, a missing digest, or no sha256sum/shasum on the box all abort the install rather than proceeding. Nothing is written to your PATH before the digest matches.
  5. Unpacks and installs cs into ~/.local/bin, falling back to /usr/local/bin if that directory is not writable. The tarball also carries cosmon-remote — the connector for driving a remote cosmon service — and the installer places it in the same directory, so one command gives you both laptop tools.

It carries no secret and needs no privilege beyond writing to that one directory.

Choosing a version

The default is the latest release. To pin a specific one, either flag or environment works:

curl -fsSL https://noogram.org/cosmon/install.sh | sh -s -- --version v0.1.0
# or
curl -fsSL https://noogram.org/cosmon/install.sh | COSMON_VERSION=v0.1.0 sh

v0.1.0 is the tag format the installer expects, shown here as an example — pinning any specific version requires that tag to actually exist as a published release. --dir <path> (or COSMON_INSTALL_DIR) changes where cs lands.

Route 2 — Homebrew

Since v0.2.0 the tap noogram/homebrew-tap is live, on macOS and on Linuxbrew, arm64 and x86_64 alike:

brew install noogram/tap/cosmon

This is not a separate build. The release pipeline renders the formula from the same tagged, signed release tarballs the install script downloads, and brew verifies the same sha256 digests. Identical bytes, identical provenance.

Route 3 — build from source

If you would rather compile it yourself — or you are on a platform outside the four release targets — build from the cosmon repository.

On Linux (glibc) the build links the Secret Service keyring backend through libdbus, so install the system headers first, otherwise the compile fails at libdbus-sys with "The system library dbus-1 required by crate libdbus-sys was not found". macOS needs nothing extra (it uses the native keychain), and the prebuilt Linux release binaries above are static musl, so this applies only when you compile on glibc:

sudo apt install libdbus-1-dev pkg-config          # Debian/Ubuntu
sudo dnf install dbus-devel pkgconf-pkg-config     # Fedora

Then build:

git clone https://github.com/noogram/cosmon && cd cosmon
cargo install --path crates/cosmon-cli --locked

Re-run cs --help afterwards to confirm it landed on your PATH. Note that a source build is your build: it is not covered by the release signature, so the provenance check below does not apply to it.

Verify where the binary came from

The sha256 check proves the bytes match the digest the release published. It does not, on its own, prove who produced that release. That proof is a cosign signature check you run once, deliberately, and it is worth doing:

Verify the binary's provenance

A note on package registries

The product is the cs binary published on GitHub Releases, versioned by the git tag it was built from. If cosmon ever appears on crates.io, npm, or PyPI, those entries are name-holds, not the shipped binary — they exist to hold the name and point back here. Do not expect cargo install cosmon / npm install cosmon / pip install cosmon to give you the released binary.

Next

Ten minutes to cosmon

This is the shortest path from an empty terminal to one piece of work that an AI agent did, finished, and merged into your main. Every block below is meant to be copied and run in order.

If you want the same journey with the why behind each verb, take the tutorials instead — this page is the ramp, they are the lesson.

0. What you need

Three things beyond cs itself, because a cosmon worker is a real terminal session doing real git work:

git --version         # each worker runs on its own branch, in its own worktree
tmux -V               # each worker lives in a tmux session
ollama serve          # a model backend on localhost:11434 (the default adapter)
ollama pull qwen3:8b  # …serving a model. `serve` alone serves nothing

ollama serve with nothing pulled is the first sharp edge people hit: the daemon answers, so everything looks healthy, and the dispatch dies seconds after it starts. Cosmon now checks before spawning and refuses with a named repair — but pulling the model first skips the detour entirely.

Pull qwen3:8b specifically, which is also cosmon's built-in default. The local loop needs a model that emits structured tool_calls on /v1/chat/completions; qwen3:8b was measured to do that. A model that merely looks more capable is often the wrong choice — qwen2.5-coder:7b, for instance, pastes its tool call into the message text as raw JSON, which lands in your output verbatim instead of creating a file. Other models, and how to switch, are in docs/guides/local-model-selection.md.

Missing one? brew install git tmux / apt install git tmux, and see Set up cosmon for the backend options (a local OpenAI-compatible endpoint by default, or --adapter claude / aider / codex to pilot a coding-agent CLI you already use).

1. Install cs

curl -fsSL https://noogram.org/cosmon/install.sh | sh
cs --version

Homebrew and from-source routes, plus what that script does line by line, are on Install cosmon.

2. Initialise a project

From the root of any repository you want cosmon to track:

cd ~/path/to/your/project
cs init

That creates .cosmon/, the directory holding all of cosmon's state: your units of work, their event logs, and the canonical recipes. Later commands walk up to find it, the way git finds .git/. Running it twice is safe.

3. Create a unit of work

cs nucleate task-work --var topic="Add a --version flag to the CLI"

A formula (task-work) is the recipe: a small TOML file of ordered steps. A molecule is one run of that recipe — cosmon's unit of tracked work, with a state, a current step, and a durable trace on disk.

Nucleate creates the molecule. Nothing executes yet. The command prints an id:

Nucleated task-20260711-a1b2 (task-work): pending

Yours will differ; substitute it everywhere below.

4. Put it in motion

cs tackle task-20260711-a1b2

Tackle creates a git worktree and branch for this molecule, opens a tmux session, and launches your agent inside it with the briefing injected. It returns immediately — the worker runs in the background while your shell stays free.

5. Watch it work

cs peek

cs peek is the fleet portal: workers on the left, the selection followed on the right. Press p to drop into the live pane of the selected worker, q to come back up. Never tmux attach — it breaks the agent's rendering.

To block until the work is finished instead of watching it:

cs wait task-20260711-a1b2

6. Close the loop

cs done task-20260711-a1b2

Done merges the worker's branch into main, kills the tmux session, and removes the worktree. It is the only verb that merges: a worker can finish its own steps, but it cannot merge itself — that call stays yours.

Confirm:

cs status

The molecule shows as completed and no worker is running. That empty ensemble is the correct resting state.

The whole cycle, in one picture

cs nucleate   →   cs tackle   →   cs wait   →   cs done
  create          start a         block until    merge the
  the work        worker on it    it finishes    result, clean up

Everything the worker did is still on disk under .cosmon/, long after the tmux pane is gone. That on-disk trace is the point: a worker dying never loses your work.

Where to go next

Set up cosmon (prerequisites)

This is the first tutorial. By the end you will have every prerequisite in place, a project that cosmon can track, and everything the next tutorial, Your first molecule, needs to actually run. If you skip this page, the nucleate → tackle → wait → done cycle in that tutorial will stall on a missing tool, so do it here, once.

Just want cs on your machine? Installing the binary is its own page — Install cosmon — and a condensed run through the whole cycle is Ten minutes to cosmon. This tutorial covers what a worker needs around the binary (git, tmux, a model backend) and does not repeat the install routes.

New to the physics-inspired names (nucleate, evolve, spore, …)? You do not need them yet. This page installs tools; the vocabulary is introduced word by word as you meet it, and explained in full in The physics vocabulary.

What you are about to install

Cosmon steers agents, AI coding sessions that run in their own terminal, and it keeps their state in plain files inside your project. So the prerequisites are the things an agent needs to live in, plus the files cosmon writes to:

PrerequisiteWhy cosmon needs itCheck it is there
gitEach worker runs on its own git branch, in its own worktree. Cosmon merges that branch back when the work is done.git --version
tmuxA worker is a long-lived terminal session. Cosmon spawns each one inside a tmux pane so it survives your shell closing.tmux -V
A model backendThe actual worker. By default the built-in local adapter drives a local OpenAI-compatible endpoint (e.g. Ollama); or pass --adapter claude to launch an external CLI in the tmux pane.ollama serve (default) or claude --version
The cs binaryCosmon itself: a single stateless command-line tool.cs --help
At least one formulaA formula is the recipe a piece of work follows: a small TOML file of ordered steps. Cosmon ships canonical ones (like task-work) so you have one on day zero.(created by cs init, below)

If the first four checks all print a version, you already have the hard part.

Step 1: Confirm git and tmux

git --version     # e.g. git version 2.44.0
tmux -V           # e.g. tmux 3.4

If either is missing, install it with your platform's package manager (brew install git tmux, apt install git tmux, …) and re-run the checks.

Step 2: Confirm a model backend

Cosmon does not do the coding itself; it pilots a model that does. With no adapter configured the default is the built-in local adapter: cosmon drives the agent loop itself against a local OpenAI-compatible endpoint — for example Ollama on localhost:11434. Start that endpoint before the first dispatch:

ollama serve        # or any OpenAI-compatible endpoint on localhost:11434

To pilot an external coding-agent CLI instead, pass --adapter claude (Claude Code), aider, or codex; those need the tool installed and authenticated on your PATH. The adapter only has to be reachable by name; cosmon spawns it for you, you never call it directly. The full resolution chain (flag → $COSMON_DEFAULT_ADAPTER → config → built-in local) is in the adapter explanation.

Step 3: Install the cs binary

If you have not installed it yet, do it now — the routes (install script, Homebrew, from source), version pinning, and what the one-liner actually does line by line all live on one page:

Install cosmon

The short version, on macOS or Linux:

curl -fsSL https://noogram.org/cosmon/install.sh | sh

Then confirm:

cs --version
cs --help

You should see the command groups (lifecycle, fleet, execution, …). The full command surface is documented in the CLI overview.

Step 4: Initialise a project

Pick any repository you want cosmon to track (a Rust crate, a research repo, a plain folder of notes) and, from its root, run:

cd ~/path/to/your/project
cs init

cs init creates a .cosmon/ directory. That directory is where cosmon keeps all of its state: the molecules you will create, their event logs, and the canonical formulas (including task-work). It walks up from wherever you run cs, the way git finds .git/, so once .cosmon/ exists every later command finds it automatically.

cs init is safe to run twice: if .cosmon/ already exists it does nothing.

Confirm the formulas landed:

ls .cosmon/formulas/

You should see task-work.formula.toml among others. That is the one formula the next tutorial uses.

Step 5: Confirm the project is live

cs status

cs status is cosmon's git status: a quick read of the project's tracked work. On a freshly initialised project it reports an empty ensemble: no molecules yet. That empty report is success: cosmon is installed, the project is registered, and there is nothing running.

You are ready

You now have the four tools and an initialised project. Nothing is running, and that is the correct resting state; an initialised project holds files, not processes.

Go to Your first molecule to create and run one unit of tracked work end to end.

You do not have to type cs by hand. If you already work inside an agentic coding CLI (Claude Code, Codex, gemini-cli, opencode, aider, …), one line in its context file lets you drive the same cycle in plain English — "nucleate a task to … , then tackle it and wait". See Pilot cosmon in natural language. Learn the commands here first: it is what lets you tell whether the agent is doing the right thing.

Your first molecule

In this tutorial you will create one piece of tracked work, hand it to an AI worker, wait for it to finish, and close the loop: the full nucleate → tackle → wait → done cycle that every piece of work in cosmon goes through. By the end you will have watched a molecule go from nothing to a merged result.

Before you start: finish Set up cosmon. You need cs, tmux, an agent adapter, git, and a project where you have run cs init.

The commands below use physics-inspired names. Each one is glossed the first time it appears; the full story is in The physics vocabulary.

The four verbs, in one picture

Cosmon runs every piece of work through the same four-step loop:

cs nucleate   →   cs tackle   →   cs wait   →   cs done
  create          start a         block until    merge the
  the work        worker on it    it finishes    result, clean up

You will run each verb once.

Step 1: Nucleate a molecule

From your project root:

cs nucleate task-work --var topic="Add a --version flag to the CLI"

Two new words here:

  • A molecule is cosmon's unit of tracked work: one running instance of a recipe, bound to a task. It has a state, a current step, and a durable trace on disk. Think of it as a single job with a memory.
  • A formula is that recipe: task-work is a formula, a small TOML template of ordered steps ("implement", then "verify"). The molecule is one run of that formula, the way an object is one instance of a class.

Nucleate means create the molecule from the formula: pure creation, nothing executes yet. The command prints the new molecule's id:

Nucleated task-20260711-a1b2 (task-work): pending

Copy that id; you will use it in the next three steps. (Your id will differ; substitute it everywhere you see task-20260711-a1b2 below.)

Confirm it exists and is pending:

cs observe task-20260711-a1b2

cs observe is a one-shot read of a single molecule's state. It reports pending: the molecule exists on disk but no one is working on it yet.

Step 2: Tackle it

cs tackle task-20260711-a1b2

Tackle is the verb that puts a molecule into motion. In one command cosmon:

  1. creates a git worktree and a branch for this molecule,
  2. opens a tmux session, and
  3. launches your agent adapter inside it, with the molecule's briefing injected.

The agent is now a worker: a live process, in its own pane, driving this one molecule. It reads the formula's steps and executes them, recording its progress as it goes.

cs tackle returns immediately; it does not wait for the work to finish. The worker runs in the background tmux session while your shell stays free.

Step 3: Wait for it

You do not poll by hand. Ask cosmon to notify you:

cs wait task-20260711-a1b2

cs wait blocks until the molecule reaches a terminal state (completed or collapsed), then returns. While it blocks, the worker is stepping through the formula: implementing, then verifying, committing its work to the molecule's branch at each step.

When cs wait returns, the molecule has finished its steps and marked itself completed, but its work is still on its own branch, not yet in your main.

Tip. In real use you background the wait (cs wait <id> &) so you can do other things while the worker runs, and get notified on completion. For this first run, a foreground wait is fine; it just sits there until the worker is done.

If you want to watch it work while you wait, open a second terminal and run cs peek, the fleet portal shown in the next tutorial.

Step 4: Done

cs done task-20260711-a1b2

Done closes the loop. It merges the worker's branch back into main, kills the tmux session, and removes the worktree. After it returns, the work is in your main branch and nothing is left running.

cs done is the only verb that merges and tears down; a worker can finish its own steps, but it cannot merge itself. That is a human's call, which is why you run cs done, not the worker.

Confirm the loop is closed:

cs status

The molecule now shows as completed, and the ensemble has no running workers.

What just happened

You ran one molecule through its whole life:

VerbWhat it didState after
cs nucleateCreated the molecule from the task-work formulapending
cs tackleSpawned a worker to drive itrunning
cs waitBlocked until the worker finished its stepscompleted
cs doneMerged the branch and cleaned upcompleted + merged

The molecule's full trace (every step, every commit) is on disk in .cosmon/state/, and survives long after the worker's tmux pane is gone. That on-disk trace is the whole point: see Crash recovery for why a worker dying never loses your work.

Next

Running a fleet of agents

The whole reason cosmon exists is to run many agents at once without losing track of who is doing what. In this tutorial you will start three independent workers in parallel and watch them from a single live portal, cs peek. By the end you will have three molecules running side by side and know how to read the fleet at a glance.

Before you start: finish Your first molecule. You should be comfortable with nucleate → tackle → wait → done for one molecule.

The ensemble is the whole fleet: every molecule and worker seen at once. That is the word cosmon uses for "all your running work together."

Step 1: Nucleate three independent molecules

These three tasks have nothing to do with each other, so they can all run at the same time. Nucleate one after another:

cs nucleate task-work --var topic="Write the README quickstart"     # → mol A
cs nucleate task-work --var topic="Add unit tests for the parser"   # → mol B
cs nucleate task-work --var topic="Fix the changelog formatting"    # → mol C

Each prints its own id. Note all three (referred to below as A, B, C). Confirm they are all pending:

cs status

You should see three pending molecules and no workers.

Step 2: Tackle all three in parallel

Because the molecules are independent, you can put them all into motion at once. Tackle each; the command returns immediately, so three quick calls launch three workers:

cs tackle <A>
cs tackle <B>
cs tackle <C>

Each cs tackle gets its own worktree, its own tmux session, and its own git branch, so the three workers never collide: they edit separate checkouts of the repo and only meet again at merge time.

Step 3: Watch the fleet with cs peek

Now the payoff. Instead of attaching to three terminals, open one portal:

cs peek

cs peek is cosmon's fleet observation command: a TUI (terminal UI) that shows every worker in the ensemble on the left and a detail view on the right. It is the one tool you reach for to watch a fleet; it is a plain window, not an action on your molecules, so it can never disturb them.

Keys inside cs peek:

KeyWhat it does
j / kMove the selection down / up the worker list
pShow the selected worker's live tmux pane: what the agent is doing right now
bBriefing: the plan the worker is following
lLog: the worker's step-by-step history
eEvents: the raw event stream
qQuit the portal

Press j/k to move between your three workers and p to drop into each one's live output. This is the "fractal descent" cosmon is built around: one portal, one keystroke down to any single worker, back up with one keystroke.

Do not tmux attach to a worker's session to check on it. That breaks the agent's rendering and confuses it. cs peek + p shows you the same pane read-only, which is always what you want.

Step 4: Read the ensemble as a table

cs peek is the live portal; for a one-shot snapshot (handy in scripts) use cs ensemble:

cs ensemble
NAME          ROLE            EFFECTIVE   LIVE            COST    MOLECULE
worker-A      Implementation  healthy     working:step 1  $0.42   <A>
worker-B      Implementation  healthy     working:step 2  $0.31   <B>
worker-C      Implementation  suspect     stale           $0.20   <C>

The EFFECTIVE / LIVE columns tell you the health of each worker at a glance: healthy and working is good; suspect / stale means a worker has stopped making progress (you will handle that case in Recover a crashed agent). Add --json for machine-readable output.

Step 5: Wait, then close each loop

Background a wait on each molecule so you are notified as they finish:

cs wait <A> &
cs wait <B> &
cs wait <C> &

The & sends each wait to the background, so your shell stays responsive and all three notify you independently. As each molecule completes, close its loop with cs done:

cs done <A>
cs done <B>
cs done <C>

Because the three workers touched different files, all three branches merge cleanly into main. (When parallel workers do touch the same file, cs done detects the conflict, aborts the merge cleanly, and prints exact recovery commands; you will see that in Composing a DAG.)

What just happened

You ran a real fleet: three agents, three branches, one portal. The pattern scales: ten workers read the same way as three, because cs peek and cs ensemble always show the whole ensemble, never one session at a time.

Next

Composing a DAG

So far your molecules have been independent. Real work has order: clean the data before you build features, build the API and the UI before you integration- test them. In this tutorial you will wire molecules into a DAG, a directed acyclic graph of dependencies, and let cosmon run them in the right order, automatically. By the end you will have run a small pipeline end to end with a single command.

Before you start: finish Running a fleet of agents.

A DAG is just "work with arrows": each molecule points at the ones that must finish before it can start. "Acyclic" means no arrow ever loops back, so the graph always has a beginning. The running graph of linked molecules is called a polymer (or a mission): where one molecule is a single unit, a polymer is the whole wired chain.

Step 1: Wire a linear chain

Molecules become a DAG when you connect them with --blocked-by. The rule reads like English: if B is blocked by A, then A must finish before B can start.

Nucleate three tasks and chain them A → B → C:

cs nucleate task-work --var topic="Fetch raw data"                 # → A
cs nucleate task-work --var topic="Clean and validate" \
    --blocked-by <A>                                                # → B
cs nucleate task-work --var topic="Build features" \
    --blocked-by <B>                                                # → C

Each --blocked-by records the edge on both molecules at once: the new one learns it is blocked, the referenced one learns it blocks. You never maintain two sides by hand. --blocks is the mirror flag if you prefer to wire from the other direction; both are repeatable, so --blocked-by <A> --blocked-by <B> fans two dependencies into one molecule.

Cosmon validates the graph as you build it: a reference to a molecule that does not exist aborts the nucleation, and so does any edge that would create a cycle.

Step 2: Inspect the graph

Before running anything, look at what you wired:

cs deps <B>
⏳ Blocked by:
  <A>   [pending]

⛔ Blocks:
  <C>   [pending]

cs deps shows one molecule's direct neighbours. To see the whole connected chain at once, walk it transitively:

cs deps <C> --transitive

Add --json to either for structured output you can pipe into other tools.

Step 3: Run the whole DAG with cs run

You could tackle each molecule by hand in order, but that is exactly the bookkeeping cosmon exists to remove. Hand the whole graph to the runtime with one command, pointing it at the root:

cs run <A>

cs run is the resident runtime: it walks the DAG for you. Step by step it:

  1. discovers the full graph by following the edges out from <A>,
  2. finds the ready frontier: every molecule whose upstream is already done (at the start, just <A>),
  3. advances the ready molecules,
  4. when one finishes, unlocks whatever it was blocking, recomputing the frontier,
  5. repeats until nothing is left, then exits.

So <A> runs first; only when it completes does <B> become ready; then <C>. You wired the order once, declaratively, and the runtime enforces it.

cs run blocks your terminal until the whole graph drains. For anything long-running, launch it in a detached tmux session so your shell stays free:

tmux new -d -s runtime cs run <A> --poll-interval 5

Useful options:

cs run <A> \
    --timeout 300 \       # give up after 300s (exit code 124); 0 = no limit
    --poll-interval 1     # seconds between scheduler ticks

Step 4: When branches diverge, cs done protects you

cs run calls cs done for each molecule as it completes, merging its branch before dispatching whatever depended on it, so each worker sees its predecessor's committed output in its own worktree. This is why order matters for content, not just timing: B's worker can read A's finished files because A was merged first.

If two molecules that touch the same file ever merge in a way that conflicts, cs done does not leave you with a broken tree. It aborts the merge cleanly and prints exact recovery steps, for example:

Conflict detected in 1 file(s):
  src/config.rs

To resolve:
  cd .worktrees/<mol-id> && git merge main
  # fix conflicts
  git add . && git commit
  cd - && cs done <mol-id>

Diamonds and parallelism

A chain is the simplest DAG. The same flags build a diamond, where two molecules run in parallel and a third fans them back in:

cs nucleate task-work --var topic="Setup infrastructure"      # → infra
cs nucleate task-work --var topic="Build API"  --blocked-by <infra>   # → api
cs nucleate task-work --var topic="Build UI"   --blocked-by <infra>   # → ui
cs nucleate task-work --var topic="Integration tests" \
    --blocked-by <api> --blocked-by <ui>                              # → tests

Under cs run, api and ui become ready together the moment infra completes, run in parallel, and tests waits for both. You describe the shape; the runtime finds the parallelism.

What just happened

You moved from "three independent jobs" to "a pipeline with a shape." The shape lives in the edges (--blocked-by) and cs run turns that shape into the correct execution order, including running independent branches at once. Nothing about a single molecule changed; you only added arrows between them.

Next

Verify the binary's provenance

One line. Every cosmon release binary is reproducibly built, signed with a short-lived Sigstore certificate bound to the release workflow, and recorded in the public Rekor transparency log. You can check all three from your own machine, without having to trust "a download from the internet."

Why this page exists

Installing cs checks that the tarball you carried home weighs what the stall said it would weigh — the sha256 from the release's SHA256SUMS, served over TLS. That is real, and it is fail-closed: a mismatch aborts the install. But it only proves the basket matches the stall's label. It does not prove who filled the basket.

Cosign and Rekor are the greengrocer's signed, dated, publicly-posted receipt: "I, the release workflow, packed this exact basket on this exact day, and here is the entry in the town ledger anyone can read." You check the receipt once; after that you trust the binary, not the download.

Be clear about the trust boundary. The curl … | sh installer does the sha256 leg only. It does not verify signatures, and it does not need cosign installed. The cryptographic provenance proof below is opt-in: it is a separate step, it needs cosign (and, for Layer 3, rekor-cli) on your machine, and you run it when you want the stronger claim.

What a release carries

For each platform target (aarch64-apple-darwin, x86_64-apple-darwin, x86_64-unknown-linux-musl, aarch64-unknown-linux-musl) the GitHub Release carries:

FileWhat it is
cosmon-<v>-<target>.tar.gzthe cs binary, tarred (what the installer downloads)
cosmon-<v>-<target>.tar.gz.sigcosign signature over the tarball
cosmon-<v>-<target>.tar.gz.pemthe short-lived signing certificate
cosmon-<v>-<target>the raw cs binary (so you can verify what's on your PATH)
cosmon-<v>-<target>.sig / .pemcosign signature + cert over the raw binary
cosmon-<v>-<target>.spdx.jsonSPDX SBOM (dependency closure)
cosmon-service-<v>-<target>.tar.gzthe cosmon-rpp-adapter + cs-oidc-mock service binaries (see Run cosmon as a remote service)
cosmon-service-<v>-<target>.tar.gz.sig / .pemcosign signature + cert over the service tarball
SHA256SUMSone digest per shipped artifact

Verify — 3 layers, weakest to strongest

Layer 1 — the sha256 check (you already have it)

The installer fails closed if the downloaded tarball's sha256 does not match the digest in the release's SHA256SUMS. You get this for free on every install. It proves byte-integrity of the download against the release's own manifest — not provenance. Layers 2 and 3 are what close that gap.

Layer 2 — cosign signature (provenance)

Prove the binary on your PATH was signed by the cosmon release workflow:

v=0.1.0
target=aarch64-apple-darwin          # match your platform
base="https://github.com/noogram/cosmon/releases/download/v${v}"

curl -sSLO "${base}/cosmon-${v}-${target}"        # raw binary we signed
curl -sSLO "${base}/cosmon-${v}-${target}.sig"
curl -sSLO "${base}/cosmon-${v}-${target}.pem"

cosign verify-blob \
  --certificate-identity-regexp 'https://github.com/noogram/cosmon/.github/workflows/release.yml@.*' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --signature  "cosmon-${v}-${target}.sig" \
  --certificate "cosmon-${v}-${target}.pem" \
  "cosmon-${v}-${target}"
# Verified OK

--certificate-identity-regexp is the load-bearing pin: it asserts the certificate's subject is the cosmon release.yml workflow, not some other repo's workflow that happened to sign a blob. --certificate-oidc-issuer pins the token issuer to GitHub Actions. Swap the org if you forked.

To verify the binary already sitting on your PATH (instead of the raw download), point the last argument at it — it is byte-identical to the signed binary inside the tarball:

cosign verify-blob \
  --certificate-identity-regexp 'https://github.com/noogram/cosmon/.github/workflows/release.yml@.*' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --signature  "cosmon-${v}-${target}.sig" \
  --certificate "cosmon-${v}-${target}.pem" \
  "$(which cs)"

Layer 3 — Rekor transparency log (public, after-the-fact audit)

Keyless cosign uploads every signature to the public Rekor log by default, so the signing event is permanently auditable even if you weren't watching when it happened. Find the entry:

rekor-cli search --artifact "cosmon-${v}-${target}"
# or by the certificate:
rekor-cli search --pki-format=x509 --public-key "cosmon-${v}-${target}.pem"

cosign verify-blob already checks the Rekor inclusion proof during Layer 2; Layer 3 is for an independent auditor who wants to read the log directly.

Reproduce the build yourself (optional, strongest)

Because the build is reproducible (--locked + pinned SOURCE_DATE_EPOCH + path remapping), you can rebuild the exact bytes and compare:

git clone https://github.com/noogram/cosmon && cd cosmon
git checkout v${v}
export SOURCE_DATE_EPOCH="$(git log -1 --pretty=%ct)"
export RUSTFLAGS="-C strip=symbols --remap-path-prefix=${PWD}=/cosmon --remap-path-prefix=${HOME}=/home"
cargo build --release --locked --bin cs --target ${target}
sha256sum target/${target}/release/cs
# compare against cosmon-${v}-${target}.bin.sha256 from the release

Identical digests prove the published binary is exactly what this source tree compiles to — no hidden step between git tag and the bytes you run.

If verification fails

A red cosign verify-blob or a sha256 mismatch is a security signal, not a nuisance. Do not bypass it, do not --insecure, do not skip the digest. Stop, and report it as an issue on the repository. A genuine release never fails these checks; a failure means either a corrupted download or a tampered artifact.

See also

Recover a crashed agent

Goal: a worker died (the laptop rebooted, a tmux server was killed, a model call timed out) and a molecule is now stranded. This guide gets it moving again (or retires it) without losing any work.

The key fact that makes recovery cheap: cosmon keeps its truth on disk in .cosmon/state/, not in the worker's memory. A crash preserves every molecule; it only strands the live worker that was driving it. Recovery is noticing the strand and re-attaching a fresh worker. See Crash recovery for the mechanism.

There is no single recover verb. Recovery is a short sequence of one-decision commands: scan, then decide one molecule at a time.

When you need this

  • After a host reboot or an editor/IDE crash.
  • After a SIGKILL or OOM of a tmux server.
  • When cs ensemble shows molecules that say running but you cannot reach.
  • As the first move in any "something is wrong, I don't know what" triage.

Step 1: Scan for strands

cs patrol

cs patrol runs the fleet's health checks and surfaces molecules whose lifecycle says running but whose worker process is gone. For a read-only look that mutates nothing, use the anomaly catalog instead:

cs health

Both tell you the same thing: which molecules are stranded. cs patrol never silently re-tackles anything; it detects and reports; you pick the fix.

Step 2: Decide, one molecule at a time

For each stranded molecule, choose exactly one verb:

SituationVerbWhat it does
The worker is alive but sitting idle mid-stepcs resume <id>Re-propels the existing worker (a nudge to continue).
The worker is genuinely dead, but the work is worth continuingcs resurrect <id>Revives the molecule with a fresh worker: the re-tackle after a crash.
You want to park it and record whycs stuck <id> --reason "..."Freezes the molecule and notes the blocker.
It is not worth recoveringcs collapse <id> --reason "..."Terminates it permanently, with a reason on the record.

Example: a worker died on a molecule you still want:

cs resurrect task-20260711-a1b2

A fresh worker starts in a new tmux session, reads the molecule's on-disk trace, and picks up from where the state file says it was.

Step 3: Confirm it is moving

cs peek

Select the recovered molecule (j/k) and press p to see its new worker's live pane. Or, for a one-shot check:

cs observe task-20260711-a1b2

If a frozen molecule's blocker later clears, bring it back with:

cs thaw task-20260711-a1b2

Scope

Recovery is project-local: these verbs act on molecules in the current project's .cosmon/state/, discovered by walking up from your working directory. For another project, run the same verbs from that project's directory. Pending, Completed, and Collapsed molecules are never "stranded"; only running molecules with a dead worker are.

See also

Curate the backlog with temperature tags

Goal: keep a growing backlog of pending molecules honest, so it never turns into sediment that a later cs run or patrol accidentally resurrects. Cosmon's tool for this is a small set of temperature tags you attach to pending work.

A pending molecule that just sits there untagged is the problem. The tag says, in one word, how hot the work is: whether to grab it now, park it, or let it cool. The cost of stale pendings is not disk space; it is scope pollution: a greedy runtime can pick them up.

The four temperatures

TagMeaning
temp:hot 🔥Actionable now: tackle soon; often unblocks other work.
temp:warm 🌡️Valid, not urgent: fine to park on the shelf.
temp:cold ❄️Interesting but deprioritised: revisit in a later cycle.
temp:frozen 🧊Blocked on an external decision or a missing prerequisite.

Tag a molecule

cs tag task-20260711-a1b2 --add temp:warm

Remove or change a tag the same way:

cs tag task-20260711-a1b2 --remove temp:warm --add temp:hot

See only the actionable queue

cs ensemble --tag temp:hot

Add --json to feed the actionable set into a script.

The rules that keep it clean

  • Every pending molecule older than ~48h should carry a temp:* tag. If it has none, either tag it or cs collapse it with a reason. An untagged, aging pending is a bug in your backlog, not a neutral state.
  • Drop the tag when you tackle it. A hot molecule you have started is no longer on the shelf; it is in motion. If it bounces back to pending (a revision), re-tag it.
  • Promote when a blocker clears. When a temp:frozen molecule's prerequisite lands, re-tag it temp:hot or temp:warm and consider tackling it.
  • Decomposition auto-tags its children. Any workflow that nucleates child molecules should immediately tag each child temp:warm, so no child is ever born invisible. The periodic sweep is a safety net, not the primary mechanism.

Periodic hygiene

Every week or so (or after a big session) let the system curate itself. The temp-review formula scans every pending by age and tag, triages the stale ones, and writes a report:

cs nucleate temp-review
cs tackle <id>
cs wait <id>
cs done <id>

The worker sweeps the backlog and produces a triage report: what it collapsed, what it tagged, the top priorities, and trends. Because curation is itself just a molecule, the backlog stays honest with the same nucleate → tackle → wait → done loop you use for everything else.

See also

Bootstrap a new project with cs init

Goal: make cosmon track the work in an existing repository (a Rust crate, a research repo, a folder of notes) without vendoring cosmon's source or turning your project into a cosmon subdirectory. One command does it.

Cosmon is a substrate: your project embeds it. Nothing of cosmon's source enters your dependency graph. Your project holds only a .cosmon/ directory; a single globally-installed cs reaches into it.

Step 1: Initialise

From the root of the project you want tracked:

cd ~/path/to/your/project
cs init

This creates .cosmon/, containing:

  • state/: the on-disk source of truth for every molecule you create,
  • formulas/: the canonical formula recipes (task-work, temp-review, …),
  • a project id and default configuration.

cs init is strictly idempotent: run it twice and the second run is a no-op, so it is safe in scripts and CI.

Step 2: Verify

cs status
ls .cosmon/formulas/

cs status reports an empty ensemble (no molecules yet); the ls shows the formulas that shipped with init. That is a healthy fresh project.

How cosmon finds your project

Once .cosmon/ exists, every cs invocation walks up from your current directory to find it, exactly the way git finds .git/. So you can run cs from any subdirectory and it resolves to the same project state. If you are inside a git worktree, cosmon detects it and redirects to the main repo's .cosmon/, so commands behave identically from a worktree and from the main checkout.

Choosing a mode

Cosmon supports two embedding modes; pick one:

You need…Use…
The full lifecycle: cs tackle to spawn workers, cs run for DAGsThe globally-installed cs + a project .cosmon/ (what cs init sets up).
Only to create/read/evolve molecules in-process from Rust, no spawningThe cosmon-embed crate (Inert-only facade).

Most projects want the first. The second is for test harnesses, CI jobs, or third-party schedulers that run the actual work themselves and use cosmon purely as a state store. A per-project cosmon daemon is neither: it is prohibited by cosmon's architecture; the cs binary is stateless by design.

A lighter footprint: --soft

If you want to propagate cosmon's conventions into a project without any orchestration state at all, generate just a minimal CLAUDE.md:

cs init --soft                    # generic conventions
cs init --soft --template rust    # cargo-based conventions

--soft writes a single small file any agent can read, and creates no .cosmon/: no runtime, no state. Use it when you want an agent to follow the house style but do not need cosmon to track molecules there yet.

Upgrading an existing project

When a new cosmon release adds canonical formulas, backfill them without touching your existing files:

cs init --upgrade

This adds any missing canonical formulas and a project_id if absent, and overwrites nothing you already have.

Next

  • Create your first tracked molecule: Your first molecule.
  • Bootstrap a whole galaxy of related projects: see the galaxy-onboarding workflow (referenced from the project reference).
  • Full command surface: Project commands reference.

Germinate a polymer from a spore

Goal: you have a mission shape (a whole DAG of molecules) that you want to reuse or share, not re-wire by hand every time. A spore packages that shape as one parameterizable template; germinating it stamps out the whole running graph in one command.

Two words up front. A spore is a shareable template of an entire wired DAG: recipes (formulas) plus fleet config and an optional proof, the way a formula is the template of a single molecule. A polymer is the running graph a spore germinates into: a mission of linked molecules. Where a formula nucleates one molecule, a spore germinates the whole set. It is the same generative relation, one scale up.

cs spore is a declarative front end over cs nucleate, not a new scheduler and not a new molecule type. It replays the same nucleate-and-wire calls you would otherwise type by hand.

What a spore declares

A spore is one spore.toml. It bundles:

  • [spore]: name, version, description.
  • [spore.params.*]: the parameters callers fill in (typed: string, int, bool, enum, list<string>), each with a required flag and optional default.
  • [spore.formulas.*]: named recipe aliases pointing at *.formula.toml files. A formula is the recipe a single molecule follows.
  • [[spore.node]]: each node: a kind (fixed / fanout / emergent), a formula alias, and per-node variables.
  • [[spore.edge]]: the typed blocked-by edges wiring the DAG. The edge set must be acyclic.
  • [spore.seal] (optional): a .tla module that proves a property of the plan.

The parser is fail-closed: it rejects an emergent node with no bounds, an edge cycle, an unknown node kind, a parameter-type mismatch, and duplicate or dangling node references.

Step 0: Install someone else's spore

If the spore is yours, it is already on disk and you can skip to step 1. If someone shared one — a repository, a GitHub URL, a directory — install it:

cs spore install github:noogram/cosmon/spores/cosmon-dev
cs spore install https://github.com/noogram/cosmon/tree/main/spores/cosmon-dev
cs spore install ../shared/bundle --dest spores/shared

This does two things, and the second is the one that is easy to forget by hand: it copies the bundle into <project>/spores/<name>/, and it registers each of the bundle's recipes in .cosmon/formulas/. A germinated molecule stores its formula by id, and cs tackle looks that id up in your project's registry — so a bundle whose recipes were never installed germinates fine and then runs every node on the adapter default, with the per-step adapter/model pins the author wrote silently inert.

Install refuses before writing anything: on a --expect-hash mismatch (the id cs spore export prints), a bundle missing a file its manifest declares, a symlink in the fetched tree, a non-empty destination, or a registry recipe of the same name with different content. Re-installing an unchanged bundle is a no-op. Add --dry-run to see the plan first.

Step 1: Validate before you germinate (dry run)

Always check what a spore would create before it creates anything:

cs spore validate ./spore.toml --var subject="octopus cognition"

cs spore validate parses and expands the spore as a dry run: it prints the ordered list of cs nucleate … --blocked-by … calls it would make, and germinates nothing. Pass --json for one NDJSON object per expanded call. Fill parameters with --var key=value (repeatable); a list<string> splits on commas (--var axes=a,b,c).

spore: demo (v1) - 3 call(s)
seal: none
  • frame [fixed]      formula: work.formula.toml
  • analyse-0 [fanout] formula: work.formula.toml  blocked-by: frame
  • analyse-1 [fanout] formula: work.formula.toml  blocked-by: frame

Step 2: Germinate it

When the dry run looks right, germinate the polymer into the live state store:

cs spore run ./spore.toml --var subject="octopus cognition"

This nucleates every node and wires every edge, in dependency order so each blocked-by reference already exists when its dependent is created. Each germinated molecule is tagged temp:warm automatically (backlog-curation discipline; see Curate the backlog with temperature tags).

seal: none
Germinated spore demo into 3 molecule(s):
  task-20260629-...  (work)
  task-20260629-...  (work)
  task-20260629-...  (work)

You now have a live polymer. Run it exactly like the DAG you wired by hand in Composing a DAG: point cs run at the root, or tackle nodes as they become ready.

You can pass a directory instead of a file (cs spore run ./bundle/), and --json prints one NDJSON line per germinated molecule.

The seal gate, stated honestly

cs spore run never claims a proof is verified when it is not:

  • A spore with no seal germinates freely (seal: none).
  • A sealed spore on a machine without the TLC verifier wired in fails closed by default and refuses to germinate.
  • --allow-unchecked-seal opts into the risk; the status then reads seal: present, NOT verified, never verified.

Step 3: Share a spore

Emit a content-addressed bundle for sharing:

cs spore export ./spore.toml            # prints a blake3: bundle id
cs spore export ./spore.toml --out dist/

The id is a stable hash over the manifest and every recipe and seal file it references, in sorted order: the same content always yields the same id, so the bundle is its own registry entry.

See also

Monitor the fleet with cs peek

Goal: watch what your agents are doing (across one project or many) without attaching to terminals or tailing raw log files. Cosmon's observability is a fractal portal, not a dashboard: one tool, recursive, from a fleet overview down to a single worker's live pane.

Reach for these tools before tmux, tail, or cat. If cs peek cannot show you something, that is a gap to report, not a reason to go back to shell archaeology.

The one tool: cs peek

cs peek

cs peek is the canonical fleet observation command: a TUI portal. The left pane lists every worker; the right pane follows your selection. One keystroke descends one level:

KeyWhat it shows
j / kMove the selection down / up the worker list
pThe selected worker's live tmux pane: what the agent is doing right now
bBriefing: the plan the worker is following
lLog: its step-by-step history
eEvents: the raw event stream
sSynthesis (for molecules that produce one)
rResponses
qQuit
?Help overlay — keybindings. Press Tab there for the glyph legend

The table is dense with symbols: a lifecycle pastille ( 💤 · 🧊 👻), a whisper bubble, a temperature, a trust bar, an energy bar. You are not expected to memorise them — press ? then Tab and the legend sits beside the table it explains, saying what each glyph means and what to do about it. The same legend is mirrored in man cs and in the handbook for reading away from the terminal.

Press p to drop into any worker's output, q to come back up. That descend- and-return is the whole model: you keep the fleet view while you inspect one worker.

Across many projects at once

cs peek --all

--all aggregates every tmux session and every .cosmon/ on disk, so you get the multi-project view from any directory.

One-shot snapshots (for scripts and quick checks)

cs peek is the live portal. When you want a single printed snapshot instead (in a script, a CI log, a quick glance) use these:

cs ensemble          # table of every worker: role, health, cost, molecule
cs status            # a quick DAG overview, like `git status`
cs pulse             # runtime-vitality reading: a tachometer + status lights

cs ensemble --json (and --json on the others) gives machine-readable output. The EFFECTIVE / LIVE columns in cs ensemble are your health signal: healthy + working is good; suspect / stale means a worker has stopped progressing; take it to Recover a crashed agent.

When something breaks

cs errors            # aggregate molecule-collapse events into one failure view
cs health            # read-only anomaly catalog across the fleet

cs errors answers "what is breaking the fleet, and which molecules are hit," with a --since 7d window and a --kind filter for a specific failure class. cs health mutates nothing; it is the safe first look during triage. Add --all to cs health to scan every project federation-wide.

The live event stream

To follow events as they land, the raw NDJSON history a molecule writes:

cs tail --follow

cs tail is a notify-driven reader over the fleet's events.jsonl. --follow stays attached and streams new events; --all-galaxies widens it across every project (opt-in; cross-project reach is never implicit).

Anti-patterns: do not do these

Instead of…Use…Why
tmux attach to a worker's sessioncs peek + pAttaching breaks the agent's rendering and confuses it.
watch cs observe … in a shell loopcs wait <id> &Hand-polling burns CPU and misses transitions between polls.
tail -f on events.jsonlcs tailSame stream, structured and fleet-aware.
cat a briefing from a random terminalcs peek (b)Loses fleet context.

See also

Pilot cosmon in natural language

Goal: drive cosmon by saying what you want — "nucleate a task to fix the flaky parser test, then tackle it and wait" — instead of typing cs commands by hand. You do this by pointing an agentic coding CLI at cosmon's own help surface, once, in a single line of config.

This is not a new cosmon feature or a plugin. cs is a plain command-line tool with a self-describing help surface. Any agent that can read cs help and run a shell command can already pilot cosmon. The only thing missing is a pointer telling it that cosmon is there.

The idea in one picture

An agentic CLI (Claude Code, Codex, gemini-cli, opencode, aider, …) reads a context file in your repository when it starts. If that file says "to operate cosmon, run cs help", the agent discovers the whole command surface on its own, and your English turns into the right cs invocations.

you (English)  →  agentic CLI  →  reads `cs help`  →  runs `cs nucleate …`

Three steps: install cs, add the pointer, speak.

Step 1: Install cs

curl -fsSL https://noogram.org/cosmon/install.sh | sh

This installs a single binary into ~/.local/bin (falling back to /usr/local/bin), verifying its checksum against the release SHA256SUMS. If that directory is not on your PATH, the installer says so and prints the line to add. Confirm:

cs --version
cs help          # the surface the agent will read

cs help is the load-bearing part. It prints every command grouped by theme (molecule lifecycle, fleet management, execution, …) with a one-line description each, and every subcommand takes --help. That is enough for an agent to work out the vocabulary without any further documentation.

man cs is a contributor extra, not part of this path. The published installer ships the cs binary and nothing else, so do not expect a man page on a fresh machine. Contributors who build from the repository get one via just install. Point your agent at cs help, which is always present.

Step 2: Add the pointer to your agent's context file

Each CLI reads its own file at startup — commonly AGENTS.md or CLAUDE.md at the repository root; check your tool's documentation for the exact name. Add a short section like this:

## Orchestration

This project is orchestrated with cosmon. The `cs` binary is on `PATH`.

To operate it, discover the command surface first: run `cs help` for the
grouped command list, and `cs <command> --help` for any single command.
Do not guess flags — read the help output.

The normal cycle for one unit of work is:
nucleate → tackle → wait → done.

That is the whole transport. It carries no secrets and pins no versions: it names the tool, states that it is on PATH, and tells the agent to read the help rather than invent flags. Because the pointer defers to cs help instead of restating commands, it cannot drift out of date when cosmon's surface changes.

Keep it minimal on purpose. A long transcription of cosmon's commands into your context file is a second copy of the reference that will rot; the two lines above delegate to the copy that ships with the binary.

Step 3: Speak

With the pointer in place, you talk to your coding CLI normally:

"Nucleate a task to fix the flaky parser test, then tackle it and wait for it."

and it resolves that into the cycle:

cs nucleate task-work --kind task --var topic="fix the flaky parser test"
cs tackle task-20260716-1a2b
cs wait   task-20260716-1a2b
cs done   task-20260716-1a2b

You stay in the loop: the agent proposes the commands, you watch the molecule run. Other phrasings map the same way — "what's running right now?" becomes cs status or cs ensemble, "show me what that worker is doing" becomes cs peek.

If the agent guesses a flag that does not exist, that is the signal your pointer is being skipped — make sure the context file is at the repository root and that your CLI actually loads it.

Which CLIs work

Any coding agent that can read a context file and run shell commands. That includes Claude Code, Codex, gemini-cli, opencode, and aider, among others. Cosmon does not integrate with them individually and does not detect which one you are using — it exposes cs help and they read it. Support is therefore a property of the CLI (does it read a context file? can it run a shell command?), not something cosmon maintains per tool.

This is a different axis from --adapter. Here an agentic CLI drives cosmon from the outside, translating your English into cs commands. The adapter is the reverse: cosmon spawning a model underneath to do the work of a molecule. You can use either alone, or both.

Wire cosmon into an external scheduler

Goal: drive cosmon from your scheduler (cron, a systemd timer, a CI job, a platform runtime) instead of leaving a cs run in the foreground. Cosmon is a stateless CLI, so it composes with any scheduler the same way git does: you call one-shot commands on a clock you own.

Cosmon has two layers. The Transactional Core (cs tackle, cs done, cs reconcile, …) is stateless and git-like: one decision per invocation, files on disk are the truth. The Resident Runtime (cs run) is a long-lived client of that core; it owns no private truth and holds no lock. An external scheduler drives the core directly and never needs the runtime. See Why a stateless CLI.

Why this works: no daemon, no lock

Every cs command reads the on-disk state, changes it, writes it back, and exits. There is no background process holding truth in RAM, so it is always safe for an external scheduler to invoke cs on a timer. Two invocations never race over a lock, because there is no lock: the state file is the single point of coordination, and each command is one transaction against it.

Pattern A: tick a DAG from cron

If you want cosmon to advance a dependency graph but do not want a long-running cs run, drive it one tick at a time. Point your scheduler at a bounded run:

# crontab entry: every 5 minutes, advance the DAG rooted at <root>, then exit.
*/5 * * * *  cd /path/to/project && cs run <root> --timeout 60

--timeout 60 bounds each invocation (exit code 124 on deadline), so the job always returns and the scheduler owns the cadence. Because the runtime is a pure client of the on-disk state, the next tick resumes exactly where the last one left off; nothing is lost between fires.

Pattern B: a hand-rolled tackle/done loop

For full control, script the Transactional Core verbs directly. This walks a linear chain sequentially, one molecule per scheduler tick or all at once:

for mol in <A> <B> <C>; do
    cs tackle "$mol"     # spawn one worker on this node
    cs wait "$mol"       # block until it reaches a terminal state
    cs done "$mol"       # merge its branch, tear down, unblock the next
done

cs tackle puts a molecule into motion; cs wait blocks until it finishes; cs done merges and cleans up. Your scheduler decides when to run the loop; cosmon decides what each step means.

Pattern C: the built-in patrol scheduler

Cosmon ships its own lightweight scheduler for recurring fleet maintenance, configured by a patrols.toml file. Lint it before it ever fires: a zero-side- effect pre-flight that doubles as a CI gate:

cs scheduler validate       # parse & validate patrols.toml, no dispatch
cs scheduler status         # last-known state of every patrol

cs scheduler is a read-only view onto the scheduler's state; adding or editing a patrol is a patrols.toml edit, validated with the command above.

Keeping projected surfaces fresh

Any batch of molecule changes can leave cosmon's projected surfaces (STATUS.md, ISSUES.md, …) stale. Have your scheduler reconcile after a batch:

cs reconcile            # project current state onto all surfaces
cs reconcile --check    # dry-run; exit 1 if surfaces are stale (a CI gate)

cs reconcile is strictly idempotent (running it twice is the same as once) so it is safe to call on every tick. --check makes it a CI guard that fails the build when a surface has drifted.

Reacting to events (notifications)

To push cosmon events to an external system, pipe its NDJSON event stream into a hook script. Cosmon emits one JSON object per event; a hook reads them on stdin and does whatever you need (post to chat, page on error). Filter to the kinds you care about:

cs tail --follow --json | your-hook.sh

Event kinds include worker_spawned, worker_terminated, molecule_transitioned, step_completed, and error_occurred. A hook can forward only a subset (e.g. errors and terminations) and ignore the rest.

What not to do

  • Do not run a per-project cosmon daemon. It is prohibited by cosmon's architecture: the core is stateless on purpose. Your scheduler is the daemon; cs is the one-shot tool it calls.
  • Do not leave cs run in a foreground shell you depend on. If you want it resident, detach it: tmux new -d -s runtime cs run <root>.

See also

Run cosmon as a remote service

Goal: run a cosmon service on a remote GPU box and drive it from your own machine with cosmon-remote. This is useful for an invited-guest host: a machine you operate but may not own, where you have no root access and cannot use Docker.

The client never needs an interactive shell on the service host. It talks to one HTTP entry point (the fente); an SSH tunnel is only an L0 transport that makes that entry point local to the client. Configure ProxyJump in your SSH config if <remote> is behind a bastion.

Remote service topology. On your machine, the cosmon-remote thin client has no interactive shell on the host. It crosses one HTTP entry point, optionally carried by an SSH tunnel at L0, into a remote box you operate. There, cosmon-rpp-adapter is the fente and HTTP service; it delegates to cs tackle, which runs a local model. The remote host therefore runs a server.
Remote mode has one HTTP doorway; lifecycle work and the model stay on the host you operate.

This guide uses a demo identity provider so that the complete auth path is reproducible. Replace it with your production issuer before exposing the service beyond a private tunnel. For how this service surface relates to the runtime, see Control plane vs data plane.

What to deploy

The public noogram/cosmon product closure contains both service components:

CrateRoleLicense
cosmon-rpp-adapterThe HTTP fente and /v1/... service surface.AGPL-3.0-only
cosmon-remoteThin client that drives the service.AGPL-3.0-only

The two host-side binaries — cosmon-rpp-adapter (the fente) and cs-oidc-mock (the demo IdP used in Step 2) — ship as a signed cosmon-service-<version>-<target>.tar.gz release asset per target, alongside the cs CLI tarball. Step 1 therefore has two routes: download the signed release bundle (no Rust toolchain required), or build from source. Prefer the download route unless you need an unreleased revision.

The client, cosmon-remote, is a laptop tool, so it ships with cs: the cosmon-<version>-<target>.tar.gz release tarball carries both, and the one-liner installer (curl -fsSL https://noogram.org/cosmon/install.sh | sh) and the Homebrew formula each place cs and cosmon-remote together. If you installed cs, you already have the connector — there is no separate client fetch. The steps below cover only the host; run the cosmon-remote commands from Step 4 on the machine where you installed cs.

The service delegates work to cs tackle; it is not a second scheduler. On the host, cs resolves the selected worker adapter. For this setup it uses the built-in local adapter: an in-process Ollama /v1 client. No Node.js, Claude runtime, or tmux session is required for that worker leg.

Step 1: Get the binaries and prepare the remote galaxy

You need three binaries on the host: cosmon-rpp-adapter, cs-oidc-mock, and a compatible cs. Get them the signed-release way (no toolchain) or build them from source.

First, make the target directory on the host. This guide calls it $COSMON_HOME.

ssh <remote> "mkdir -p '$COSMON_HOME/bin' '$COSMON_HOME/state/security' '$COSMON_HOME/galaxies'"

Each release ships a cosmon-service-<version>-<target>.tar.gz (the fente + demo IdP) next to the cs CLI tarball. Pick the target matching the host — a static Linux box uses x86_64-unknown-linux-musl or aarch64-unknown-linux-musl. Both tarballs are cosign-signed and Rekor-anchored; verify them as in Verify the binary's provenance.

ver=0.1.0
target=x86_64-unknown-linux-musl
base="https://github.com/noogram/cosmon/releases/download/v${ver}"
curl -fsSLO "${base}/cosmon-service-${ver}-${target}.tar.gz"   # cosmon-rpp-adapter + cs-oidc-mock
curl -fsSLO "${base}/cosmon-${ver}-${target}.tar.gz"           # cs
tar xzf "cosmon-service-${ver}-${target}.tar.gz"
tar xzf "cosmon-${ver}-${target}.tar.gz"
scp cosmon-rpp-adapter cs-oidc-mock cs <remote>:$COSMON_HOME/bin/

Route B — build from source

Build a static musl release on your development machine. cargo-zigbuild uses Zig as the cross-linker, so this works without a Linux container. Install its prerequisites first (Rust's musl target, Zig, and cargo-zigbuild).

cd /path/to/cosmon
cargo zigbuild --release --target x86_64-unknown-linux-musl \
  -p cosmon-rpp-adapter --bin cosmon-rpp-adapter
cargo zigbuild --release --target x86_64-unknown-linux-musl \
  -p cosmon-oidc-testkit --bin cs-oidc-mock

Copy the resulting binaries, plus a compatible cs binary, to $COSMON_HOME/bin.

scp target/x86_64-unknown-linux-musl/release/cosmon-rpp-adapter \
    target/x86_64-unknown-linux-musl/release/cs-oidc-mock \
    /path/to/compatible/cs <remote>:$COSMON_HOME/bin/

Install or configure Ollama on the remote host and make a model that fits its VRAM available. Initialise the demo galaxy and select the local adapter so cs tackle selects Ollama rather than an external coding-agent adapter:

ssh <remote> '
  "$COSMON_HOME/bin/cs" init "$COSMON_HOME/galaxies/demo" --tenant demo
  cat >> "$COSMON_HOME/galaxies/demo/.cosmon/config.toml" <<'"'"'EOF'"'"'

[adapters]
default = "local"

[adapters.local]
default_model = "<your-model>"
EOF
'

Step 2: Start the demo identity provider and pin its keys

cs-oidc-mock is a small demo IdP. Its defaults are issuer https://idp.test.cosmon-oidc-testkit, audience cosmon-rpp-test, a 10-minute token lifetime, and bind address 0.0.0.0:8444. This guide binds it to loopback on port 8444, writes its JWKS, and uses its POST /issue route to mint signed test tokens:

ssh <remote> '
  $COSMON_HOME/bin/cs-oidc-mock \
    --bind 127.0.0.1:8444 \
    --write-jwks-out $COSMON_HOME/state/security/jwks/idp.json
'

In a second remote shell, declare the matching issuer and render the demo identity's binding. The issuer, audience, and subject must agree with the token minted below:

ssh <remote> '
  cat > "$COSMON_HOME/state/security/trusted-issuers.toml" <<'"'"'EOF'"'"'
[[issuer]]
iss = "https://idp.test.cosmon-oidc-testkit"
jwks_uri = "http://127.0.0.1:8444/jwks.json"
audiences = ["cosmon-rpp-test"]
EOF

  mkdir -p "$COSMON_HOME/state/nucleons/demo"
  "$COSMON_HOME/bin/cosmon-rpp-adapter" nucleon render \
    --noyau demo --sub demo-operator \
    --iss https://idp.test.cosmon-oidc-testkit --aud cosmon-rpp-test \
    --scope cosmon:molecule:read --scope cosmon:molecule:write \
    > "$COSMON_HOME/state/nucleons/demo/oidc-identity.toml"
'

The pinned JWKS and this nucleon binding are both required: a valid token alone does not grant access to a tenant.

For a production deployment, replace the mock with your production IdP, pin its JWKS under $COSMON_HOME/state/security, and keep the issuer and binding rules explicit.

Step 3: Start the fente on loopback

Start cosmon-rpp-adapter with its state directory, tenant configuration, and the loopback address that the tunnel will reach. Keep this process supervised by the service manager available to the host.

ssh <remote> '
  $COSMON_HOME/bin/cosmon-rpp-adapter \
    --bind 127.0.0.1:8443 \
    --config $COSMON_HOME/rpp.toml
'

The rpp.toml config declares the state directory, the tenant galaxies root, and the path to the cs binary — for example:

bind_addr = "127.0.0.1:8443"
state_dir = "/opt/cosmon/state"
galaxies_root = "/opt/cosmon/galaxies"
cs_path = "/opt/cosmon/bin/cs"
artifact_root = "/opt/cosmon/artifacts"

The service is deliberately loopback-only here. The tunnel is the sole L0 path to its HTTP surface; the client does not use a direct shell or container-exec path to create, tackle, or fetch work.

Step 4: Open the tunnel, mint a demo token, and create a client profile

On the client machine, open a tunnel. It maps the remote service's loopback port to a local port. The mock remains loopback-only on the remote host, so mint its short-lived token server-side and pass it to the client; this avoids needing a second IdP tunnel:

ssh -f -N -L 127.0.0.1:8443:127.0.0.1:8443 <remote>

TOKEN=$(ssh <remote> '
  curl --fail --silent --show-error -X POST \
    "http://127.0.0.1:8444/issue?sub=demo-operator&aud=cosmon-rpp-test&scopes=cosmon:molecule:read,cosmon:molecule:write" \
    | jq -r .access_token
')
export COSMON_REMOTE_TOKEN="$TOKEN"

cosmon-remote stores a default profile and one profile file per service. Resolution is --profile first, then $COSMON_REMOTE_PROFILE, then the configured default.

Create the profile manually (or use the service's install.sh profile installer when your deployment provides one). oidc-url remains required by a profile, but the pre-minted token means this client does not need to reach it:

cosmon-remote config init demo http://127.0.0.1:8443
cosmon-remote config set host http://127.0.0.1:8443
cosmon-remote config set sub demo-operator
cosmon-remote config set aud cosmon-rpp-test
cosmon-remote config set oidc-url http://127.0.0.1:8444
cosmon-remote config set issuer https://idp.test.cosmon-oidc-testkit
cosmon-remote config set client-id cosmon-rpp-test
cosmon-remote config set noyau demo
cosmon-remote config set timeout 30
cosmon-remote config set artifacts-dir ./cosmon-artifacts
cosmon-remote config set phone-home off

Verify both liveness and the identity that the service resolved:

cosmon-remote healthz
cosmon-remote auth me

Step 5: Drive the measured golden path

From the thin client, create a molecule, dispatch it, wait for its detached worker to finish, and retrieve its artifact:

cosmon-remote do --yes "write a Rust function that returns the nth Fibonacci number"
cosmon-remote artifact list <molecule-id>
cosmon-remote artifact get <molecule-id> <artifact-token> --out ./result.md

The do gesture performs nucleate then tackle; tackle returns a worker session promptly while the local Ollama worker runs detached on the remote host. The successful path is:

thin client -> tunnel -> fente -> cs tackle -> local Ollama worker
             <- artifact get <- completed molecule <- detached worker

This confirms the full service contract: a profile-authenticated thin client creates work over the tunnel, the remote service dispatches the local adapter, the molecule reaches completed, and the client receives the resulting artifact without an interactive remote execution path.

Addressing artifacts

artifact list prints opaque artifact tokens such as art_...; use the token, not a server path, with artifact get <molecule-id> <artifact-token>. During cs tackle, the adapter creates <artifact_root>/<noyau>/<molecule-id>/ and exports that directory as $COSMON_ARTIFACT_DIR to the worker. The client fetches bytes with --out; when omitted, it writes under ./cosmon-artifacts/<molecule-id>/<artifact-token>.

Troubleshooting and security

On a sovereign local-adapter host, a 503 tackle_unavailable message mentioning “Claude Code not installed” is an expected default-container diagnostic, not a requirement for the local Ollama path. An empty artifact list normally means the worker has not written its deliverable or has not completed yet. A 401 or 403 from auth me means to compare the token's issuer, subject, audience, and scopes with trusted-issuers.toml and the rendered nucleon binding.

Security: the local worker is sandboxed for untrusted work: it receives a six-tool, shell-free registry rather than host-shell access; a toolchain preflight runs before work; and each molecule has a wall-clock limit. It cannot use that worker interface to scan the host or read outside its worktree.

See also

CLI overview

These commands use physics-inspired names (nucleate, evolve, decay, spore, …). New to the vocabulary? See The physics vocabulary.

Cosmon — compose, pilot and audit long-haul AI missions where the trace matters.

Global options

These flags are accepted before any subcommand and apply to every command:

FlagEffect
--config <PATH>Path to the configuration file.
--verbose, -vEnable verbose output.
--jsonEmit machine-readable JSON/NDJSON instead of the human view.

--json is the agent-first interface: every cs command honours it, so a worker or external orchestrator parses structured output rather than scraping the terminal render.

Command groups

The command reference is split by role:

Molecule lifecycle commands

These commands use physics-inspired names (nucleate, evolve, decay, spore, …). New to the vocabulary? See The physics vocabulary.

cs spark

Spark — capture a one-line operator intent into the Inbox (ADR-061)

Usage: cs spark [OPTIONS] <TEXT>

EXAMPLES: cs spark "réunion demain : revoir le pitch" cs spark "debug the flaky test" --kind task cs spark "CI broken on macOS" --kind issue --tag temp:warm cs spark "constellation idea" --nucleon operator-demo@example.com

A spark is the pre-task — a one-line operator intent dropped into the Inbox (HOT bucket by default) with the sparker's identity attached. The demo criterion: operator-demo on her iPhone via Blink Shell SSH types a single spark and the operator sees it on the next 'cs peek' refresh. No Claude Code in the chain.

DEFAULTS: --kind idea # 💡 one-line Inbox shape --tag temp:hot # surfaces in 'cs inbox' HOT bucket nucleon_id: git user.email, else $USER@$(hostname)

SACRIFICES: offline fails, auth ≡ SSH access, no push (next refresh), raw Blink terminal UX, v1 is one-way (no pilot reply from Inbox).

SEE ALSO: cs inbox (where sparks land), cs tackle (promote to work), cs transform (re-kind), cs collapse (reject with reason).

Arguments:
  • <TEXT> — The spark text itself — what appeared in the operator's head.

    Captured verbatim into the molecule's topic variable and thus into prompt.md (sealed by the usual nucleate path). Quote the argument if it contains spaces.

Options:
  • --kind <KIND> — Override the molecule kind. Defaults to idea (💡) — the Jobs §2 shape. Accepts idea, task, issue, or any other [cosmon_core::kind::MoleculeKind] string the operator cares to pass; the actual validation happens in nucleate

    Default value: idea

  • --tag <TAG> — Tag to attach (repeatable). When no --tag is supplied the spark lands with temp:hot so it surfaces immediately in cs inbox (HOT bucket) and cs ensemble --tag temp:hot

  • --fleet <FLEET> — Fleet to nucleate into. Defaults to default

    Default value: default

  • --nucleon <NUCLEON> — Override the auto-derived nucleon_id (sparker identity).

    Normally derived from git config user.email with a $USER@$(hostname) fallback. Pass this when scripting a test demo or when the git email is not the identity you want to record.

  • --sparked-by <SESSION_ID> — Currently-open pilot-session molecule id (ADR-061 §SparkedBy).

    Recorded as a variable only in v1 — the SparkedBy typed link is reserved until ADR-061 is marked accepted. Passed verbatim into prompt.md so later migrations can recover the edge.

  • --formula <FORMULA> — Override the formula name (defaults to spark). Exists for tests and for exotic deployments that vendor their own capture formula; normal callers leave this unset

    Default value: spark

  • --formulas-dir <DIR> — Path to the formulas directory (defaults to walk-up discovery)

  • --store-dir <DIR> — Path to the state store root (defaults to walk-up discovery)

cs drop

Drop — universal Inbox gesture (hotkey / zsh widget / menubar) → cs spark

Usage: cs drop [OPTIONS] [TEXT]...

EXAMPLES: cs drop # universal Inbox gesture — captures whatever is in scope

Equivalent of cs spark reachable from hotkey / zsh widget / menubar.

SEE ALSO: cs spark (canonical), cs nucleate spark (formula form).

Arguments:
  • <TEXT> — The drop text itself. When absent or empty, the text is read from stdin — supports cs drop < file and pipe chains.

    Multiple words are joined with single spaces so callers can pass raw command-line tokens (cs drop hello there) without quoting. Leading/trailing whitespace is trimmed.

Options:
  • --galaxy <NAME> — Galaxy name to drop into. Resolved via ~/.config/cosmon/galaxies.toml ([TomlGalaxyIndex]).

    When set, the resolved Galaxy.path becomes the store root (<path>/.cosmon/state/) for this nucleation. Without it, cosmon's usual walk-up discovery picks the galaxy from the current working directory.

  • --kind <KIND> — Molecule kind override. Defaults to idea — same as cs spark.

    The briefing names spark | idea | task as common choices; any valid [cosmon_core::kind::MoleculeKind] token is accepted (validated in nucleate).

    Default value: idea

  • --tag <TAG> — Additional tag to attach (repeatable). temp:hot and source:drop are always added; --tag extends the list.

    Callers use this to stamp the drop's origin surface (e.g. --tag source:shortcut from the iPhone SSH wrapper, which supplements rather than replaces source:drop).

  • --fleet <FLEET> — Fleet to nucleate into. Defaults to default

    Default value: default

  • --nucleon <NUCLEON> — Override the auto-derived nucleon_id (drop author identity). Same semantics as cs spark --nucleon

  • --sparked-by <SESSION_ID> — Currently-open pilot-session molecule id (ADR-061 §SparkedBy). Same semantics as cs spark --sparked-by

  • --formula <FORMULA> — Override the formula name (defaults to spark). Exists for tests and exotic deployments; normal callers leave this unset

    Default value: spark

  • --formulas-dir <DIR> — Path to the formulas directory (default: walk-up discovery)

  • --store-dir <DIR> — Path to the state store root (default: walk-up discovery, or the galaxy-registry lookup when --galaxy is set)

cs listen

Listen — voice → whisper.cpp → cs nucleate spark (MVP)

Usage: cs listen [OPTIONS]

EXAMPLES: cs listen # voice-driven spark capture (whisper.cpp) cs listen --once # single utterance, then exit

Voice ingress to the fleet. Wraps whisper.cpp transcription and produces a spark molecule per utterance.

SEE ALSO: cs spark, cs drop.

Options:
  • --seconds <SECONDS> — Seconds to record before cutting off (no VAD in v0).

    Ignored when --transcript or --audio is supplied. Keep the value short: whisper-cli on CPU runs near 1× realtime on the small model, so 15 s of speech costs ~15 s of wall-clock.

    Default value: 10

  • --transcript <TEXT> — Skip recording + transcription and use this text directly.

    Useful for scripting (end-to-end dry-runs without a microphone) and for isolating the spark pipeline from the audio stack when debugging. Incompatible with --audio.

  • --audio <PATH> — Transcribe an existing audio file instead of recording.

    Accepted formats are whatever the configured whisper-cli was built with (WAV/FLAC/MP3 on the default homebrew build). Incompatible with --transcript.

  • --whisper-bin <PATH> — Path to the whisper-cli binary (defaults to whisper-cli in $PATH).

    This is the whisper.cpp CLI (brew install whisper-cpp), not the OpenAI Python package — the latter is slower and violates the local-first constraint (it bundles PyTorch).

    Default value: whisper-cli

  • --model <PATH> — Path to the whisper model (e.g. ggml-small.bin).

    Can also be set via the COSMON_WHISPER_MODEL env var. Required for actual transcription — if absent and --transcript was not supplied the command fails loudly instead of silently producing an empty spark.

  • --language <LANG> — Whisper language hint: auto, fr, en, …

    The whisper-cpp flag accepts ISO 639-1 codes. auto asks whisper to detect the language itself.

    Default value: auto

  • --ffmpeg-bin <PATH> — Path to the ffmpeg binary used for recording

    Default value: ffmpeg

  • --device <SPEC> — ffmpeg AVFoundation input device specifier.

    On macOS the default microphone is ":0". Run ffmpeg -f avfoundation -list_devices true -i "" to enumerate.

    Default value: :0

  • --dry-run — Skip nucleation — print the transcript only.

    Use this when validating the audio path on a fresh machine so you do not pollute the Inbox with test utterances.

  • --kind <KIND> — Molecule kind for the resulting spark (delegated to cs spark)

    Default value: idea

  • --tag <TAG> — Tag to attach (repeatable, defaults to temp:hot)

  • --fleet <FLEET> — Fleet to nucleate into

    Default value: default

  • --nucleon <NUCLEON> — Override the auto-derived nucleon_id (sparker identity)

  • --formulas-dir <DIR> — Path to the formulas directory (defaults to walk-up discovery)

  • --store-dir <DIR> — Path to the state store root (defaults to walk-up discovery)

cs nucleate

Nucleate a new molecule from a formula template

Usage: cs nucleate [OPTIONS] [FORMULA]

EXAMPLES: cs nucleate task-work --var topic="refactor CLI help" cs nucleate deep-think --kind deliberation --var question="..." cs nucleate patrol --blocks root-mol # add a DAG edge cs nucleate constellation --kind constellation
--var pattern="three molecules re-invent the same missing primitive"
--var citations="delib-example-0001,task-example-0002,idea-example-0003" cs nucleate --from molecules/ # hydrate from TOML declarations

KINDS (--kind): idea 💡, task 🔧, decision 📐, issue 🐛, signal ⚡, deliberation 🧠 (use with the deep-think formula), constellation 🌌 (fil-rouge artifact; see cs help guide).

LINK FLAGS: --blocks DAG progression edge (target cannot advance until this one completes) --blocked-by symmetric counterpart of --blocks --decayed-from information edge: parent this molecule emerged from --refines citation edge (no progression semantics), auto-populated from --var citations for --kind constellation

SEE ALSO: cs tackle (launch a worker on the molecule you just nucleated). docs/guides/constellation-pattern.md (when to use 🌌 vs 🧠).

Arguments:
  • <FORMULA> — Formula name (looks for {name}.formula.toml in the formulas directory).

    Required unless --from is supplied.

Options:
  • --from <PATH> — Hydrate molecule(s) from a TOML declaration file or directory.

    When PATH is a directory, every *.toml file inside (non-recursive, sorted) is loaded as a [MoleculeDeclaration]. The positional formula argument is ignored in this mode — each declaration carries its own formula field.

  • --blocks <MOLECULE_REF> — Target molecule(s) that this new molecule blocks — each target cannot progress until this one completes.

    Accepts two forms: - <molecule-id> — same-galaxy edge. Adds Blocks here and a symmetric BlockedBy on the target. Targets must already exist. - <galaxy-alias>:<molecule-id> (or <galaxy-alias>@<molecule-id>) — cross-galaxy edge (Phase 1, ADR-035). The remote target is resolved best-effort via configured galaxy aliases or the cluster root. The reciprocal edge is not filed on the target galaxy (one-writer-per-galaxy, ADR-052) — the edge is recorded locally and a stderr warning is emitted if the target is unreachable.

  • --blocked-by <MOLECULE_REF> — Source molecule(s) that block this new molecule — this new molecule cannot progress until each source completes.

    Same syntax as --blocks, including the <alias>:<mol_id> cross-galaxy form (Phase 1, ADR-035).

  • --decayed-from <MOLECULE_ID> — Declare that the new molecule decayed from PARENT_ID — an information edge (not a progression edge): the parent is the cognitive source this molecule emerged from, but the parent is free to keep advancing independently. Symmetric counterpart: the parent gains a DecayProduct link to the new molecule.

    This is the explicit form of the auto-parent contract: when a worker cs tackles a molecule, COSMON_PARENT_MOL_ID is injected into its environment, and any subsequent cs nucleate from that worker auto-populates this flag unless one of --blocks, --blocked-by, --decayed-from, or --no-parent is already set. Passing it explicitly wins over the env var.

  • --no-parent — Disable the env-driven auto-parent contract for this invocation.

    When set, the COSMON_PARENT_MOL_ID environment variable is ignored and no DecayedFrom edge is synthesized. Use this for legitimate orphan nucleations (e.g., a worker that intentionally spawns an unrelated top-level molecule).

  • --refines <MOLECULE_ID> — Cited molecule(s) that this new molecule refines (semantic citation edge — does NOT carry progression semantics, unlike --blocks).

    For every target, the new molecule gets a Refines link and the target gets a symmetric RefinedBy link. Intended for Constellation molecules that name a fil-rouge across N existing molecules. Repeat the flag per citation; targets must already exist.

    Also auto-populated for --kind constellation from a comma-separated --var citations=mol1,mol2,mol3.

  • --refutes <MOLECULE_ID> — Diagnosis molecule(s) that this new molecule refutes (semantic refutation edge — no progression semantics, unlike --blocks).

    For every target, the new molecule gets a Refutes link and the target gets a symmetric RefutedBy link. This is the DAG-native form of the ADR-143 diagnosis-verify gate: a cmb-verify molecule that reproduces a relayed symptom but finds the stated mechanism describes a nonexistent code path records the divergence by refuting the diagnosis molecule. Repeat the flag per refuted diagnosis; targets must already exist.

  • --fleet <FLEET> — Fleet to nucleate the molecule into (default: "default")

    Default value: default

  • --kind <KIND> — Molecule kind: idea, task, decision, issue, signal, deliberation, constellation (see docs/guides/constellation-pattern.md)

  • --class <CLASS> — Operational class — standard (default), stress-test, or infra (ADR-085 §1).

    stress-test opts the molecule into the two-layer pre-commitment seal at dispatch (Layer 1 runtime precondition + Layer 2 witness-quorum, ADR-085 §2-§3) and out of autopilot drain. The remaining classes are gate-equivalent to the legacy default; this flag is a marker, not a runtime mode.

  • --assign <ASSIGN> — Assign a worker to the new molecule

  • --var <KEY=VALUE> — Set a variable (repeatable: --var key=value)

  • --formulas-dir <DIR> — Path to the formulas directory (default: ./formulas)

  • --role <ROLE> — Agent role for the worker that will tackle this molecule.

    Valid roles: orchestration, research, implementation, infrastructure, advisory, validation. When set, cs tackle uses this role instead of the default implementation.

  • --store-dir <DIR> — Path to the state store root (default: .cosmon)

  • --tag <TAG> — Typed label to attach to the new molecule (repeatable).

    Format: key or key:value. Keys are kebab-case; values exclude whitespace and :. Duplicate tags are deduplicated.

  • --interaction-mode <MODE> — Static interaction-mode discriminant posed at nucleation.

    One of operator-required or background. Recorded as the interaction-mode:<mode> tag. Posed by the molecule's author — often an agent — and read at dispatch ; survives the operator's present state. Default explicit, not implicit : when absent, the tag is simply not set, and consumers (the graceful degradation controller, in particular) decide what to do.

    Conflicts with --tag interaction-mode:* to keep the discriminant single-sourced.

  • --may-block-on-operator <BOUNDARY> — Grant the operator-block capability at an irreversibility boundary (ADR-123 Q5).

    One of signature, external-send, publish, authoritative-value. Recorded as the op-block:<boundary> tag. A worker reads this single typed capability to decide whether it MAY pause for an operator (cs await-operator) at that boundary — or, when absent, MUST surface-and-continue. The capability is granted here at nucleation and never self-asserted by the worker.

    Conflicts with --tag op-block:* to keep the grant single-sourced.

  • --ttl <DURATION> — Relative TTL — deadline is now + duration (ADR-029).

    Grammar: <N><unit> where unit ∈ {s,m,h,d,w}. Examples: 7d, 24h, 2w. Mutually exclusive with --expires-at.

  • --expires-at <WHEN> — Absolute expiry instant (ADR-029).

    Accepts RFC3339 (2026-07-02T00:00:00Z) or a plain YYYY-MM-DD date (anchored at end-of-day 23:59:59Z). Mutually exclusive with --ttl.

  • --expiry-policy <POLICY> — Expiry policy — what to do when expires_at is in the past.

    One of warn, collapse, escalate. Defaults to the per-kind default from config (or warn) when unset. Only meaningful when --ttl or --expires-at is also provided.

  • --energy-budget <N> — Per-molecule step counter circuit breaker (THESIS Part XI).

    cs evolve decrements this once per step. At zero, the next attempt transitions the molecule to Frozen with reason "energy-exhausted". Default comes from .cosmon/config.toml [energy] default_step_budget (100 if absent). Pass 0 to disable the breaker for this molecule.

  • --require-galaxy — Refuse to nucleate into the host-global ~/.cosmon/state fleet.

    By default, running cs nucleate from a directory with no .cosmon/config.toml in cwd or any ancestor falls back to the host-global state dir ($HOME/.cosmon/state) and prints a warning to stderr — the molecule is born into a fleet invisible to every galaxy. --require-galaxy turns that warning into a hard error (exit ≠ 0), so scripts and tooling that must write galaxy-scoped state can fail fast instead of silently leaking orphans.

  • --adapter <NAME> — Durable per-molecule adapter pin — the rung-1 provider-family intent stamped at nucleation (ADR-097 / C6; committee-20260723-c0a1).

    Unlike the transient cs tackle --adapter flag (which routes a single dispatch), this pin is persisted to MoleculeData::adapter and survives any later run directive. A cs run --resident --adapter <X> owns a run-wide directive that stamps every pin-less molecule with <X>; a molecule nucleated with --adapter <Y> keeps <Y> because the per-molecule pin beats the run directive (cosmon_runtime::resident). This is what lets a cross-provider committee pin a seat's distinct family (e.g. mistral) so a resident loop driving the generator's family (e.g. claude) cannot auto-tackle the seat into a FamilyCollision.

    Values are validated against the adapter-name grammar (the same check cs tackle --adapter applies); an empty or malformed name aborts the nucleation. None (the default) stamps no pin — the molecule resolves its adapter through the canonical cs tackle chain at dispatch.

cs observe

Observe a molecule's current state and history

Usage: cs observe [OPTIONS] [MOLECULE_ID]

EXAMPLES: cs observe task-example-0001 # one-shot snapshot (never poll!) cs observe task-example-0001 --json # for scripts

SEE ALSO: cs wait (block until terminal), cs peek (fractal TUI).

Arguments:
  • <MOLECULE_ID> — Molecule ID (or prefix) to inspect. Omit to list all molecules
Options:
  • --status <STATUS> — Filter by status (active, frozen, completed, collapsed)

  • --worker <WORKER> — Filter by assigned worker

  • --formula <FORMULA> — Filter by formula

  • --search <SEARCH> — Free-text search across molecule fields

  • --all — Include completed and collapsed molecules (excluded by default in list mode)

  • --tag <GLOB> — Filter by tag glob pattern (repeatable, any-match)

  • --notes <N> — Number of trailing notes to show in detail mode (default: 3)

    Default value: 3

cs evolve

Evolve a molecule to its next lifecycle state

Usage: cs evolve [OPTIONS] --evidence <EVIDENCE> --formula <FORMULA> <MOLECULE>

EXAMPLES: cs evolve --evidence "step 1 done"
--formula .cosmon/formulas/task-work.formula.toml

Worker-callable. Advances the molecule one step per invocation.

Arguments:
  • <MOLECULE> — Molecule ID to evolve
Options:
  • --evidence <EVIDENCE> — Evidence documenting why the current step is complete
  • --ops-dir <OPS_DIR> — Path to the state store root (overrides walk-up discovery)
  • --formula <FORMULA> — Path to the formula TOML file

cs complete

Complete a molecule — idempotent Active→Completed transition (worker-callable)

Usage: cs complete [OPTIONS] [MOLECULE]

EXAMPLES: cs complete --reason "all steps done"

Idempotent Active→Completed transition. Worker-callable. Does NOT merge the branch or teardown the tmux session — use cs done for that.

SEE ALSO: cs done (merge + teardown), cs evolve (advance one step).

Arguments:
  • <MOLECULE> — Molecule ID to complete (single mode)
Options:
  • --batch <BATCH> — Complete multiple molecules at once

  • --reason <REASON> — Reason for completion (recorded in the log)

    Default value: completed via cs complete

  • --ops-dir <OPS_DIR> — Path to the state store root (overrides walk-up discovery)

  • --override-mindguard-down — Bypass mindguard only when the gate machinery itself is unreachable. Requires --justification. Lands a record in the append-only ledger at ~/.cosmon/audit/mindguard-overrides.jsonl before the completion proceeds. NEVER use this to bypass a MindguardRefused — the remedy for that is to run cs nucleate verify-surface --var target=<MOL>

  • --justification <JUSTIFICATION> — Justification for --override-mindguard-down. Required when the override flag is set. Recorded write-once in the audit ledger

cs collapse

Collapse a molecule — terminate with final state recording

Usage: cs collapse [OPTIONS] --reason <REASON> <MOLECULE>

EXAMPLES: cs collapse --reason "superseded by " cs collapse --reason "Claude usage limit reached"
--cause rate_limit --account default --kind max_rolling_5h

Terminal transition. Use instead of leaving stale pending molecules.

Pass --cause to attribute the failure with a structured tag (ADR-062): rate_limit — quota refused; pair with --account ALIAS --kind CURRENCY (max_rolling_5h, max_weekly, api_key_org_monthly, …). Surfaces as ghost: quota-exhausted in cs peek. inference_stall — worker alive but stopped emitting tokens. manual — operator decision (default if --reason alone). process_death — worker process died (OOM, signal). unknown — could not be classified.

Arguments:
  • <MOLECULE> — Molecule ID to collapse
Options:
  • --reason <REASON> — Reason for the collapse
  • --cause <CAUSE> — Structured cause attribution (ADR-062): rate_limit, inference_stall, manual, process_death, unknown. With rate_limit, pair --account and --kind for the K3 fixture shape
  • --account <ALIAS> — Account alias for --cause rate_limit (e.g. default)
  • --kind <KIND> — Quota currency name for --cause rate_limit (e.g. max_rolling_5h, max_weekly, api_key_org_monthly, financial_usd, custody_scoped). Free-form to remain extensible across providers
  • --reason-kind <REASON_KIND> — Operator-facing collapse classification for cs errors aggregation: one of worker_crashed, gate_failed, blocker_stuck, manual_abort, resource_exhausted. Any other value lands in [CollapseReason::Other] verbatim
  • --ops-dir <OPS_DIR> — Path to the state store root (overrides walk-up discovery)

cs stuck

Stuck — freeze a molecule and record the blocker

Usage: cs stuck --reason <REASON> <MOLECULE>

EXAMPLES: cs stuck --reason "waiting on ADR-30 decision"

Terminal-ish: freezes the molecule with a recorded blocker. Consider cs tag <mol> --add temp:frozen for backlog hygiene.

Arguments:
  • <MOLECULE> — Molecule ID that is stuck
Options:
  • --reason <REASON> — What is blocking progress

cs await-operator

Await-operator — the only sanctioned way to block on an operator decision at an irreversibility boundary (ADR-123). Routes on the molecule's op-block:* capability: block-and-emit, or surface-and-continue

Usage: cs await-operator --question <TEXT> <MOLECULE_ID>

EXAMPLES: cs await-operator --question "Sign and transmit the act, or revise?" cs await-operator --question "Push to the shared remote?" --question "Tag v1.2?"

Worker-callable (ADR-123). The ONLY sanctioned way to block on an operator decision at an IRREVERSIBLE boundary (signature transmitted, push to a shared remote, publish, an authoritative value downstream consumers act on). NEVER raise an off-cosmon modal (AskUserQuestion) — it is invisible to cosmon and the DAG stalls silently.

Routes on the molecule's op-block:<boundary> capability (granted at nucleation via cs nucleate --may-block-on-operator <boundary>): • capability present → BLOCK: writes blocked_on.json, emits worker_blocked_on_operator, tags temp:awaiting-op, and yields. Molecule stays Running. • capability absent → SURFACE-AND-CONTINUE: writes responses/needs-review.md and tells you to pick a sensible default and keep working (reversible).

SEE ALSO: cs nucleate --may-block-on-operator, cs patrol --event-age.

Arguments:
  • <MOLECULE_ID> — Molecule ID whose worker is blocking
Options:
  • --question <TEXT> — A decision the operator is being asked to make (repeatable). At least one is required

cs freeze

Freeze a worker — suspend with state preservation (preemption)

Usage: cs freeze [OPTIONS] <WORKER>

EXAMPLES: cs freeze worker-3 # suspend, keep state for later thaw cs freeze worker-3 --reason "rotating OOM" # graceful shutdown with recorded intent

--reason <str> is the canonical replacement for the former cs quench verb (ADR-052 §D3): graceful shutdown with state preservation IS freeze, and the reason captures operator intent on the audit event.

SEE ALSO: cs thaw (resume a frozen worker), cs tackle (launch replacement after freezing an incumbent — priority inversion = freeze + tackle).

Arguments:
  • <WORKER> — ID of the worker to freeze
Options:
  • --by <BY> — ID of the worker that is preempting this one (optional metadata)

  • --reason <REASON> — Operator-supplied reason for the freeze, recorded on the event.

    Under ADR-052 §D3, cs freeze --reason <str> subsumes the former cs quench verb: "graceful shutdown with state preservation" is what freeze already does, and the reason is the missing metadata that distinguished quench's intent.

  • --timeout <TIMEOUT> — Grace period in seconds before force-killing (default: 15)

    Default value: 15

  • --no-tmux — Skip tmux interaction (state-only transition, for testing)

cs thaw

Thaw a worker — resume a frozen worker's Claude session

Usage: cs thaw [OPTIONS] <WORKER>

EXAMPLES: cs thaw worker-3 # resume a previously frozen worker

SEE ALSO: cs freeze (counterpart), cs resume (nudge idle workers).

Arguments:
  • <WORKER> — ID of the worker to thaw
Options:
  • -c, --continue <CONTINUE_MSG> — Custom message to send after respawn instead of the default resume prompt.

    Useful for hot-restart scenarios: e.g. "A new MCP server X is now available. Continue your work on molecule Y."

  • --no-tmux — Skip tmux interaction (state-only transition, for testing)

cs decay

Decay a molecule into child molecules (1 → N)

Usage: cs decay [OPTIONS] --formula <FORMULA> --reason <REASON> <SOURCE>

EXAMPLES: cs decay --into task --var topic="subtask A" cs decay --formula task-work --var topic="subtask B"

1 → N. Children get a DecayProduct link back to parent. Remember to cs tag <child> --add temp:warm so backlog curation works.

Arguments:
  • <SOURCE> — Source molecule ID to decay
Options:
  • --formula <FORMULA> — Formula for the product molecules

  • --count <COUNT> — Number of products to create (or provide --product-vars multiple times)

    Default value: 1

  • --product-kind <PRODUCT_KIND> — Kind for the product molecules (default: task)

    Default value: task

  • --reason <REASON> — Reason for the decay

  • --chain — Wire consecutive decay products with Blocks/BlockedBy links (A→B→C)

  • --blocks <BLOCKS> — Explicit Blocks edges: the i-th product blocks the given molecule IDs. Repeatable; applied to each product in order

cs merge

Merge molecules into a synthesis (N → 1)

Usage: cs merge [OPTIONS] --formula <FORMULA> --reason <REASON> [SOURCES]...

EXAMPLES: cs merge --into synthesis- cs merge --formula synthesis --var kind=decision

N → 1. Inverse of decay.

Arguments:
  • <SOURCES> — Source molecule IDs to merge (space-separated)
Options:
  • --formula <FORMULA> — Formula for the product molecule

  • --product-kind <PRODUCT_KIND> — Kind for the product molecule (default: decision)

    Default value: decision

  • --reason <REASON> — Reason for the merge

cs transform

Transform a molecule's kind (idea → task, etc.)

Usage: cs transform --to <TO> --reason <REASON> <MOLECULE>

EXAMPLES: cs transform --to task # idea → task cs transform --to decision

Preserves molecule ID; rewrites kind + formula bindings.

Arguments:
  • <MOLECULE> — Molecule ID to transform
Options:
  • --to <TO> — Target kind: idea, task, decision, issue
  • --reason <REASON> — Reason for the transform

cs tag

Tag — add or remove typed labels on a molecule

Usage: cs tag [OPTIONS] <MOLECULE_ID>

EXAMPLES: cs tag --add temp:hot cs tag --remove temp:warm --add temp:frozen

Temperature tags govern backlog curation — see CLAUDE.md § Molecule Temperature Tags.

Arguments:
  • <MOLECULE_ID> — Molecule ID to retag
Options:
  • --add <TAG> — Tag to add (repeatable). Format: key or key:value
  • --remove <TAG> — Tag to remove (repeatable). Matched by exact string

Fleet management commands

These commands use physics-inspired names (nucleate, evolve, decay, spore, …). New to the vocabulary? See The physics vocabulary.

cs ensemble

Display ensemble status — observe the fleet at a glance

Usage: cs ensemble [OPTIONS]

EXAMPLES: cs ensemble # all molecules, all fleets cs ensemble --tag temp:hot # actionable backlog snapshot cs ensemble --fleet research # one fleet only cs ensemble --json # NDJSON for scripting

Options:
  • --all — Show molecules from all projects, not just the current one

  • --cluster [alias: cluster] — Walk every .cosmon/-bearing galaxy under $COSMON_CLUSTER_ROOT (default $HOME/galaxies) and print one aggregated table.

    This is the cross-galaxy extension of --all. Where --all drops the project-id filter within the current state dir, --cluster visits every sibling galaxy on disk and prints their workers + molecule counts. Works in tandem with --all (implicitly drops the project filter because the scope is now the whole cluster).

  • --cluster-root <DIR> — Override the cluster root directory when --cluster is set. Defaults to $COSMON_CLUSTER_ROOT env var, then $HOME/galaxies

  • --tag <GLOB> — Filter molecules by tag glob pattern (repeatable, any-match).

    Patterns support * as wildcard. Example: --tag deferred:*. Molecules without a matching tag are excluded from the molecule summary counts.

cs purge

Purge dead workers from fleet state (Stopped, Error, Stale)

Usage: cs purge [OPTIONS] [WORKER]

EXAMPLES: cs purge # sweep: remove Stopped / Error / Stale workers cs purge worker-3 # targeted: remove a single worker (graceful path) cs purge worker-3 --force # targeted + SIGKILL tmux (supersedes cs kill)

ADR-052 §D3 collapses cs kill + cs purge into this one verb: both are infrastructure teardown. Sweep mode (no argument) stays unchanged; targeted mode with --force replaces cs kill.

SEE ALSO: cs freeze (graceful + state preservation), cs teardown (fleet-wide graceful shutdown).

Arguments:
  • <WORKER> — Optional worker ID — when given, targeted purge of that worker only.

    Without a worker the command sweeps every terminal-state worker from fleet state (the pre-ADR-052 behaviour). With a worker, only that worker is removed; pair with --force to SIGKILL its tmux session first (formerly cs kill).

Options:
  • --force — In targeted mode, SIGKILL the tmux session before removing the fleet entry. Ignored in sweep mode. Supersedes the stand-alone cs kill verb (ADR-052 §D3)

  • --status <STATUS> — Only purge workers matching this desired state (default: sweep all workers — Stopped ones and Running/Paused ones whose tmux session is gone)

  • --role <ROLE> — Restrict the purge to workers matching this role discriminator — either cognition or runtime (see WorkerRole). Without this flag cs purge removes both runtime and cognition workers that meet the status predicate; with it, operators can clean up one half of a runtime+cognition pair without collapsing the other

  • --allow-unharvested — Collapse molecules whose work is still unharvested (commits ahead of base, or an unclean worktree).

    Without this flag cs purge fails closed: a worker whose pane is gone but whose branch still carries commits — or whose worktree still has uncommitted files — is left in the fleet, its molecule left running, and the commits and files at stake are named in an alert. A dead tmux session is evidence about the pane, not about the work (incident 2026-08-02, where four molecules were silently collapsed after a reboot with up to three commits each still unmerged).

cs kill

Kill a worker — immediate termination (no state flush)

Usage: cs kill <WORKER>

EXAMPLES: cs kill worker-3 # DEPRECATED — see below

DEPRECATED (ADR-052 §D3): use cs purge worker-3 --force instead. This alias will be removed after one release cycle.

SEE ALSO: cs purge (canonical), cs freeze (preserve state), cs done (teardown after a molecule completes).

Arguments:
  • <WORKER> — ID of the worker to terminate

cs quench

Quench a worker — graceful shutdown with state preservation

Usage: cs quench [OPTIONS] <WORKER>

EXAMPLES: cs quench worker-3 # DEPRECATED — see below

DEPRECATED (ADR-052 §D3): use cs freeze worker-3 --reason quench instead. Graceful shutdown with state preservation IS freeze; --reason captures operator intent. Note: the canonical path lands in Paused (resumable via cs thaw) rather than Stopped. This alias will be removed after one release cycle.

SEE ALSO: cs freeze (canonical), cs purge (fleet teardown), cs teardown (fleet-wide graceful shutdown).

Arguments:
  • <WORKER> — ID of the worker to gracefully shut down
Options:
  • --timeout <TIMEOUT> — Grace period in seconds before force-killing (default: 30)

    Default value: 30

  • --force — Skip graceful exit — go straight to force-kill (same as kill)

  • --no-tmux — Skip tmux interaction (state-only transition, for testing)

cs teardown

Teardown a fleet — gracefully stop all fleet workers

Usage: cs teardown [OPTIONS] <FLEET>

EXAMPLES: cs teardown # gracefully stop every worker in the default fleet cs teardown --fleet research

SEE ALSO: cs kill (single worker, hard), cs quench (single worker, graceful).

Arguments:
  • <FLEET> — Name of the fleet to tear down (matches fleet.toml fleet = "..." name)
Options:
  • --force — Force-kill instead of graceful quench
  • --no-tmux — Skip tmux interaction (state-only, for testing)

cs resume

Resume — convenience alias for cs patrol --propel --molecule <id>

Usage: cs resume [OPTIONS]

EXAMPLES: cs resume # nudge all idle workers cs resume worker-3 # nudge one

Convenience alias for cs patrol --propel --molecule <id> — maintains the Propelled regime by re-delivering the propulsion signal. Does NOT change state or advance molecules.

SEE ALSO: cs patrol --propel (canonical command), cs thaw (frozen workers).

Options:
  • --fleet <FLEET> — Only resume workers in this fleet
  • --agent <AGENT> — Only resume this specific agent (by name, across all fleets)
  • -c, --message <MESSAGE> — Custom resume message (default: standard RESUME signal)

cs patrol

Patrol the fleet — health checks and anomaly detection

Usage: cs patrol [OPTIONS]

EXAMPLES: cs patrol # run one health sweep cs patrol --propel # nudge stale molecules cs patrol --respawn # restart dead workers cs patrol --harvest # close Completed-but-unmerged molecules cs patrol --silence-detect # flag workers that stopped heartbeating cs patrol --livelock # detect circular blocked-on waits cs patrol --event-age # flag Running molecules with a quiet event log cs patrol --heal # remediate safe anomaly classes, each §5-guarded cs patrol --heal --dry-run # preview the Deacon's actions, mutate nothing

Designed to be run by an external scheduler (cron, launchd) in the Propelled regime. --harvest is the belt-and-suspenders sweep that complements the tmux pane-died hook installed at cs tackle time. --silence-detect, --livelock, and --event-age are the runtime-independent stall detectors: they read state from disk only, so they fire even when cosmon-runtime is dead (the watchdog's liveness is independent of the thing it watches). --event-age is the external-modal backstop — it keys on the age of any event-log append, so it catches a worker parked at a Claude Code AskUserQuestion modal that emits no cosmon-visible state. Alerts are tiered by irreversibility: only an irreversible-class block (signature/push/publish) fires cs notify.

Options:
  • --respawn — Auto-respawn: restart dead workers by re-creating tmux sessions

  • --no-tmux — Skip tmux liveness checks and respawn (state-only mode, for testing)

  • --propel — Propel: detect running molecules with stale progress and nudge their workers via transport. The cognitive safety net that complements the new propulsion prompt — if a worker falls silent mid-molecule, patrol re-engages it. A worker whose terminal is still producing output is thinking, not idle, and is never nudged; a genuinely silent one is nudged with exponential backoff, at most 4 times, after which the molecule is tagged propel-exhausted for --heal. A worker that lost its briefing (orphaned by a crash / machine-sleep) cannot evolve, so it is never nudged at all: it is tagged propel-orphaned, the operator is paged via cs notify, and the brief must be re-delivered (cs tackle --force) or the molecule collapsed — closing the 2026-07-21 money-pump where a brief-less worker was nudged for six hours

  • --propel-api-stall — Propel on a typed provider stall — the narrow channel. Consults each live worker's provider session journal and re-engages one only when its last assistant record carries the provider's own transport-failure flag (Claude's isApiErrorMessage), the molecule is still Running, and no human is piloting it. Distinct from --propel, whose trigger is the inference "this worker looks idle" — the trigger that had to be turned off on 2026-07-23 because a worker that is thinking is not a worker that is stuck. The flag is a fact the provider wrote down; a worker parked on it has no turn in flight to interrupt. Never keys on pane text or on the error sentence: a user record quoting that sentence verbatim carries no flag and is never propelled (the be1e SEV-1 use/mention trap). Keeps every --propel guardrail — exponential backoff to propel-exhausted, the propel-orphaned escalation, the ADR-137 §5 no-interference guard and the ~/.cosmon/health.off kill-switch

  • --stale-after <STALE_AFTER> — Staleness threshold in seconds for --propel (default: 300). A molecule is a candidate if updated_at is older than this AND its worker's terminal has been silent at least as long. Also the first backoff window, doubling per nudge up to 30 min. --propel-api-stall reuses it for the terminal-silence bar and the backoff base, but never as a candidacy test: there, candidacy is the provider's typed flag

    Default value: 300

  • --nudge — Nudge: per-step stall remediation. Like --propel, but classifies stalls from last_progress_at against the active step's timeout_minutes budget (M3, default 30 min) and guards idempotence — a worker won't be nudged twice within 60 s. Also covers the boot-stall class (task-20260718-ac03): a Running molecule with NO progress signal at all — the stuck bootstrap paste whose Enter was lost at spawn — is nudged once tackled more than 120 s ago. The nudge text references briefing.md so the re-engaged worker re-reads its contract before continuing. Increments [cosmon_state::MoleculeData::nudge_count] (M5)

  • --expire — Expire sweep: scan molecules whose expires_at is in the past and apply their [ExpiryPolicy] (ADR-029). Idempotent — safe to run repeatedly on the same state. Warn tags the molecule with expired and emits a surface alert; Collapse transitions pendingcollapsed with reason expired (TTL); Escalate tags escalated and emits the canonical Expired event for downstream transforms

  • --auto-collapse — Aggressive orphan remediation: transition orphaned molecules to Collapsed (terminal) instead of Frozen (recoverable). Default is Frozen because the molecule can be revived once the worker situation is understood; --auto-collapse is for cases where the operator wants the DAG to advance past the dead work and never revisit it

  • --harvest — Harvest sweep: scan every Completed molecule with merged_at = None and invoke cs harvest --molecule <id> on each one. Belt-and- suspenders safety net for cases where the tmux pane-died hook never armed (tmux server restart, brutal crash, molecule completed before the hook was installed, …). Idempotent: already-merged molecules are silent no-ops inside cs harvest

  • --livelock — Livelock sweep: read .cosmon/state/presence/<sid>/blocked_on.json for every live session, build the session-wait graph, and report any non-trivial strongly connected component. Emits a temp:hot issue molecule tagged livelock-detected per cycle. Never auto-resolves (turing §6, §8b: propose, don't impose)

  • --livelock-stale-after <LIVELOCK_STALE_AFTER> — Staleness threshold for --livelock, in seconds. blocked_on.json entries older than this are considered crashed-session residue rather than live waits and are excluded from the graph. Defaults to one hour — the cost of a false negative (missing a real lock) is lower than the cost of a false positive (nuisance issue)

    Default value: 3600

  • --silence-detect — Silence-detect: scan running molecules for those whose worker has not emitted a WorkerHeartbeat in silence_after seconds. Tags temp:frozen, emits WorkerSilenceDetected, and fires cs notify ("absence of signal must itself be a signal"). Does not kill the worker

  • --silence-after <SILENCE_AFTER> — Threshold in seconds for --silence-detect (default: 90). Roughly 3 × the recommended 30-second heartbeat cadence; raise it for fleets with longer steps or noisy networks

    Default value: 90

  • --event-age — Event-age check: for every Running molecule, raise an ALERT-only signal when the most recent entry in the event log for that molecule is older than event_age_after seconds. Unlike --silence-detect (which keys specifically on WorkerHeartbeat), this keys on any event append, so it catches the external-modal case — a Claude Code AskUserQuestion modal that emits no cosmon-visible state at all. It never tags, never kills, never touches transport: it is a pure read over molecules + events.jsonl, so it works even when cosmon-runtime is dead (CV-5 — the watchdog's liveness must be independent of the thing it watches). Alerts are tiered by irreversibility (CV-6): only an irreversible-class block (signature / push / publish) fires cs notify; operational stalls are report-only, to keep the one load-bearing alert out of an alert-fatigue flood

  • --event-age-after <EVENT_AGE_AFTER> — Threshold in seconds for --event-age (default: 900 = 15 min). The panel's suggested floor — long enough that a worker genuinely thinking between event appends is not mistaken for a stall

    Default value: 900

  • --abandon — Abandon sweep (patrouille-abandon): fold traces an instance has ALREADY emitted (audit envelopes, phone-home reports, PKCE auth sessions, instance ledgers) into named abandonment motifs per tenant — nucleate-sans-tackle, pkce-start-sans-completed, incarne-sans-login, rafale-4xx-puis-silence, decroissance-de-signalement (the Dave rule, gravity HIGH: losing the client who talks loses the only human sensor). Read-only: reports, never remediates

  • --abandon-root <ABANDON_ROOT> — Instance root for --abandon — the instance's .cosmon/ directory (containing whispers/inbox/ and state/). Defaults to the parent of the resolved state dir

  • --abandon-quiet-hours <ABANDON_QUIET_HOURS> — Quiet window in hours for the "puis silence" motifs of --abandon (default 24 — one daily patrol cadence)

    Default value: 24

  • --heal — Heal (the Deacon, ADR-137 §11 P3): run one detect → guard → remediate pass over the molecule-health anomaly catalog, mutating only the safe, reversible classes, each behind the §5 no-interference guard: A1 unsent-paste (delegate to the transport submit-retry), A4/A8 idle-after-complete / completed-unharvested (cs done harvest from the orchestrator — never a worker self-done), A5 idle-no-progress (nudge), A6 overloaded (backoff hold). The collapse / integrity classes (A3/A7/A9) are reported but never auto-collapsed here (that is P4). Detection is keyed off control-plane state only — never a pane glyph (the be1e SEV-1 lesson). Pair with --dry-run for a zero-mutation preview. Use cs health for the read-only, federation-wide catalog

  • --dry-run — Dry-run: with --heal, compute and print the health report + the guarded actions the Deacon would take, but mutate nothing. The safe default for earning operator trust before enabling a scheduled heal pass

  • --dialogue-scan — Dialogue-scan: capture each running worker's pane and classify any blocking dialogue sitting in it (tool-permission prompt vs. the Claude Code spend-/usage-limit dialog). The motivating incident: ten synthetic workers blocked on the spend-limit dialog with no human to press Enter. Per the be1e discipline (ADR-137 §2) pane text is read only to surface a finding — a money_stake class always pages the operator via cs notify and is never auto-confirmed; an unknown block alerts too; a safe permission prompt is auto-confirmed only when --auto-confirm-safe is also passed. Report-only by default (no keystroke) so it is safe to schedule

  • --auto-confirm-safe — With --dialogue-scan, opt in to firing the default-accept keystroke (Enter) on safe permission-class prompts only. Money stakes and unrecognised blocks are still never auto-confirmed — that refusal is encoded in the classifier, not in this flag. Off by default: the safe posture is to surface every block to a human

  • --dialogue-lines <DIALOGUE_LINES> — Number of pane lines --dialogue-scan captures per worker (default 40). The live prompt sits at the bottom of the pane, so a small tail is enough; raise it for TUIs that render tall dialogs

    Default value: 40

  • --dialogue-blocked-after <DIALOGUE_BLOCKED_AFTER> — Blocked-duration threshold in seconds for --dialogue-scan (default 900 = 15 min). A molecule whose progress has been frozen longer than this and is still sitting on a blocking dialogue escalates to a canary RED operator page — the heartbeat half of the primitive: "blocked > X min despite detection ⇒ RED"

    Default value: 900

cs fleet

Fleet template discovery and initialization

Usage: cs fleet <COMMAND>

EXAMPLES: cs fleet list-templates # installed templates cs fleet init research # scaffold a .fleet.toml from a template cs fleet resolve # flatten a composable fleet.toml (ADR-038) cs fleet resolve --json # NDJSON for scripting

SEE ALSO: cs deploy (instantiate a fleet from the .fleet.toml).

Subcommands:
  • list-templates — List available fleet templates
  • init — Initialize a fleet from a template (copies to .cosmon/fleet.toml)
  • resolve — Resolve a fleet.toml (follow [[fleet.include]]) and print the flattened fleet

cs fleet list-templates

List available fleet templates

Usage: cs fleet list-templates

cs fleet init

Initialize a fleet from a template (copies to .cosmon/fleet.toml)

Usage: cs fleet init [OPTIONS] <TEMPLATE>

Arguments:
  • <TEMPLATE> — Template name (from cs fleet list-templates)
Options:
  • -o, --output <PATH> — Output path (default: .cosmon/fleet.toml)

cs fleet resolve

Resolve a fleet.toml (follow [[fleet.include]]) and print the flattened fleet

Usage: cs fleet resolve [PATH]

Arguments:
  • <PATH> — Path to the master fleet.toml (default: .cosmon/fleet.toml via walk-up)

cs wait

Wait — block until a molecule reaches a terminal (or requested) status

Usage: cs wait [OPTIONS] <MOLECULE>

EXAMPLES: cs wait # block until terminal cs wait --timeout 600 # 10-minute cap cs wait --status Completed # custom target set cs wait & # background wait, notified on exit

This is kubectl-wait, not kubectl-watch. One molecule, bounded poll, exits on target. Never poll cs observe in a shell loop.

SEE ALSO: cs observe (snapshot), cs peek (live fleet view).

Arguments:
  • <MOLECULE> — Molecule ID to wait on. Must be an exact ID — we never want a prefix to match the wrong molecule under a long-running wait
Options:
  • --for <FOR> — Statuses to wait for, comma-separated. Defaults to the terminal set so cs tackle M && cs wait M && cs done M just works

    Default value: completed,collapsed

  • --timeout <TIMEOUT> — Maximum seconds to wait before giving up

    Default value: 600

  • --poll-interval <POLL_INTERVAL> — Seconds between polls. Clamped internally to the remaining budget, so setting this larger than --timeout still terminates on time

    Default value: 5

  • --quiet — Suppress per-poll progress lines — only emit the final result. Implied when --json is set

Execution commands

These commands use physics-inspired names (nucleate, evolve, decay, spore, …). New to the vocabulary? See The physics vocabulary.

cs tackle

Tackle a molecule — spawn ONE worker on this node (always leaf; for DAG walks use cs run)

Usage: cs tackle [OPTIONS] <MOLECULE>

EXAMPLES: cs tackle task-example-0001 # worktree + tmux + Claude (one node) cs tackle --dry-run # print the bootstrap prompt cs tackle --no-worktree # reuse current directory cs tackle --base release/2.0 # cut from — and merge back to — that trunk

--base makes the integration branch a property of the MOLECULE: the worker's branch is cut from it, the name is persisted in the molecule's state, and cs done merges back into it with no COSMON_BASE_BRANCH in the environment. Without --base, the branch is cut from the ambient HEAD and cs done falls back to COSMON_BASE_BRANCH → origin/HEAD → main, exactly as before.

cs tackle is ALWAYS leaf — it spawns one worker on the named node and never walks the DAG. To walk a DAG of N≥1 nodes (1 = leaf, N = full orchestration), use cs run instead. Human only. Workers never self-tackle. Pairs with cs done.

The historical --leaf and --force-runtime flags are deprecated no-ops since the verb-unification: the routing decision is now the verb itself, not a flag on a polymorphic command.

SEE ALSO: cs run (DAG walk), cs done (teardown), cs wait (block on completion).

Arguments:
  • <MOLECULE> — Molecule ID, prefix, or fuzzy name (e.g. "ADR-15", "idea-2026")
Options:
  • --fleet <FLEET> — Fleet to use (default: molecule's fleet)

  • --workdir <WORKDIR> — Working directory override (default: .worktrees/{mol-id})

  • --base <BRANCH> — Integration base branch for this molecule (default: the ambient HEAD of the main checkout).

    The worker's feat/{mol-id} branch is cut from this ref instead of whatever the main checkout has checked out, and the branch name is persisted on the molecule so cs done merges back into it without any COSMON_BASE_BRANCH in the environment. Makes the base a property of the molecule rather than of the session that launched it.

  • --no-worktree — Skip git worktree creation (use current directory)

  • --dry-run — Skip tmux session — print the prompt to stdout instead

  • --permission-mode <PERMISSION_MODE> — Permission mode for Claude (default: based on molecule kind)

  • --force — Reclaim the molecule's tmux session and respawn (instead of reporting the running one). Also thaws a frozen molecule: the respawned worker is live, so the molecule reads running again. A session left behind by a dead worker is reclaimed without this flag — there is nothing there to protect

  • --name <NAME> — Override the tmux session name. ASCII alphanumerics and hyphens are kept; everything else is replaced with -. Max 50 chars. Default: {slug}-{shortid} derived from the molecule topic + id

  • --bypass-seal — Override the ADR-085 stress-test seal at dispatch (Layer 1).

    Without this flag, cs tackle of a --class stress-test molecule refuses dispatch unless prior.md + prior.b3 exist on disk and a matching cs witness attest event has been emitted. With it, the runtime writes a typed BypassReceipt to <molecule_dir>/bypass-receipt.json and emits EventV2::SealBypassed, then proceeds with dispatch. Requires --bypass-reason "<…>" — silent overrides are forbidden by ADR-085 §3.5.

  • --bypass-reason <TEXT> — One-line reason recorded in the BypassReceipt when --bypass-seal is used.

    Free-text but non-empty; the runtime refuses a blank reason because the entire point of the receipt is to surface accountability for the override (ADR-085 §3.5).

  • --adapter <NAME> — Worker-Spawn Port Adapter to dispatch (ADR-097 / C6; ADR-108 Q5a chain).

    Resolution order (highest priority first): this flag → formula-step adapter = "<name>" pin → $COSMON_DEFAULT_ADAPTER env var → per-galaxy .cosmon/config.toml::[adapters.default] → global ~/.config/cosmon/config.toml::[adapters.default] → built-in "local" (the Ollama-backed in-process loop). Values are looked up against the registered Adapter table (claude, aider, openai, anthropic, llama-cpp, local, …). An unknown name aborts the dispatch with a typed AdapterNotFound carrying the list of available names — no silent fallback. To restore the legacy Claude-Code default pass --adapter claude, export COSMON_DEFAULT_ADAPTER=claude, or set [adapters.default] = "claude" in either config file.

    Capability gate (noogram/cosmon #4)

    A formula may declare what its steps need of a worker (requires_capabilities = ["shell", "vcs"]). A local adapter (local / ollama / llama-cpp / llama) is an in-process chat loop with no shell, no VCS and no cs command, so such a pairing is refused with exit code 17 — before any worktree, pane or model preflight, and under --dry-run too. The molecule stays pending and re-tacklable. Re-run with a coding-agent adapter, or set COSMON_SKIP_CAPABILITY_GATE=1 to dispatch anyway. Formulas that declare nothing are unaffected on every adapter.

    Every invocation (with or without the flag) emits an EventV2::AdapterSelected envelope so the cat-test (jq -c 'select(.type == "adapter_selected")') can answer "which Adapter ran for this molecule?" without parsing shell history.

    Composition with cs run --resident (issue-#21, reconciled)

    The resident loop (cs run --resident) is not a second resolver; it is a composer that delegates to this one chain. Its scheduler owns only the two rung-1 flag intents — a per-molecule pin and the opt-in cs run --adapter <name> run directive — and stamps them onto the shelled cs tackle. When neither is present it stamps no --adapter flag, so this full six-level chain runs unchanged in the child: formula step → $COSMON_DEFAULT_ADAPTER → per-galaxy config → global config → the local floor. The floor is therefore reached under --resident iff it is reached under a bare cs tackle, and the operator's env and committed config are honoured identically on both paths — the #21 fix removed the resident-only --adapter local stamp that used to mask them. See cs run --help (--adapter) and cosmon_runtime::resident.

  • --model <MODEL_ID> — Per-molecule model pin — the model sibling of --adapter (see ADR-097).

    Resolution order (highest priority first): this flag → formula-step model = "<id>" pin → $COSMON_DEFAULT_MODEL (else the legacy $ANTHROPIC_MODEL) env var → per-galaxy .cosmon/config.toml::[adapters.<name>].default_model → global ~/.config/cosmon/config.toml::[adapters.<name>].default_modelfloor None (cosmon pins no model; the adapter's own default applies — byte-identical to today's no-pin behaviour).

    Strong is never inherited. Every dispatch resolves the model fresh; a strong (frontier) model is reachable only from this flag or a formula-step pin — a positive per-molecule act — never from a config/env default that could silently make an entire fleet expensive (the /model-hack leak this axis exists to close).

    The id is carried opaquely: cosmon does not check that it is legal for the resolved adapter. A recognisable cross-family pair produces a non-blocking advisory, but the Adapter remains the authority because custom endpoints can legitimately serve another family's model. Config default_model rows are scoped per adapter because a model id only has meaning inside its adapter.

  • --role-hint <ROLE> — Forensic-only role-of-origin hint propagated through to EventV2::AdapterSelected (ADR-097 / C6).

    Cosmon does not interpret this value — it is the academy-shim's channel for preserving the driver's vocabulary (a --role researcher invocation on the driver side becomes role_hint: "researcher" on the cosmon event), so the role of origin survives the seam between driver (roles) and cosmon (adapters). Optional; absent for direct operator invocations.

  • --fallback-from-local <CAUSE> — Loud opt-in fallback from the local default to a remote oracle after a decidable local hard-failure (Q5b).

    Pass a LocalFailureCause token — crash, oom, timeout, connection-refused, or any bespoke string (recorded verbatim as Other). This flag is the ONLY path from a local hard-failure to a remote oracle: there is no automatic in-loop fallback. It is meaningful only alongside a remote --adapter (claude / openai / anthropic / aider) — combining it with a local adapter is a contradiction and aborts the dispatch.

    When set, cs tackle mints an EventV2::LocalFallback line in the same atom as the RemoteEgressOptIn egress grant, so a remote call carrying a fallback cause can never reach the wire without a matching loud audit record — silent fallback is impossible by construction. Soft "the output looked bad" judgement is NOT a valid cause: that is undecidable (Rice) and belongs to acceptance tests, not this routing flag.

  • --by <ACTOR> — Actor class recording who dispatched this molecule — the anti-preemption lease.

    Accepts human (the default when the flag is absent — a direct operator invocation) or runtime:<pid> (the resident runtime cs run passes its own process id). The value is stamped onto the molecule's tackled_by field when the molecule flips to Running, so the walker can enforce "manual always wins": a human-claimed molecule is never raffled by the runtime, even if it briefly returns to Pending on a revision. This is cs tackle's only role in the lease — recording the claim; honouring it is the walker's job.

    Default value: human

cs done

Done — terminal teardown for a molecule (merge + cleanup, human-callable)

Usage: cs done [OPTIONS] <MOLECULE>

EXAMPLES: cs done task-example-0001 # merge + teardown cs done --strategy ff-only # linear history; attribution off cs done --force # skip completion check cs done --if-completed # silent no-op if not Completed

Not-the-worker. Legitimate callers: humans, external schedulers (cron/launchd), and transport watchdogs (tmux pane-died hooks via cs done --if-completed). Required to close the nucleate → tackle → wait → done cycle: without it the branch never merges and the tmux worktree persists.

--if-completed is the hook-friendly gate: exits success without touching state when the molecule is not Completed or already merged; behaves identically to plain cs done otherwise. Supersedes the former cs harvest verb (ADR-052 §D3).

BASE BRANCH — the branch this merge lands on is resolved once per run, in this order (first that answers wins):

  1. the molecule's own base, stamped by cs tackle --base <branch>
  2. the COSMON_BASE_BRANCH environment variable
  3. git symbolic-ref refs/remotes/origin/HEAD
  4. the literal main

Rung 1 is why a cs done fired from a tmux hook — whose environment froze when the tmux server started and never saw a later export — still merges onto the right trunk. Molecules tackled without --base resolve through rungs 2-4 exactly as they always did. cs done still refuses (NotOnBase) when HEAD is not the resolved base: git merges into the current HEAD, never into a branch by name.

SEE ALSO: cs complete (state transition only), cs tackle (counterpart).

Arguments:
  • <MOLECULE> — Molecule ID to tear down
Options:
  • --force — Proceed even if the molecule is not in a terminal state

  • --if-completed — Silent no-op when the molecule is not Completed or already merged.

    Hook-friendly gate for callers that do not know whether the molecule is ready for teardown — tmux pane-died hooks, patrol sweeps, and the legacy cs harvest alias. Exits success without touching state when the precondition is not met; otherwise, behaves exactly like cs done. Supersedes the stand-alone cs harvest verb (ADR-052).

  • --dry-run — Compute and display the teardown plan without executing any steps.

    Reports what cs done would do: worktree state (clean/dirty), whether a merge is needed, whether the tmux session is alive, whether a fleet worker is registered, and whether the branch exists.

  • --no-merge — Skip merging the worker's branch into the base branch

  • --no-worktree-remove — Skip removing the git worktree

  • --no-branch-delete — Skip deleting the worker's branch after merge

  • --no-kill — Skip killing the tmux session

  • --strategy <STRATEGY> — Merge strategy for the worker's branch.

    merge (default) creates a merge commit (git merge --no-ff) so parallel workers can land independently even when main has moved. ff-only preserves a strictly linear history and refuses anything that is not a fast-forward; it is refused when native attribution is configured because a fast-forward creates no trailer carrier.

    Default value: merge

    Possible values:

    • merge: Non-fast-forward merge (git merge --no-ff --no-edit)
    • ff-only: Fast-forward-only merge (git merge --ff-only)
  • --no-auto-propel — Disable auto-propel escalation on merge conflict.

    By default, when a merge conflict is detected, cs done escalates by sending a resume signal to the worker with rebase instructions, then retries the merge after a backoff delay. This flag restores the old behavior: abort immediately and print a manual-resolution message.

    Mechanical-first escalation: see docs/architectural-invariants.md

  • --propel-message <PROPEL_MESSAGE> — Custom message sent to the worker during auto-propel escalation.

    The default instructs the worker to rebase onto the base branch, resolve conflicts, run tests, and NOT call cs done itself.

  • --max-retries <MAX_RETRIES> — Maximum number of auto-propel escalation retries before giving up

    Default value: 3

  • --skip-pre-done-hook — Skip the blocking [hooks] pre_done gate for this invocation.

    The pre_done hook (when configured) runs before the merge and aborts teardown on a non-zero exit — the galaxy-owned Definition-of- Done gate. This flag is the human operator's kill-switch: it bypasses the gate entirely for a deliverable the operator knows is good but the script cannot see (e.g. evidence living outside the repo). Equivalent to setting the COSMON_SKIP_PRE_DONE_HOOK environment variable. No effect when no pre_done hook is configured.

  • --deploy-off-trunk — Run the [hooks] post_merge deploy hook even when this harvest merges into a parked work branch rather than the reference trunk.

    By default the post_merge hook is bounded to the trunk: it fires only when the resolved integration base is the galaxy's reference trunk (origin/HEAD, or main as a last resort). The hook deploys — the canonical just install refreshes the on-disk cs binary — so running it after a merge into an older parked branch would silently rejuvenate the operator's tool, dropping whatever the parked branch predates (task-20260725-b64f). When the merge targets a parked branch the hook is skipped with a warning naming the reason.

    This flag is the operator's explicit escape hatch for the rare-but- legitimate case of deploying from a parked branch on purpose. No effect when no post_merge hook is configured or when the merge already targets the trunk.

cs sync

Sync — base-sync the current worktree from main, stamping a Base-Sync trailer

Usage: cs sync [OPTIONS]

Options:
  • --base <BASE> — Base branch to sync from (defaults to main)

    Default value: main

  • --dry-run — Report what would happen without performing the merge

cs harvest

Harvest — close a completed-but-unmerged molecule by invoking cs done

Usage: cs harvest [OPTIONS] --molecule <MOLECULE>

EXAMPLES: cs harvest --molecule task-example-0001 # DEPRECATED — see below

DEPRECATED (ADR-052 §D3): use cs done --if-completed <mol> instead. The canonical path carries byte-identical semantics: silent no-op when the molecule is not Completed or already merged; full teardown otherwise. This alias will be removed after one release cycle.

SEE ALSO: cs done --if-completed (canonical), cs patrol --harvest (belt-and-suspenders sweep).

Options:
  • --molecule <MOLECULE> — Molecule to harvest. Required — cs harvest operates on one molecule per invocation. Use cs patrol --harvest for the sweep variant

  • --dry-run — Print what cs harvest would do without exec'ing cs done

  • --from-pane-died — Flag the invocation as caused by a tmux pane-died hook.

    ADR-052 child #4 (I4 + I8 + I10): the probe must emit its observation before acting on it. When set, cs harvest first appends a EventV2::WorkerExited event to events.jsonl (reason = pane_died) and then runs the normal harvest logic. Absent this flag, no WorkerExited is emitted — periodic cs patrol --harvest sweeps observe via witness, not via the kernel-level pane-died channel.

  • --exit-code <EXIT_CODE> — Exit code reported by tmux #{pane_dead_status} when the pane died.

    Only meaningful together with --from-pane-died. Accepts any signed 32-bit integer so the wait-status (which may encode signals) survives round-trip. Strings that fail to parse are treated as "no information" (None in the emitted event).

cs run

Run — walk a molecule DAG of N≥1 nodes via the resident runtime (ADR-016 Layer B)

Usage: cs run [OPTIONS] [MOLECULE]

EXAMPLES: tmux new -d -s runtime cs run --poll-interval 5 cs run # also valid: 1-node DAG = single dispatch cs run --force-runtime # bypass the ADR-048 backlog-sanity guard

Resident runtime — walks a DAG of N≥1 nodes. Calls cs tackle for each ready node and cs done automatically as predecessors complete. The single-node case (1 = leaf) is the same code path as the N-node case; cs tackle <id> is the no-walk equivalent if the operator wants exactly one worker without any runtime ceremony.

NEVER run cs run in the foreground; always detach via tmux so the pilot stays responsive.

SEE ALSO: cs tackle (single node, no runtime), docs/handbook.md#one-primitive.

Arguments:
  • <MOLECULE> — Root molecule ID (supports prefix matching like other commands).

    Required for the legacy DAG-policy mode. With --resident the loop walks the whole ensemble, so this argument is optional (any value, including _, is accepted and ignored).

    Default value: ``

Options:
  • --policy <POLICY> — Scheduling policy to use

    Default value: dag

    Possible values: dag, noop

  • --timeout <TIMEOUT> — Maximum seconds before the runtime exits. 0 means no timeout (default)

    Default value: 0

  • --poll-interval <POLL_INTERVAL> — Seconds between runtime ticks. Lower values are more responsive but increase store I/O

    Default value: 1

  • --no-teardown — Skip automatic teardown of completed molecules after the run

  • --sweep-every <SWEEP_EVERY> — ADR-038 Limit 1: re-walk the store every N ticks to absorb descendants nucleated dynamically by workers (mission-controller decompose, deep-think step 4, etc.) that are not reachable from the runtime's root via pre-existing typed links. Zero disables the sweep (default) — the scope is frozen at compile-plan time, which is the pre-2026-04-14 behavior

    Default value: 0

  • --force-runtime — Override the ADR-048 backlog-sanity guard on runtime bootstrap.

    When a dirty backlog would normally refuse runtime bootstrap (sediment ≥ threshold, default 5), --force-runtime bypasses the refusal and writes a runtime_guard_override audit event to events.jsonl so the override leaves a durable trail.

  • --max-actions <MAX_ACTIONS> — B3 — decreasing action budget (moussage bounds). Each applied runtime action costs one unit; when the budget floor is reached the loop exits with the NAMED reason budget_exhausted (exit code 90) instead of dispatching further. This is the well-founded measure that makes an unbounded moussage total. 0 = unbounded (default, operator-local behaviour unchanged). Server-side callers (the tenant drain path) pass the binding-derived value — the bound is never client-writable

    Default value: 0

  • --max-depth <MAX_DEPTH> — B1 — maximum DAG depth (longest dependency chain, in molecules). Checked at compile-plan time, BEFORE the loop starts: a plan deeper than the bound is refused with the NAMED error max_depth_exceeded (exit code 92), never started. 0 = unbounded (default)

    Default value: 0

  • --max-molecules <MAX_MOLECULES> — B2 — maximum molecules tolerated in the fleet while draining. Checked at compile-plan time AND on every loop tick (so mid-run nucleations count); exceeding it exits with the NAMED reason molecule_quota_exceeded (exit code 91). 0 = unbounded (default)

    Default value: 0

  • --residentADR-095 — switch to the fully event-sourced Resident Runtime loop.

    When set, the legacy in-process DagPolicy is bypassed and the new [cosmon_runtime::RuntimeLoop] takes over. The loop:

    • Shells out to cs ensemble --json, cs tackle, cs done exactly as a human operator would (RR-1). - Wakes on FS changes under .cosmon/state/ (notify backend) plus a --poll-interval heartbeat. - Writes an NDJSON trace line per loop iteration to .cosmon/state/runtime-trace.jsonl (RR-5). - Exits cleanly on SIGTERM / Ctrl-C. - Drains when the ensemble has no pending and no running.

    Does not require <molecule> — the loop walks the whole ensemble. The positional argument is accepted but ignored in resident mode; pass _ if you have nothing to name.

  • --affinityADR-145 — model-affinity ordering of the ready frontier.

    On a single-resident-model local oracle (ollama-g5: 48 GB ≈ one 120 B model in VRAM), an alternating frontier reloads the model (~40 GB off disk) on every dispatch. With --affinity the runtime clusters same-model molecules contiguously and drains the resident model first, so a same-model batch pays the load cost once. The per-molecule model is PRE-RESOLVED from each molecule's formula-step model = pin (the ADR-142 Incarnation model), since a pending frontier molecule has no ModelSelected event yet.

    Off by default: cloud dispatch (many models, no resident constraint) keeps pure critical-path order. The reorder is a permutation — the DAG semantics and the set of dispatched molecules are unchanged; only the order within a ready batch differs. Legacy DAG-policy mode only (not --resident).

  • --resident-model <RESIDENT_MODEL> — Model already warm in the oracle's VRAM at runtime start, so the affinity reorder drains its bucket first with no reload. Only read when --affinity is set; a cold start (unset) simply pays one extra load for the first bucket

  • --adapter <NAME>Opt-in run-wide adapter directive (resident mode only).

    The resident scheduler owns exactly one run-wide flag intent — this flag — and nothing below it (COSMON-DEV #21). Passing --adapter <name> is the operator's explicit, conscious choice to spend on that adapter for this run: it stamps every pin-less molecule dispatched — both static frontier nodes and children a worker nucleates dynamically mid-run (the converge/committee loop). A per-molecule pin still wins over it.

    When this flag is absent, the scheduler stamps nothing: the shelled cs tackle inherits the environment and runs the full canonical resolution chain itself (formula step → $COSMON_DEFAULT_ADAPTER → per-galaxy config → global config → the built-in local floor). So the operator's live env, session hammer, and committed config are all honoured under --resident exactly as they are under a bare cs tackle — the resident loop no longer masks them with a rung-1 --adapter local floor (the #21 defect). The local floor is still reached iff nothing higher speaks, so an inadvertent paid dispatch remains impossible: a paid adapter is chosen only by a conscious flag, formula step, env export, or committed config. See docs/adr (ADR-095) and the cs tackle adapter-chain docs for the single canonical resolution order.

cs spore

Spore germinates a whole polymer from a shareable spore.toml template (validate / run / export, ADR-140)

Usage: cs spore <COMMAND>

EXAMPLES: cs spore install github:noogram/cosmon/spores/cosmon-dev # fetch + place cs spore validate ./spore.toml --var subject="octopus cognition" cs spore run ./bundle/ --var subject="..." --var axes=a,b,c cs spore run ./spore.toml --allow-unchecked-seal # sealed, no TLC cs spore export ./spore.toml --out dist/ # bundle hash + ASTRA cs spore validate ./spore.toml --json # NDJSON expansion

VERBS: install fetch a shareable bundle and place it in this project, copying its recipes into .cosmon/formulas/ so their pins reach dispatch. validate parse + expand as a dry run; prints the ordered nucleate call list, germinates nothing. run parse + expand + seal gate, then germinate the polymer into the live state store. --json emits one NDJSON line per molecule. export content-addressed bundle hash + ASTRA descriptive layer (D6).

SEAL (ADR-140 D4): a sealed spore fails closed unless --allow-unchecked-seal is passed; the status line never claims 'verified' when TLC did not run.

SEE ALSO: cs nucleate (one molecule), ADR-140, docs/design/spore-impl-dag-manifest.md.

Subcommands:
  • validate — Parse + expand a spore as a dry run; print the ordered nucleate call list without germinating anything
  • run — Germinate the polymer: parse + expand + seal gate, then replay the call list against the live state store
  • export — Emit a content-addressed bundle id and an ASTRA descriptive layer (ADR-140 D6) for sharing the spore
  • install — Fetch a shareable bundle and place it into this project, installing its recipes into .cosmon/formulas/ so their per-step pins reach dispatch

cs spore validate

Parse + expand a spore as a dry run; print the ordered nucleate call list without germinating anything

Usage: cs spore validate [OPTIONS] <REF>

EXAMPLES: cs spore validate ./spore.toml --var subject="octopus cognition" cs spore validate ./bundle/ --var axes=a,b,c # directory ref cs spore validate ./spore.toml --json # NDJSON expansion

Dry run only: parse (N2) + expand (N3), print the ordered 'cs nucleate ... --blocked-by ...' call list, germinate nothing. The seal is reported but never gated here; use it to inspect what 'cs spore run' would create. Each --var is coerced into its declared ParamSchema type before expansion; a list param splits on commas.

SEE ALSO: cs spore run, cs spore export, ADR-140 D3.

Arguments:
  • <REF> — Path to a spore.toml manifest (or a directory containing one)
Options:
  • --var <KEY=VALUE> — Bind a parameter (repeatable: --var key=value). Values are coerced into the declared ParamSchema type before expansion

cs spore run

Germinate the polymer: parse + expand + seal gate, then replay the call list against the live state store

Usage: cs spore run [OPTIONS] <REF>

EXAMPLES: cs spore run ./spore.toml --var subject="..." --var axes=a,b,c cs spore run ./bundle/ --fleet default # directory ref cs spore run ./spore.toml --allow-unchecked-seal # sealed, no TLC cs spore run ./spore.toml --json # one NDJSON line/molecule

Germinates the whole polymer: parse + expand + seal gate, then replays the call list against the live state store via the canonical 'cs nucleate' path. Every germinated molecule is tagged temp:warm and wired to its blocked-by predecessors. The seal status note goes to stderr so --json stdout stays clean NDJSON.

SEAL (ADR-140 D4): a spore with no [spore.seal] germinates freely. A sealed spore fails closed unless --allow-unchecked-seal is passed, in which case the status line reads 'seal: present, NOT verified' and never 'verified'.

SEE ALSO: cs spore validate (dry run), cs run (DAG of existing molecules).

Arguments:
  • <REF> — Path to a spore.toml manifest (or a directory containing one)
Options:
  • --var <KEY=VALUE> — Bind a parameter (repeatable: --var key=value)

  • --allow-unchecked-seal — Germinate a sealed spore even though its .tla proof was not verified this run (TLC unavailable). The status line stays honest: seal: present, NOT verified (ADR-140 D4). Without this flag a sealed spore fails closed

  • --fleet <FLEET> — Fleet to germinate the polymer into

    Default value: default

  • --store-dir <DIR> — State store root (default: walk-up .cosmon)

cs spore export

Emit a content-addressed bundle id and an ASTRA descriptive layer (ADR-140 D6) for sharing the spore

Usage: cs spore export [OPTIONS] <REF>

EXAMPLES: cs spore export ./spore.toml # bundle hash to stdout cs spore export ./spore.toml --out dist/ # ASTRA into dist/ cs spore export ./bundle/ --json # machine-readable

Emits a content-addressed bundle id over the manifest and every recipe and seal file it references (BLAKE3, sorted paths), plus an ASTRA-compatible RO-Crate descriptive layer (ADR-140 D6) when [spore.astra].emit is true. The seal verdict is attached honestly: marked present/absent and never claimed verified. The bundle hash is stable: the same bundle content always yields the same id (content-addressing is the registry, ADR-039).

SEE ALSO: cs spore run, ADR-140 D6, ADR-039.

Arguments:
  • <REF> — Path to a spore.toml manifest (or a directory containing one)
Options:
  • --out <DIR> — Output directory for the ASTRA descriptive layer. Defaults to the manifest directory. The crate is always written here as ro-crate-metadata.json unless [spore.astra].output names a different (manifest-relative) path

cs spore install

Fetch a shareable bundle and place it into this project, installing its recipes into .cosmon/formulas/ so their per-step pins reach dispatch

Usage: cs spore install [OPTIONS] <SOURCE>

EXAMPLES: cs spore install github:noogram/cosmon/spores/cosmon-dev cs spore install https://github.com/noogram/cosmon/tree/main/spores/cosmon-dev cs spore install ../shared/bundle --dest spores/shared # local copy cs spore install github:o/r@v1 --expect-hash blake3:... # verified fetch cs spore install github:o/r --dry-run --json # plan only

Fetches the bundle (git remote or local path), places it under /spores// unless --dest says otherwise, and copies each [spore.formulas.*] recipe into .cosmon/formulas/ under the name the recipe DECLARES — which is the name 'cs tackle' resolves at dispatch. That second half is why the verb is called install and not add: without it a bundle germinates fine and then runs with every per-step adapter/model pin silently inert (task-20260725-eb3b).

SOURCE: a local path, 'github:owner/repo[/subdir][@ref]', a GitHub tree/blob URL, or any other git remote (use --git-ref / --subdir to pin one).

REFUSALS, all before anything is written: a bundle whose hash does not match --expect-hash; a bundle missing a file its manifest declares; a symlink inside the fetched tree; a non-empty destination (without --force); and a registry that already holds a DIFFERENT recipe of the same name (without --force), since overwriting changes what already-germinated molecules run. An identical recipe is a no-op, so re-installing is idempotent.

SEE ALSO: cs spore validate (inspect what was installed), cs spore export (the id --expect-hash checks), docs/cs-spore.md.

Arguments:
  • <SOURCE> — Where the bundle comes from: a local path, github:owner/repo[/dir][@ref], a GitHub tree/blob URL, or any other git remote
Options:
  • --dest <DIR> — Where to place the bundle. Defaults to <project>/spores/<spore-name>/
  • --git-ref <REF> — Branch, tag, or commit to fetch. Overrides a ref encoded in the source
  • --subdir <PATH> — Path to the bundle inside the checkout. Overrides one encoded in the source; the way to install from a subdirectory of a non-GitHub remote
  • --expect-hash <BLAKE3> — Refuse unless the fetched bundle hashes to exactly this id (as printed by cs spore export). Checked before anything is written
  • --no-formulas — Place the bundle but do not copy its recipes into .cosmon/formulas/. The bundle then germinates without its per-step adapter/model pins
  • --force — Overwrite a non-empty destination and replace conflicting recipes already in the registry. The copy is a merge: a file the new bundle carries replaces the one there, and a file it does not carry is left alone — nothing is deleted on your behalf
  • --dry-run — Report what would be installed and write nothing
  • --formulas-dir <DIR> — Formula registry to install recipes into (default: walk-up .cosmon/formulas)

Project commands

These commands use physics-inspired names (nucleate, evolve, decay, spore, …). New to the vocabulary? See The physics vocabulary.

cs init

Bootstrap a project-local .cosmon/ directory (creates the target dir if missing)

Usage: cs init [OPTIONS] [PATH]

EXAMPLES: cs init # bootstrap .cosmon/ in the current directory cs init ./new-galaxy # create ./new-galaxy/, then populate .cosmon/ cs init --soft # generate only CLAUDE.md (no .cosmon/) cs init --soft --template rust # Rust-specific conventions cs init --soft --template data # data/research conventions cs init --upgrade # backfill missing canonical formulas

Creates .cosmon/{config.toml, state/, formulas/, …}. The target path may not exist — cs init runs mkdir -p before populating. Running twice on the same path is a strict no-op.

Does NOT run git init (that is git's job) and does NOT write CLAUDE.md by default — pass --soft to generate an agent template. Refuses to nest: if an ancestor already carries .cosmon/, exits non-zero — no --force.

On a terminal, the first cs init of your life also asks the one-time developer-share question (deny-by-default, cs opt-in-share --status to review). Never asked under --json, never asked when stdout is captured.

Symmetric undo: rm -rf <path>/.cosmon/.

Arguments:
  • <PATH> — Directory to initialize (default: current directory).

    Need not exist. If it does not, cs init creates it with mkdir -p. If it exists and already contains .cosmon/, the command is a no-op (strict idempotency).

    Default value: .

Options:
  • --upgrade — Upgrade an existing .cosmon/ project by backfilling missing canonical formulas AND project_id without overwriting existing files

  • --soft — Generate only a minimal CLAUDE.md (≤50 lines) without creating .cosmon/.

    Constitutional projection: conventions propagated via a single file that any agent can read independently. No orchestration infrastructure, no runtime state, no external dependency.

  • --template <TEMPLATE> — Project-type template for --soft (default: generic)

    Default value: generic

    Possible values:

    • generic: Generic project — language-agnostic conventions
    • rust: Rust project — cargo-based conventions
    • data: Data/research project — notebook + pipeline conventions
  • -y, --yes — Assume "yes" to any confirmation prompt (non-interactive mode).

    cs init is already fully non-interactive today, so this flag is accepted and ignored. It is reserved so that README quickstarts (cs init --yes) stay paste-testable if prompts are ever added — per the knuth paste-testability invariant and tolnay's semver rule that reserving a flag now makes adding prompts later a non-breaking elaboration.

  • --tenant <NOYAU> — Tenant (noyau) this galaxy belongs to. Records the ADR-063 layer-3 label in config.toml and provisions the .cosmon/state/nucleons/ directory where ADR-080 OIDC identity mappings (oidc-identity.toml) and future YubiKey keyring entries land.

    Convention: one tenant per galaxy below the configured cluster root. This flag records the label but does not enforce a path. Downstream tools read the noyau to verify the galaxy belongs to its tenant.

cs trust

Trust — grant this repository permission to run its own formulas/hooks (the direnv allow of cosmon; refuses repo-supplied shell until granted)

Usage: cs trust [OPTIONS]

Options:
  • --status — Report the current trust status without changing anything
  • --revoke — Revoke this repository's trust grant
  • --dir <DIR> — Operate on this directory instead of the current working directory

cs config

Config — inspect .cosmon/config.toml (show adapters, adapters)

Usage: cs config <COMMAND>

Subcommands:
  • show — Show resolved configuration for a topic (currently: adapters)
  • adapters — List every adapter name the dispatch registry would accept (union of compile-time built-ins and [adapters.<name>] rows from .cosmon/config.toml)

cs config show

Show resolved configuration for a topic (currently: adapters)

Usage: cs config show <COMMAND>

Subcommands:
  • adapters — Print the effective [adapters.*] resolution for Direct-API adapters (openai, anthropic)

cs config show adapters

Print the effective [adapters.*] resolution for Direct-API adapters (openai, anthropic)

Usage: cs config show adapters

cs config adapters

List every adapter name the dispatch registry would accept (union of compile-time built-ins and [adapters.<name>] rows from .cosmon/config.toml)

Usage: cs config adapters

cs status

Project pulse — quick DAG overview like git status

Usage: cs status

EXAMPLES: cs status # pulse: active / pending / blocked / completed cs status --fleet research cs status --json # includes galaxies block (by-kind + nascent)

SEE ALSO: cs peek (fractal TUI), cs ensemble (full snapshot), cs galaxies list (four-family taxonomy).

cs project

Project — materialize views from the ledger (STATUS.md, ISSUES.md, GitHub Issues)

Usage: cs project [OPTIONS]

EXAMPLES: cs project # materialize surfaces from the ledger cs project --check # dry-run; exit 1 if surfaces are stale cs project --fetch # pull current GitHub Issue state before comparing

Pure projection. Writes STATUS.md / ISSUES.md / GitHub issues per .cosmon/surfaces.toml. Always safe to rerun. Reads as "materialize views from the ledger" (ADR-052 §D3).

Options:
  • --check — Dry-run: check if surfaces are up to date without writing

  • --fetch — Fetch current GitHub Issue state before comparing (detect remote edits)

  • --force — Deprecated no-op. Surfaces are always overwritten from authoritative state (derived-view semantics), so there is no longer a non-force mode to override. Accepted for backward compatibility

  • --no-escalate — Deprecated no-op. Surface conflicts no longer escalate or write git-style conflict blocks — surfaces are derived views and are always regenerated. Accepted for backward compatibility

  • --wait — Deprecated no-op. Reconcile never nucleates resolver molecules, so there is nothing to wait for. Accepted for backward compatibility

  • --heal-invariants — Heal the archived ⇒ status.is_terminal() invariant on disk.

    Default reconcile is a pure projection onto surfaces and never mutates molecule state (architectural-invariants.md). This flag opts into a one-shot migration: every molecule that is archived but carries a non-terminal status (a ghost, e.g. {archived: true, status: running}) is rewritten to status = Collapsed with reason archived-but-alive heal, and a MoleculeStatusChanged + MoleculeCollapsed event pair is appended so the heal survives a cache rebuild from events.jsonl.

    Idempotent: once healed, a second --heal-invariants pass finds nothing to do. Detect the violations first with cs verify --invariants.

cs reconcile

Reconcile — deprecated alias for cs project (ADR-052 §D3)

Usage: cs reconcile [OPTIONS]

EXAMPLES: cs reconcile # DEPRECATED — see below

DEPRECATED (ADR-052 §D3): use cs project instead. The new verb reads as "materialize views from the ledger"; reconcile read as "patch something that drifted", which is the framing ADR-052 retires. This alias will be removed after one release cycle.

SEE ALSO: cs project (canonical).

Options:
  • --check — Dry-run: check if surfaces are up to date without writing

  • --fetch — Fetch current GitHub Issue state before comparing (detect remote edits)

  • --force — Deprecated no-op. Surfaces are always overwritten from authoritative state (derived-view semantics), so there is no longer a non-force mode to override. Accepted for backward compatibility

  • --no-escalate — Deprecated no-op. Surface conflicts no longer escalate or write git-style conflict blocks — surfaces are derived views and are always regenerated. Accepted for backward compatibility

  • --wait — Deprecated no-op. Reconcile never nucleates resolver molecules, so there is nothing to wait for. Accepted for backward compatibility

  • --heal-invariants — Heal the archived ⇒ status.is_terminal() invariant on disk.

    Default reconcile is a pure projection onto surfaces and never mutates molecule state (architectural-invariants.md). This flag opts into a one-shot migration: every molecule that is archived but carries a non-terminal status (a ghost, e.g. {archived: true, status: running}) is rewritten to status = Collapsed with reason archived-but-alive heal, and a MoleculeStatusChanged + MoleculeCollapsed event pair is appended so the heal survives a cache rebuild from events.jsonl.

    Idempotent: once healed, a second --heal-invariants pass finds nothing to do. Detect the violations first with cs verify --invariants.

cs scheduler

Scheduler — read-only view onto cosmon-scheduler's state (patrols, last fires, log)

Usage: cs scheduler <COMMAND>

IMAGE: cosmon-scheduler is the house's alarm clock. It looks at the wall clock every 60s, reads its tablet (~/.config/cosmon/patrols.toml), and asks: 'was anything supposed to ring now?'. If yes, it fires a short-lived command, the command finishes, it dies. Cron-like.

(See the seven-clocks chronicle and the '2026-04-19 — Deux métiers, deux outils' chronicle for the full réveil/veilleur-de-nuit image.)

WHEN TO USE THE SCHEDULER:

  • periodic gesture, short burst (executor-pulse every 2h, mailroom-sync every 15min, chronicle-lint every Sunday morning)
  • fire-and-forget: the command finishes on its own
  • no persistent connection to maintain If the command must stay alive between fires, use cs daemons instead.

EXAMPLES — operator-facing (cs scheduler): cs scheduler status # pretty table of patrol last-fires cs scheduler status --json # NDJSON, one object per patrol cs scheduler status --log-lines 20 # also tail last 20 log lines cs scheduler status --state-file /tmp/state.json cs scheduler validate # lint ~/.config/cosmon/patrols.toml cs scheduler validate --config cand.toml # pre-flight a candidate file

CARDINAL PATROLS (copy-ready reference): docs/guides/patrols-cardinal.md cosmon-ward-mayor, reading-club-tick, leaks-watchdog, backlog-frontier-rot, digest-personnel — one [[patrol]] block each.

MINIMAL patrols.toml (/.config/cosmon/patrols.toml): [scheduler] state_file = "/.cosmon/scheduler.state.json" log_file = "/.cosmon/scheduler.log" kill_switch = "/.cosmon/stand-down.lock" tick_interval_seconds = 60

[[patrol]] name = "executor-pulse" interval_seconds = 7200 # cadence: every 2h command = ["mailroom", "executor-pulse"] enabled = true

[[patrol]] name = "chronicle-lint-weekly" cron = "0 9 * * 0" # cadence: Sundays 09:00 command = ["cs", "nucleate", "chronicle-lint"] working_dir = "~/galaxies/example-project" enabled = true

HOT-RELOAD: The scheduler re-reads patrols.toml on every tick (default 60s). Edit the file, save it, and the change takes effect within one tick — no signal, no reload command. Add a patrol = it fires on the next tick; disable one = it stops.

KILL-SWITCH: touch ~/.cosmon/stand-down.lock — the scheduler observes the lock at the next tick and quietly skips every patrol until the file is removed. No child is killed; already-firing patrols finish on their own. Same lock convention as cs daemons (one lockfile silences both worlds).

SEE ALSO: cs daemons (long-running processes), ADR-050 (unified patrol scheduler).

Subcommands:
  • status — Show the last-known state of every patrol the scheduler has observed
  • validate — Lint patrols.toml without firing anything — the safe pre-flight when adding or editing a patrol (success criterion (i) of the autopilot primitive). Zero side-effects: no state read, no dispatch, no kill-switch touch. Exits 0 when the file parses and validates, 1 otherwise — so it doubles as a CI gate. Mirrors cosmon-scheduler validate

cs scheduler status

Show the last-known state of every patrol the scheduler has observed

Usage: cs scheduler status [OPTIONS]

Options:
  • --state-file <PATH> — Path to the scheduler state file
  • --log-file <PATH> — Path to the aggregate scheduler log
  • --log-lines <N> — Tail the last N lines of the scheduler log after the status table. Omit the flag for no log output

cs scheduler validate

Lint patrols.toml without firing anything — the safe pre-flight when adding or editing a patrol (success criterion (i) of the autopilot primitive). Zero side-effects: no state read, no dispatch, no kill-switch touch. Exits 0 when the file parses and validates, 1 otherwise — so it doubles as a CI gate. Mirrors cosmon-scheduler validate

Usage: cs scheduler validate [OPTIONS]

Options:
  • --config <PATH> — Path to the patrol config TOML to lint

cs daemons

Daemons — operator view over cosmon-daemon-supervisor (list/status/reload/logs)

Usage: cs daemons <COMMAND>

IMAGE: cosmon-daemon-supervisor is the night watchman. It does not look at the clock. It looks at the dogs — processes that must always be alive. It reads its tablet (~/.config/cosmon/daemons.toml), keeps each dog alive; if one dies, it calls it back. Dogs never die voluntarily; if they die, it is an accident.

(See the '2026-04-19 — Le gardien des chiens, et le gardien des portes' and '2026-04-19 — Deux métiers, deux outils' chronicles for the full gardien-de-chiens / veilleur-de-nuit image.)

WHEN TO USE THE SUPERVISOR:

  • long-running process, persistent connection (Telegram long-polling, IMAP IDLE, MCP stdio server, Emacs daemon)
  • must be restarted if it dies
  • throttle respawns to avoid crashloops Synthetic examples: notification-bot, archive-service, editor-daemon, metrics-dashboard. If the command should run once-and-exit on a cadence, use cs scheduler instead.

EXAMPLES — operator-facing (cs daemons): cs daemons list # declared daemons (from daemons.toml) cs daemons status # per-daemon status + last spawn age cs daemons status --json # NDJSON, one object per daemon cs daemons reload # touch config → supervisor hot-reload cs daemons logs --lines 100 # tail the supervisor aggregate log

MINIMAL daemons.toml (/.config/cosmon/daemons.toml): [supervisor] state_file = "/.cosmon/daemon-supervisor.state.json" log_file = "/.cosmon/daemon-supervisor.log" kill_switch = "/.cosmon/stand-down.lock"

[[daemon]] name = "notification-bot" binary = "/.local/bin/notification-bot" args = [] throttle_seconds = 30 env = { RUST_LOG = "info" } log_stdout = "/.local/state/notification-bot/stdout.log" log_stderr = "~/.local/state/notification-bot/stderr.log" enabled = true

HOT-RELOAD: cs daemons reload touches ~/.config/cosmon/daemons.toml. The supervisor's notify watcher picks up the modification, runs the diff, and restarts ONLY the daemons whose spec actually changed (debounce ~200ms). Adding a new [[daemon]] block makes that daemon appear; removing one makes it exit gracefully. No signal sent to the supervisor itself.

SUPERVISOR-OF-THE-SUPERVISOR: The supervisor itself is a long-running process — it needs its own watchman. That is launchd (macOS): scripts/install-daemon-supervisor.sh installs one LaunchAgent for the supervisor, and launchd keeps it alive. The supervisor keeps N dogs alive. One plist, N dogs.

Install the LaunchAgent: scripts/install-daemon-supervisor.sh install scripts/install-daemon-supervisor.sh status scripts/install-daemon-supervisor.sh uninstall

KILL-SWITCH: touch ~/.cosmon/stand-down.lock — the supervisor SIGTERMs every child and parks them until the file disappears. Same convention as cs scheduler (one lockfile silences both).

SEE ALSO: cs scheduler (tick-based patrols), ADR-053 (cosmon-daemon-supervisor), ADR-016 §Autonomous (the regime this lives in).

Subcommands:
  • list — List declared daemons (reads daemons.toml, no state)
  • status — Show current status of each supervised child (reads state.json)
  • reload — Trigger a hot-reload by touching the config file
  • logs — Tail the supervisor log (the aggregate one, not per-daemon stdout)

cs daemons list

List declared daemons (reads daemons.toml, no state)

Usage: cs daemons list [OPTIONS]

Options:
  • --config <PATH> — Path to the daemons config file. Defaults to ~/.config/cosmon/daemons.toml

cs daemons status

Show current status of each supervised child (reads state.json)

Usage: cs daemons status [OPTIONS]

Options:
  • --config <PATH> — Path to the daemons config file. Defaults to ~/.config/cosmon/daemons.toml. Used to resolve the state file
  • --state-file <PATH> — Path to the supervisor state file. Overrides the state_file declared in the config

cs daemons reload

Trigger a hot-reload by touching the config file.

The supervisor's notify watcher picks up the modification and runs diff; no signal is sent and no child is restarted unless its DaemonSpec actually changed.

Usage: cs daemons reload [OPTIONS]

Options:
  • --config <PATH> — Path to the daemons config file. Defaults to ~/.config/cosmon/daemons.toml

cs daemons logs

Tail the supervisor log (the aggregate one, not per-daemon stdout)

Usage: cs daemons logs [OPTIONS]

Options:
  • --config <PATH> — Path to the daemons config file. Defaults to ~/.config/cosmon/daemons.toml. Used to resolve the log file

  • --log-file <PATH> — Path to the supervisor log file. Overrides the log_file declared in the config

  • --lines <N> — Number of trailing lines to print. Defaults to 50

    Default value: 50

cs migrate

Migrate the galaxy's memory — legacy flat→fleet, or residence-to-residence

Usage: cs migrate [OPTIONS] [COMMAND]

EXAMPLES: cs migrate # legacy flat→fleet migration (pre-residence galaxies) cs migrate to solo # atomic data+git migration to solo residence cs migrate to team # move to team residence (seal → stage → verify → flip + git-side) cs migrate to team --dry-run # seal manifest, print plan, touch no state cs migrate to solo --no-git # skip the git-side half (data only — outside a git repo) cs migrate to solo --no-commit # stage git-side changes, let operator commit cs migrate verify # re-walk state, compare against sealed manifest cs migrate rollback # inverse rename + restore git index / ignore files cs migrate rollback --dry-run # preview the rename pair, touch nothing cs migrate genre github-surface --to solo --yes # scoped: apply solo to one genre (ADR-057) cs migrate genre chronicle --to team --yes # seed orphan branch cosmon/chronicle cs migrate genre github-surface --to solo --dry-run # preview the plan, touch nothing

RESIDENCE VALUES: solo local, single operator (default layout) — state goes into .git/info/exclude team local, shared via git (cosmon-le-repo) — state goes into .gitignore encrypted local, encrypted at rest — same gitignore rule as team remote server-backed, network transport — same gitignore rule as team

EXIT CODES (cs migrate verify, mirrors cs verify): 0 manifest matches current state (A_pre ⊆ A_post, seal intact) 1 divergence: offending entries listed on stderr 2 no manifest on record (pre-migration galaxy or stale state)

The residence migration writes migration-manifest.pre.json at the galaxy root before touching any state, then stages the new tree alongside as state.next/, verifies it against the manifest, performs two atomic rename(2) calls to flip, and finally runs the git-side half: git rm -r --cached on the state directory, appends the state path to the residence's ignore file (.git/info/exclude for solo, .gitignore for team-class), and commits chore(cosmon): migrate to <residence> residence (git-side) unless --no-commit is passed. state.prev/ is kept as the rollback anchor; the pre-migration manifest also carries a snapshot of the git HEAD and ignore files so rollback restores the git side byte-for-byte. Orphan files (not tied to any molecule) are carried in a distinct bucket and never silently discarded.

Subcommands:
  • to — Perform a residence migration: seal manifest → stage next tree → verify staged tree → atomic rename pair to flip
  • verify — Verify the pre-migration BLAKE3 manifest against the current state. Exit codes mirror cs verify: 0 match, 1 divergence, 2 no manifest on record
  • rollback — Roll back the last migration by re-materializing state.prev/
  • genre — Apply a residence to every tracked path classified under a single genre (ADR-057 artifact-map). Composes artifact-map + git-side migration
Options:
  • --dry-run — Legacy mode: preview what would be migrated without moving anything
  • --cleanup — Legacy mode: remove the legacy ops/molecules/ directory after migration
  • --archive-past — Legacy mode: backfill the archive for existing terminal molecules (Completed, Collapsed, Frozen). Idempotent: molecules already carrying archived = true are skipped

cs migrate to

Perform a residence migration: seal manifest → stage next tree → verify staged tree → atomic rename pair to flip.

Atomic data-and-git residence flip. After the data-side phases (seal → stage → verify → rename), the git-side half runs (untrack + ignore-file update + path-scoped auto-commit) unless --no-git / --no-commit opt out.

Per-residence behavior (the four places the galaxy's memory can live):

solo Writes .cosmon/ to .git/info/exclude (per-clone notebook, never pushed). Sweeps any legacy .cosmon/ / .worktrees/ lines still present in the tracked .gitignore so the shared bulletin board doesn't override the local rule. Total local invisibility (ADR-055 §3.1).

team Appends .cosmon/state/ to the tracked .gitignore (shared with the code repo) and untracks any state files previously committed. Structural files (config.toml, formulas/*.toml, surfaces.toml, .gitignore) stay trackable. Orphan-branch-backed state sharing (cosmon/state) is the cosmon-le-repo backend target.

encrypted Same gitignore footprint as team today. The age-wrap backend (requires age on PATH and a --recipient recipient key) is deferred to cosmon-le-repo.

remote Same gitignore footprint as team. The server-backed transport backend is not yet implemented.

The pre-migration manifest snapshots git HEAD + ignore files so cs migrate rollback can restore the git side byte-for-byte. Orphan files (not tied to any molecule id) are carried in a distinct bucket and never silently discarded.

Usage: cs migrate to [OPTIONS] <RESIDENCE>

Arguments:
  • <RESIDENCE> — Target residence: solo, team, encrypted, or remote

    Possible values:

    • solo: Solo — local, single operator. Writes the whole .cosmon/ directory to .git/info/exclude (per-clone notebook, never pushed) and sweeps any legacy .cosmon/ / .worktrees/ lines from the tracked .gitignore (ADR-055 §3.1)
    • team: Team — local, shared across operators via git. Appends .cosmon/state/ to the tracked .gitignore (shared bulletin board) and untracks any previously committed state files. Structural files (config.toml, formulas/*.toml, surfaces.toml) stay trackable on main. Orphan-branch-based state sharing (cosmon/state) is the cosmon-le-repo backend target
    • encrypted: Encrypted — local, encrypted at rest. Same gitignore footprint as team today; the age-wrap backend (requires age on PATH and a --recipient key) is deferred to cosmon-le-repo
    • remote: Remote — server-backed state accessed via network transport. Same gitignore footprint as team; the transport backend is not yet implemented (tracked by cosmon-le-repo)
Options:
  • --dry-run — Preview the plan (seal + staging path) without renaming anything
  • --no-git — Skip the git-side half of the migration (no git rm --cached, no gitignore/exclude update, no auto-commit). Useful for tests and for galaxies that live outside a git repository
  • --no-commit — Apply git-side changes to the index + ignore file but do not create the chore(cosmon): migrate to <residence> residence (git-side) commit. The operator can inspect git status and commit manually

cs migrate verify

Verify the pre-migration BLAKE3 manifest against the current state. Exit codes mirror cs verify: 0 match, 1 divergence, 2 no manifest on record

Usage: cs migrate verify

cs migrate rollback

Roll back the last migration by re-materializing state.prev/

Usage: cs migrate rollback [OPTIONS]

Options:
  • --dry-run — Preview which rename would run without touching disk

cs migrate genre

Apply a residence to every tracked path classified under a single genre (ADR-057 artifact-map). Composes artifact-map + git-side migration

Usage: cs migrate genre [OPTIONS] --to <RESIDENCE> <NAME>

Arguments:
  • <NAME> — Genre name (must match a [<name>] table in .cosmon/artifact-map.toml)
Options:
  • --to <RESIDENCE> — Target residence

    Possible values:

    • solo: Solo — local, single operator. Writes the whole .cosmon/ directory to .git/info/exclude (per-clone notebook, never pushed) and sweeps any legacy .cosmon/ / .worktrees/ lines from the tracked .gitignore (ADR-055 §3.1)
    • team: Team — local, shared across operators via git. Appends .cosmon/state/ to the tracked .gitignore (shared bulletin board) and untracks any previously committed state files. Structural files (config.toml, formulas/*.toml, surfaces.toml) stay trackable on main. Orphan-branch-based state sharing (cosmon/state) is the cosmon-le-repo backend target
    • encrypted: Encrypted — local, encrypted at rest. Same gitignore footprint as team today; the age-wrap backend (requires age on PATH and a --recipient key) is deferred to cosmon-le-repo
    • remote: Remote — server-backed state accessed via network transport. Same gitignore footprint as team; the transport backend is not yet implemented (tracked by cosmon-le-repo)
  • --scrub-history — After the residence transition, invoke cs git scrub-history --path <paths> (when available) to rewrite prior commits that touched the matched paths.

    Soft dependency on cs git scrub-history. When the subcommand is not yet implemented, this flag degrades to a one-line warning and the migration still succeeds on the current tree.

  • --recipient <AGE_RECIPIENT>age recipient to wrap the narration for, when --to encrypted is set. Required for the encrypted path

  • --dry-run — Preview the plan without writing to disk or touching git

  • -y, --yes — Skip the interactive confirmation prompt

cs deps

Deps — show blocking dependencies for a molecule (upstream/downstream)

Usage: cs deps [OPTIONS] <MOLECULE>

EXAMPLES: cs deps # upstream + downstream blockers cs deps --upstream # only predecessors cs deps --json # for scripting

Reads the typed-link DAG (Blocks / BlockedBy).

Arguments:
  • <MOLECULE> — Molecule ID (exact or prefix) whose dependencies should be shown
Options:
  • --transitive — Walk the full transitive closure instead of only direct edges

cs mission

Mission — read-only DAG view joining ledger edges to completion merge commits

Usage: cs mission <COMMAND>

Subcommands:
  • graph — Render the mission DAG rooted at a molecule, joining ledger edges to their completion merge commits

cs mission graph

Render the mission DAG rooted at a molecule, joining ledger edges to their completion merge commits

Usage: cs mission graph <ROOT>

Arguments:
  • <ROOT> — Mission root molecule ID (exact or unambiguous prefix)

cs diverge

Diverge — structural agreement check between two sessions on a molecule (turing §5)

Usage: cs diverge [OPTIONS] <A> <B>

EXAMPLES: cs diverge <mol_id> # structural agreement check between two sessions

A structural-agreement primitive: two independent sessions on the same molecule are compared for divergence on the artifacts they produced. Used by livelock detection and consensus checks.

SEE ALSO: cs observe, cs deps.

Arguments:
  • <A> — First session — a session id or a path to a galaxy root
  • <B> — Second session — a session id or a path to a galaxy root
Options:
  • -m, --molecule <MOLECULE> — Molecule id (or prefix) whose views to compare. If omitted, only the git merge-base clause is evaluated and all molecule clauses are marked inconclusive

cs galaxies

Galaxies — inspect the four-family taxonomy

Usage: cs galaxies <COMMAND>

IMAGE: The fleet of repositories is not a flat list — it is four families, classified by the direction the bits flow across the galaxy's boundary:

infra        bits flow inward    the galaxy enables its sisters
project      bits flow through   artefacts + illuminated principles
social-hub   bits flow laterally human-to-human coordination
editorial    bits flow outward   one-way publication to strangers
nascent      not yet classified  awaiting W=28d observable tests

EXAMPLES: cs galaxies list # grouped view, one section per family cs galaxies list --json # flat array + by_kind totals

SEE ALSO: cs status --json (embeds the same galaxies block).

Subcommands:
  • list — List every galaxy grouped by its galaxy_kind family
  • registry — Inspect the stateless galaxy-name registry (~/.config/cosmon/galaxies.toml) used by cs ask

cs galaxies list

List every galaxy grouped by its galaxy_kind family

Usage: cs galaxies list

cs galaxies registry

Inspect the stateless galaxy-name registry (~/.config/cosmon/galaxies.toml) used by cs ask

Usage: cs galaxies registry <COMMAND>

Subcommands:
  • list — List every galaxy declared in the registry TOML
  • resolve — Resolve a single galaxy by name. Exits with status 1 if the name is not registered, so scripts can use it as a gate

cs galaxies registry list

List every galaxy declared in the registry TOML.

With --json, emits NDJSON (one entry per line) — the shape cs ask and other pilot agents can pipe into jq without extra envelope parsing.

Usage: cs galaxies registry list

cs galaxies registry resolve

Resolve a single galaxy by name. Exits with status 1 if the name is not registered, so scripts can use it as a gate

Usage: cs galaxies registry resolve <NAME>

Arguments:
  • <NAME> — Galaxy name to look up (exact match, case-sensitive)

cs topology

Topology — structural maps of the workspace (wraps the topon CLI)

Usage: cs topology <COMMAND>

EXAMPLES: cs topology map # PageRank-ranked module graph cs topology outline crates/cosmon-core/src/lib.rs cs topology symbols MoleculeId

Thin wrapper over the topon CLI. Structural view, not runtime state.

Subcommands:
  • map — PageRank-ranked structural map of a Rust project
  • outline — Symbol outline of a single Rust file
  • symbols — Search symbols by name across a Rust project

cs topology map

PageRank-ranked structural map of a Rust project

Usage: cs topology map [OPTIONS] [PATH]

Arguments:
  • <PATH> — Path to the project root (defaults to current directory)

    Default value: .

Options:
  • --max-symbols <MAX_SYMBOLS> — Maximum symbols per module (0 = unlimited)

    Default value: 0

cs topology outline

Symbol outline of a single Rust file

Usage: cs topology outline <FILE>

Arguments:
  • <FILE> — Path to the .rs file

cs topology symbols

Search symbols by name across a Rust project

Usage: cs topology symbols <PATH> <QUERY>

Arguments:
  • <PATH> — Path to the project root
  • <QUERY> — Search query (case-insensitive substring match)

Observability commands

These commands use physics-inspired names (nucleate, evolve, decay, spore, …). New to the vocabulary? See The physics vocabulary.

cs peek

Peek — canonical fleet observation command (TUI default; --no-tui for plaintext stream)

Usage: cs peek [OPTIONS]

EXAMPLES: cs peek # TUI over the current .cosmon/ cs peek --phase done,failed # + the archive; project scope unchanged cs peek --phase harvestable # the harvest queue: finished work still # owed a cs done (completed, unarchived) cs peek --all-galaxies # same phases, every .cosmon/ + tmux socket cs peek --all # sugar for --all-galaxies --phase all cs peek --no-tui # plaintext event stream cs peek --snapshot # byte-deterministic 120-col canonical view cs peek --snapshot > /tmp/a # capture from any device, then diff two # captures and expect zero bytes (see # docs/guides/peek-snapshot.md)

Keys in the TUI: j/k navigate, p tmux pane capture, b/l/e/s/r/n/g briefing/log/events/synthesis/responses/notes/git tabs.

Options:
  • --no-tui — Disable the TUI and render plaintext events to stdout. Required until the Phase 1 ratatui TUI lands

  • --once — Run a single poll + diff + propel pass and exit. Implies --no-tui

  • --follow — Follow the event stream until interrupted (the default for --no-tui when --once is not set)

  • --stale-after <STALE_AFTER> — Staleness threshold in seconds, passed to the propel pass

    Default value: 300

  • --poll-ms <POLL_MS> — State poll cadence in milliseconds

    Default value: 1000

  • --propel-every <PROPEL_EVERY> — Propel nudge cadence in seconds. Defaults to min(60, stale_after/5)

  • --no-tmux — Disable tmux propulsion. State is still read and diffed, but no nudges are sent

  • --all — Sugar for --all-galaxies --phase all, and exactly that. Both axes at their widest: every project AND every phase, archive included. --all means all, literally; it never narrows. Conflicts with the two flags it expands to — sugar and its expansion are one way of saying one thing, not two ways of saying it twice. See docs/guides/peek-temporalities.md

  • --all-galaxies — Perimeter axis: scan every project under $COSMON_CLUSTER_ROOT instead of the current one. Opt-in — cross-project reach is never implicit. Says nothing about which phases you see. Same spelling as cs tail --all-galaxies: one word, one meaning, across the binary. In TUI mode the a key toggles this at runtime

  • --phase <PHASE> — Temporality axis: which phases to surface. Repeatable and comma-separated; the values union. Says nothing about the perimeter. Defaults to unfinished — every molecule whose story is not over. --phase unfinished,done,failed is what --past used to mean; --phase harvestable is the harvest queue — finished work still owed a cs done. In TUI mode the A key cycles this at runtime

    Possible values:

    • live: A worker is on it right now
    • waiting: Nucleated, not yet started
    • blocked: An external authority is refusing service (ADR-062)
    • parked: Frozen by an operator gesture; one cs thaw from running
    • failed: Collapsed
    • done: Completed — the whole archive, harvested or not
    • harvestable: The harvest queue: completed and not yet archived, i.e. still owed a cs done. A strict subset of done
    • unfinished: Every phase whose story is not over — the default view
    • all: Every phase, archive included. All of this axis, and only this axis: it does not touch the perimeter
  • --energy-tick-interval <ENERGY_TICK_INTERVAL> — Cadence in seconds for emitting EnergyTick events into events.jsonl. Zero disables emission. Only active in --no-tui mode

    Default value: 30

  • --snapshot — Emit a byte-deterministic, fixed-width (120-col) ASCII snapshot of the fleet and exit. The same fleet state produces byte-identical output across every device — iPhone SSH, iPad Blink, MacBook, tmux pane — so a PR reviewer can diff two captures and expect zero differences. Implies --no-tui and disables propulsion; no clock or environment ($COLUMNS, $TERM) affects the output

cs tail

Tail — live notify-driven reader over events.jsonl (fleet or --all-galaxies)

Usage: cs tail [OPTIONS]

EXAMPLES: cs tail # live tail of the current galaxy events.jsonl cs tail --all-galaxies # multiplex all known galaxies

Live notify-driven reader over events.jsonl. Default scope is the current fleet; --all-galaxies multiplexes across the registered cosmon roots.

SEE ALSO: cs events (one-shot dump), cs ensemble (snapshot view).

Options:
  • --all-galaxies — Scan every project under $COSMON_CLUSTER_ROOT. Opt-in — cross-project reach is never implicit

  • -f, --follow — Stay attached and stream new events via notify

  • --since <SINCE> — Only show events at or after this timestamp. Accepts ISO-8601 (2026-04-24T12:00:00Z) or relative (-5m, -1h, -2d). allow_hyphen_values lets the relative form be written without --since=

  • --kind <KIND> — Only show events whose type tag matches (e.g. molecule_nucleated)

  • -n, --tail <TAIL> — Number of most-recent lines to print before follow (like tail -n)

    Default value: 20

  • --cluster-root <CLUSTER_ROOT> — Override the cluster root used by --all-galaxies

cs errors

Errors — aggregate molecule-collapse events into one failure overview: what is breaking the fleet, and which molecules are hit

Usage: cs errors [OPTIONS]

Options:
  • --since <SINCE> — Time window — accepts a relative duration (<N>d, <N>h, <N>m, <N>s) or an RFC-3339 absolute timestamp. Defaults to 7 days

    Default value: 7d

  • --kind <VARIANT> — Filter to one CollapseReason variant. Accepts the on-wire strings: worker_crashed, gate_failed, blocker_stuck, manual_abort, resource_exhausted. Any other value is treated as a substring match on the free-form Other payload

  • --reason <TEXT> — Substring match on the free-form reason text. Case-sensitive

  • --top <TOP> — Maximum number of variant rows to display in the summary

    Default value: 10

  • --ops-dir <OPS_DIR> — Path to the state store root (overrides walk-up discovery)

  • --json — Emit JSON instead of the tabular summary. The global --json flag also enables this

cs health

Health — read-only molecule-health anomaly catalog, federation-wide (ADR-137 §7)

Usage: cs health [OPTIONS]

EXAMPLES: cs health # read-only anomaly catalog, current galaxy cs health --all # every project below the configured root cs health --json # NDJSON: one header line, one line per finding cs health --no-tmux # state-only (skip the tmux liveness probe)

The Witness (ADR-137 Phase 1): a zero-mutation, control-plane-only scan that surfaces the molecule-health anomaly catalog (A1 unsent-paste, A3 auth-dead, A4 idle-after-complete, A5 idle-running-zombie, A6 overloaded, A7 ghost-merge, A8 completed-unharvested, A9 crash-zombie) the way cs peek surfaces fleet state. Every signal is read from the state machine — molecule status, liveness lease, transport probe — NEVER from a pane glyph (the be1e use/mention guard). It heals nothing; the remedies it prints are advisory. Exit code: 0 all-healthy, 1 findings present (CI/monitor-friendly).

Options:
  • --all — Scan every .cosmon/state/ below the configured cluster root, the way cs peek --all aggregates. Without it, only the current galaxy's state store is scanned
  • --no-tmux — Skip the tmux liveness probe (state-only mode, for tests / headless). Session liveness is reported as unknown, so session-dependent classes (A1/A4/A5/A9) are conservatively not flagged

cs pulse

Pulse — runtime-vitality reading: RPM tachometer, six-voyant strip (ADR-138 P1)

Usage: cs pulse [OPTIONS]

EXAMPLES: cs pulse # runtime-vitality: RPM tachometer + six voyants cs pulse --window 10m # widen observation window (default 5m) cs pulse --json # cosmon.pulse/v1 NDJSON line (CI/scripting)

Pulse (ADR-138 Phase 1): a zero-mutation, stateless projection of fleet liveness onto a single tachometer headline + six-voyant strip.

Headline: RPM = dΦ/dt = completions/min in the observation window W. The event log is the pre-integrated derivative — no stored Φ, no new state store (IFBDD). A word replaces the number when magnitude lies: SPINNING — tokens burn, Φ flat (P==0, B>b_min) → RED DRAINAGE OFF — no forward tick in τ → RED

Traffic light (first-match wins): RED — subsystem dead (H_sched>τ) OR fuel exhausted OR spinning AMBER — stalled (P==0, L>0, ¬dead) OR starved molecules present GREEN — doing work (P>0) OR quiescent (L==0)

Voyant strip: scheduler / drainage / propel / heal / fuel / workers A dead subsystem serializes 'off' (red-class) — never silently absent.

Exit code: always 0 (read-only, non-blocking — callers use --json state).

Options:
  • --window <WINDOW> — Observation window — accepts <N>d / <N>h / <N>m / <N>s. Defaults to 5 minutes (5m)

    Default value: 5m

  • --sched-tau <SCHED_TAU> — Scheduler-dead threshold — age beyond which H_sched triggers RED. Defaults to 10 minutes (10m)

    Default value: 10m

  • --sched-log <SCHED_LOG> — Path to the launchd-scheduler heartbeat log.

    Defaults to ~/.cosmon/scheduler.state.json.events.jsonl (derived from the scheduler state file by appending .events.jsonl).

    Override with COSMON_SCHED_LOG env var or this flag for testability or non-standard launchd setups.

  • --sched-state <SCHED_STATE> — Path to scheduler.state.json.

    The drainage, propel, and heal voyants read patrols.<name>.last_fired_at from this file — the authoritative per-patrol fire time written by the scheduler on every dispatch, regardless of what the patrol command does.

    Defaults to ~/.cosmon/scheduler.state.json. Override with COSMON_SCHED_STATE env var or this flag for testability.

  • --json — Emit the aggregate as a single cosmon.pulse/v1 NDJSON line. The global --json flag also enables this

  • --swiftbar — Emit SwiftBar/BitBar formatted output for the macOS menubar plugin.

    First line = menubar face (colored dot + headline + SwiftBar params). Below ---: the six voyant lines, fuel%, scanned, separator, action items. Consumed by menubar/cosmon-pulse.10s.sh which execs cs pulse --swiftbar. See ADR-068: cs pulse --swiftbar is the UI surface for cs pulse.

cs doctor

Doctor — diagnostic probes (whisper channel, …)

Usage: cs doctor <COMMAND>

Subcommands:
  • whisper — Probe the whisper channel of a molecule's assigned worker
  • leaks — Scan tracked files for leaked secrets and non-public state (blocking)
  • worktrees — Audit .worktrees/ for perm/symlink/untracked hazards
  • mcp — Audit MCP servers registered in the configured service registry
  • deps — Flag unpinned or mutable dependency declarations
  • supervision — Detect binaries supervised by both cosmon and a LaunchAgent
  • security — Run every security probe and aggregate findings

cs doctor whisper

Probe the whisper channel of a molecule's assigned worker

Usage: cs doctor whisper <MOLECULE_ID>

Arguments:
  • <MOLECULE_ID> — Molecule ID (full or unambiguous prefix)

cs doctor leaks

Scan tracked files for leaked secrets and non-public state (blocking)

Usage: cs doctor leaks [OPTIONS]

Options:
  • --path <PATH> — Limit scanning to this subdirectory (relative to repo root)
  • --include-untracked — Also scan untracked working-tree files (use when pre-commit check)
  • --corpus <FILE> — Byte-literal patterns, one per line (UTF-8, # comments)

cs doctor worktrees

Audit .worktrees/ for perm/symlink/untracked hazards

Usage: cs doctor worktrees [OPTIONS]

Options:
  • --root <ROOT> — Override the project root (default: git top-level)

cs doctor mcp

Audit MCP servers registered in the configured service registry

Usage: cs doctor mcp [OPTIONS]

Options:
  • --registry <REGISTRY> — Override the path to the service registry database.

    Defaults to the platform data dir used by the service registry.

cs doctor deps

Flag unpinned or mutable dependency declarations

Usage: cs doctor deps [OPTIONS]

Options:
  • --root <ROOT> — Override the workspace root

cs doctor supervision

Detect binaries supervised by both cosmon and a LaunchAgent

Usage: cs doctor supervision [OPTIONS]

Options:
  • --patrols <PATROLS> — Override the patrols config (~/.config/cosmon/patrols.toml)
  • --daemons <DAEMONS> — Override the daemons config (~/.config/cosmon/daemons.toml)
  • --launch-agents-dir <LAUNCH_AGENTS_DIR> — Override the LaunchAgents directory to scan

cs doctor security

Run every security probe and aggregate findings

Usage: cs doctor security [OPTIONS]

Options:
  • --root <ROOT> — Override the workspace/git root
  • --registry <REGISTRY> — Override the path to the service registry database
  • --include-untracked — Also include untracked files in the leak scan

Integrity & audit commands

These commands use physics-inspired names (nucleate, evolve, decay, spore, …). New to the vocabulary? See The physics vocabulary.

cs verify

Verify — walk a molecule's event hash chain (plumbing v2)

Usage: cs verify [OPTIONS] [MOLECULE_ID]

EXAMPLES: cs verify # walk the event hash chain cs verify --strict # also replay gates

Proof-of-work chain integrity check.

Arguments:
  • <MOLECULE_ID> — Molecule ID (or prefix) whose proof-of-work chain should be verified.

    Optional when --federation is set — the federation provenance scan is a fleet-wide audit and does not target a single molecule.

Options:
  • --no-replay — Skip gate replay (shell/native step re-execution). Artifact hash check and event chain check still run

  • --step <N> — Verify the briefing seal for a specific zero-based step index.

    When omitted, the most recent briefing seal (if any) is checked against the current briefing.md. When specified, the corresponding entry from MoleculeData::briefing_seals is used. If no seal exists for the requested step, the check is reported as SKIP (inconclusive), never as FAIL.

  • --federation — Scan the fleet-wide event log for cross-galaxy events missing federation provenance (ADR-105, I9' machinery).

    When set, walks <state_dir>/events.jsonl and reports every cross-galaxy event whose federation_provenance is None:

    • MergeDispatched / MergeCompleted whose molecule_id or branch carries a foreign galaxy alias (Oracle B subject-mark per ADR-105 §D3). - ChronicleAdded whose cites_galaxies mentions a non-cosmon peer (Oracle B'' delegation-dispatched per ADR-105 §D3). - AdrInscribed whose cites_galaxies mentions a non-cosmon peer (same Oracle B'' channel for ADR-grade citations).

    Missing provenance is a hard FAIL — the federation discipline is detect-on-write, cs verify --federation is the audit oracle.

    The flag stacks with molecule_id: when both are given, the scan is restricted to the molecule's local events.jsonl. When molecule_id is omitted, the fleet-wide log is scanned.

  • --legacy-tolerate-before <DATE> — Tolerate cross-galaxy events emitted before a specific date that lack federation provenance.

    Format: ISO8601 date (e.g. 2026-05-19). Events whose envelope timestamp is strictly before the date are downgraded from FAIL to SKIP with a tracing::warn!-equivalent detail line. Only meaningful in combination with --federation.

    Default: not set — every cross-galaxy event without provenance is a hard FAIL. ADR-105 §"Backfill discipline" recommends option (a) (backfill the field by reading the existing citation format); this flag is option (b), the legacy-tolerate escape hatch for the migration window.

  • --invariants — Check structural state-machine invariants over molecule rows.

    Currently a single invariant is enforced: archived ⇒ status.is_terminal() — an archived molecule must carry a terminal status (Completed or Collapsed). A row with {archived: true, status: running} is a ghost: it was torn down out-of-band (e.g. cs done --force on a never-completed molecule) without terminalizing its status, so it keeps rendering as live work.

    Detection only — cs verify --invariants never mutates state; it exits non-zero when any violation is found. To heal the on-disk rows (rewrite status → Collapsed), run cs reconcile --heal-invariants.

    Like --federation, the flag stacks with molecule_id: with a molecule given, only that row is checked; without one, every molecule in the fleet is swept (the galaxy-wide audit).

cs verify-trace

verify-trace — replay events.jsonl against the scheduler spec (Phase 3 CI gate)

Usage: cs verify-trace [OPTIONS] <TRACE>

Arguments:
  • <TRACE> — Path to the events.jsonl trace. Use - to read from stdin
Options:
  • --skip-unknown — Tolerate lines whose shape is not recognised by EventV2 or the legacy migration helper — they are counted and skipped instead of failing the whole replay. Required when replaying historical fleet logs that pre-date the canonical schema

cs verify-graph

verify-graph — Tarjan SCC check on the subgraph induced by a typed relation (substrate, ADR-016)

Usage: cs verify-graph [OPTIONS]

EXAMPLES: cs verify-graph --relation blocks # check the Blocks subgraph for cycles cs verify-graph --relation refines # check Refines (cycles permitted, reported as WARN) cs verify-graph --all # every registered relation cs verify-graph --all --json # NDJSON, one row per relation

Tarjan SCC check on the subgraph induced by a typed MoleculeLink relation. Substrate primitive for the organization-twin programme. Read-only — does not mutate state.

Exit code: 0 every DAG-required relation is acyclic 1 at least one DAG-required relation contained a cycle Cycles in non-DAG-required relations (e.g. refines) are reported but do not flip the exit code.

Options:
  • --relation <KIND> — Single relation to check (e.g. blocks, decay-product, merged-from, refines, refutes). Mutually exclusive with --all
  • --all — Check every registered relation kind in turn

cs spec-audit

spec-audit — ledger audit against the TLA+ spec (catches c1cb bypass_merge)

Usage: cs spec-audit [OPTIONS]

EXAMPLES: cs spec-audit # default: cosmon-run × events.jsonl cs spec-audit --fleet default # explicit fleet (advisory today) cs spec-audit --events path/to/events.jsonl cs spec-audit --json # NDJSON drift report cs spec-audit --no-git-probe # skip the c1cb merge-topology probe

Multi-spec: cs spec-audit --spec mycelial-gate --events .cosmon/state/attestor-events.jsonl cs spec-audit --spec attestor-graph --events .cosmon/state/attestor-events.jsonl cs spec-audit --spec witness-freshness --events .cosmon/state/attestor-events.jsonl cs spec-audit --spec noogram/specs/MycelialGate.tla # path also accepted

Ledger audit: replays events through the TLA+ spec and flags drifts. For --spec cosmon-run (default), drifts include c1cb bypass_merge and disabled-action-fired. For the noogram specs, drifts are emitted as spec_invariant_violation with stable (spec, invariant) tags — see crates/cosmon-core/src/attestor_audit.rs for the full taxonomy and docs/specs/attestor-events.schema.json for the AttestorEventV1 NDJSON schema. One-shot, not a daemon. Exit 0 if clean, 1 if any drift is found.

Options:
  • --fleet <FLEET> — Fleet id whose ledger should be audited. Defaults to the fleet resolved from the walk-up config (default for single-fleet projects). The fleet id is advisory today — the canonical events.jsonl lives at .cosmon/state/events.jsonl regardless of fleet — but the flag is accepted so future multi-ledger layouts stay backward-compatible

  • --spec <SPEC> — Which spec to audit against. Defaults to cosmon-run (historical behaviour). Other accepted values: mycelial-gate, attestor-graph, witness-freshness. A path to a .tla file is also accepted; the basename (snake/Camel-case normalised) is looked up in the registry

    Default value: cosmon-run

  • --events <PATH> — Explicit path to the events file to audit. Overrides --fleet and the walk-up state-dir discovery. The expected format depends on --spec:

    • cosmon-run.cosmon/state/events.jsonl (EventV2 envelopes). * Noogram specs → .cosmon/state/attestor-events.jsonl (AttestorEventV1 envelopes, see cosmon/docs/specs/attestor-events.schema.json).
  • --repo <PATH> — Repository whose branch topology should be probed for the c1cb out-of-band check. Defaults to the current working directory. Pass --no-git-probe to disable the probe entirely (useful when git is not available, e.g. inside CI sandboxes). Only meaningful when --spec cosmon-run

  • --no-git-probe — Disable the git-topology probe. When set, the audit still flags disabled-action-fired drifts but does not emit bypass_merge findings. The switch exists so the audit stays useful in environments without git (containers, strict sandboxes). Only meaningful when --spec cosmon-run

  • --target-ref <REF> — Target branch for the merge-topology probe. Defaults to origin/main; pass main to check the local branch when no remote tracking is configured. Only meaningful when --spec cosmon-run

    Default value: origin/main

cs release-audit

release-audit — dry-run drift detector for the public distribution (analogue of reconcile --check)

Usage: cs release-audit [OPTIONS]

EXAMPLES: cs release-audit --dry-run # simulate the release chain on the live tree cs release-audit --dry-run --json # machine report for CI / jq cs release-audit --repo /path/to/clone # audit an explicit repo root

Dry-run drift detector for the public cosmon distribution — the release-side analogue of cs reconcile --check.

PRIMARY MEMBRANE — deny-by-default allowlist (ADR-127). Ship nothing except positively-cleared paths: every tracked, non-purged path must carry a per-path permit in .cosmon/release-allowlist.toml, or it is a path-not-permitted regression. A new confidential file is caught BY CONSTRUCTION (new = unpermitted = refused), instead of slipping past a frozen denylist. Content-bound permits (with a blake3 seal) go permit-stale when the file changes — cleanliness-now, not freshness-at-t0. The membrane is ARMED by the presence of the allowlist file; absent it, the audit runs in legacy denylist mode and says so LOUDLY (a warning, never a silent pass). Bless paths with scripts/release/ bless-allowlist.sh (a separate tool — the audit stays read-only).

CONTENT BACKSTOP — the legacy detectors still run on permitted files:

  • a private-sibling path dependency reappeared (the claudion vendoring case);
  • a client name reintroduced in a tracked path the rename chain misses;
  • a structural string the chain does not scrub (operator homeserver, etc.);
  • a live instance oidc-identity.toml re-tracked under a non-purged path. The confidential detector literals live in the PRIVATE, purged-from-release .cosmon/release-rules.toml (Bucket-3) — not in the shipped source, so the detector is no longer its own leak. Absent that file the backstop is inert and the audit warns.

Exit 0 if the distribution is clean, 1 if it would regress. One-shot, not a daemon; reports, does not remediate. See ADR-127.

The audited repo may exempt structural strings that are intentionally public in it (e.g. a maintainer-contact domain) via .cosmon/release-audit.toml, each with a mandatory justification — the same exemption list its own forbid-strings CI gate should read, so both referees agree.

Options:
  • --dry-run — Simulate the release-resync transformation chain against the live working tree (no scratch clone) and report regressions. This is currently the only mode; the flag is accepted so the documented invocation cs release-audit --dry-run is exact
  • --repo <PATH> — Repository root to audit. Defaults to the toplevel discovered by git rev-parse --show-toplevel from the current directory

cs notarize

Notarize — issue or verify an operator-signed attestation for a molecule (ADR-056)

Usage: cs notarize [OPTIONS] [MOLECULE_ID] [COMMAND]

Subcommands:
  • issue — Issue a new seal — build the commitment, sign with Ed25519, write mint.json
  • verify — Verify an existing seal — full Ed25519 + canonical commitment bytes
Arguments:
  • <MOLECULE_ID> — Legacy: molecule ID (or prefix) to notarize. Equivalent to cs notarize issue <MOLECULE_ID>
Options:
  • --dry-run — Legacy: skip signing — compute and print the commitment only
  • --key <PATH> — Legacy: path to an Ed25519 secret-key file
  • --cosmon-version <COSMON_VERSION> — Legacy: override cosmon_version in the commitment

cs notarize issue

Issue a new seal — build the commitment, sign with Ed25519, write mint.json

Usage: cs notarize issue [OPTIONS] <MOLECULE_ID>

Arguments:
  • <MOLECULE_ID> — Molecule ID (or prefix) to notarize
Options:
  • --dry-run — Skip signing — compute and print the commitment only. Default when --key is not provided
  • --key <PATH> — Path to an Ed25519 secret-key file (raw 32 bytes or 64-char lowercase hex). Required for a real notarization
  • --cosmon-version <COSMON_VERSION> — Override cosmon_version in the commitment (defaults to the crate-level CARGO_PKG_VERSION). Mostly useful for tests

cs notarize verify

Verify an existing seal — full Ed25519 + canonical commitment bytes

Usage: cs notarize verify <PATH>

Arguments:
  • <PATH> — Path to a seal JSON file (e.g. <mol_dir>/mint.json or theater/pitch-*/notary/slides.notarization.json)

cs witness

Witness — Layer-2 witness-quorum seal for stress-test molecules (ADR-085 §3)

Usage: cs witness <COMMAND>

EXAMPLES: cs witness attest # default prior path: <mol_dir>/prior.md cs witness attest --prior-path prior.md # explicit prior file cs witness attest --witness-id ci-bot # deterministic identity (LaunchAgent/CI) cs witness attest --json # NDJSON for scripting

Layer-2 witness-quorum seal for stress-test molecules (ADR-085 §3). A separate cosmon agent reads the prior file's bytes, computes its BLAKE3 hash, and emits a SealAttested event distinct from the molecule's tackler session. Refuses if the molecule's class is not stress-test, or if the witness identity matches the tackler's session_name (cheap structural-independence check).

SEE ALSO: cs notarize (operator Ed25519 attestation, ADR-056).

Subcommands:
  • attest — Attest a stress-test molecule's prior seal — emit SealAttested

cs witness attest

Attest a stress-test molecule's prior seal — emit SealAttested

Usage: cs witness attest [OPTIONS] <MOLECULE_ID>

Arguments:
  • <MOLECULE_ID> — Molecule ID (or prefix) to attest. Must be a stress-test class molecule (ADR-085 §1); standard-class molecules are refused so a witness cannot accidentally lend weight to a tactical deliberation
Options:
  • --prior-path <PATH> — Path to the operator-sealed prior. Defaults to <molecule_dir>/prior.md. The witness opens this file, computes its BLAKE3 hash, and records that hash in the EventV2::SealAttested::prior_b3 field. The witness never inspects the file's content beyond the bytes-to-hash transformation.
  • --witness-id <ID> — Override the witness identity. Defaults to the [cosmon_runtime::resolve_witness_id] heuristic ($TMUX first, then <host>-<pid>). Useful for LaunchAgent / CI invocations that want a deterministic identity

cs key

Key — manage the operator's Ed25519 notary key (generate, show)

Usage: cs key <COMMAND>

EXAMPLES: cs key generate # ~/.config/cosmon/operator.key (0600) cs key generate --output /tmp/dev.key # alternate destination cs key generate --force # overwrite an existing key cs key show # print pubkey hex of the default key

Generates a fresh Ed25519 secret (32 bytes of OS randomness, 64-char lowercase hex) at the path cs notarize --key already expects. Silent rotation is forbidden: without --force the command refuses to clobber an existing key file. For retirement / successor publication, see ADR-060 (cs rotate-key, deferred post-S4).

SEE ALSO: cs notarize (sign a molecule under the operator key), docs/guides/notary-operator-guide.md, ADR-056, ADR-060.

Subcommands:
  • generate — Generate a fresh Ed25519 operator key (32 bytes OS randomness, hex-encoded)
  • show — Print the public key (and its path) for an existing operator key file

cs key generate

Generate a fresh Ed25519 operator key (32 bytes OS randomness, hex-encoded)

Usage: cs key generate [OPTIONS]

Options:
  • --output <PATH> — Destination path. Defaults to ~/.config/cosmon/operator.key
  • --force — Overwrite an existing key file. Without this flag, refuses to clobber any pre-existing key — silent rotation is forbidden (ADR-060 §Alternatives-rejected)

cs key show

Print the public key (and its path) for an existing operator key file

Usage: cs key show [OPTIONS]

Options:
  • --key <PATH> — Path to the operator key file. Defaults to ~/.config/cosmon/operator.key

Tools commands

These commands use physics-inspired names (nucleate, evolve, decay, spore, …). New to the vocabulary? See The physics vocabulary.

cs pilot

Pilot — interactive cognitive pilot REPL over a client-side model (--experimental). --remote pilots an avatar over the §8p wire (ADR-115)

Usage: cs pilot [OPTIONS]

Options:
  • --experimental — Enable the experimental verb. While the interactive loop matures, cs pilot without this flag prints a safety notice and does nothing — no REPL, no model call, no side effects (mirrors cs ask, ADR-071)
  • --model <TAG> — Ollama model tag to drive the loop (default: llama3.2). Falls back to the COSMON_PILOT_MODEL environment variable when the flag is omitted
  • --base-url <URL> — Override the model endpoint (default: the local Ollama OpenAI-compatible endpoint http://localhost:11434/v1). Falls back to COSMON_PILOT_BASE_URL when the flag is omitted
  • --transcript <PATH> — Path the on-disk transcript is appended to (default: pilot-transcript.md in the current directory). Falls back to COSMON_PILOT_TRANSCRIPT when the flag is omitted
  • --timeout <SECS> — Per-request timeout in seconds for each model round-trip (default: 300). The pilot defaults far above the provider's 60s library default because it injects the full repo CLAUDE.md (~36 KB) as bootstrap context, so a large local model (e.g. qwen2.5:32b) legitimately spends minutes on the first prefill. Falls back to COSMON_PILOT_TIMEOUT (also in seconds) when the flag is omitted
  • --remote — Pilot a REMOTE avatar over the network instead of the local cosmon instance (ADR-115 §6). The model still runs client-side (this box); only cosmon operations cross the wire, via the avatar's cosmon-rpp-adapter §8p routes (ADR-080). Read-only unless --write
  • --profile <NAME> — Which cosmon-remote profile to use in --remote mode (the avatar's host + JWT identity). Defaults to the configured default profile (~/.config/cosmon-remote/). Ignored without --remote
  • --write — In --remote mode, expose the write tools (nucleate / tackle) in addition to the read tools. Off by default — a remote session sees the fleet but cannot change it unless asked. done / evolve are never available regardless (ADR-080 §5). Ignored without --remote

cs prime

Prime the system — load .cosmon/config.toml and self-check gates

Usage: cs prime [OPTIONS] [MOLECULE]

EXAMPLES: cs prime # load .cosmon/config.toml, report gates

Boot-time self-check. No network calls; verifies the local project is well-formed.

Arguments:
  • <MOLECULE> — Molecule ID to prime (optional — auto-detects from running molecule)
Options:
  • --hook — Check hook and prime if work is assigned

cs paths

Paths — project the write-path taxonomy (--writes), a pure derived view

Usage: cs paths [OPTIONS]

Options:
  • --writes — Emit the set of paths cosmon writes under the state root.

    Currently the only projection mode; the flag is explicit so future projections (e.g. --reads) can be added without changing the default behaviour. Omitting it is equivalent to passing it.

cs archive

Archive — operator view over durable terminal snapshots (list/show/verify/prune, ADR-030)

Usage: cs archive <COMMAND>

EXAMPLES: cs archive list # every archived molecule, all months cs archive list --year 2026 # scoped to one year cs archive list --year 2026 --month 04 # scoped to one month cs archive list --json # NDJSON for scripting cs archive show # manifest + artifact inventory cs archive verify # recompute hashes (exit 1 if tampered) cs archive prune --dry-run # what retention policy would delete cs archive prune # execute the retention policy

Operator view onto .cosmon/state/archive/. Terminal transitions (cs done / cs collapse / cs freeze / cs stuck) populate the archive when [archive] enabled = true in the project config. The archive outlives worktree teardown and branch deletion — a fresh clone sees every merged molecule's canonical snapshot.

Retention is controlled by [archive.retention] in config.toml: keep_all (default true) — safety switch; must be false to delete max_age_days (default 0) — 0 disables the age rule max_total_mb (default 0) — 0 disables the size rule keep_kinds (default decision, deliberation)

Hash-chain integrity is enforced: a molecule referenced as parent (DecayedFrom / BlockedBy / MergedFrom) by a kept entry is never deleted.

Subcommands:
  • list — List archived molecules (optionally filtered by year / month)
  • show — Show the manifest + artifact inventory for one archived molecule
  • verify — Verify artifact hashes — exits non-zero if tampered
  • prune — Apply the [archive.retention] policy; --dry-run shows the plan

cs archive list

List archived molecules (optionally filtered by year / month)

Usage: cs archive list [OPTIONS]

Options:
  • --year <YYYY> — Restrict the scan to a single year (e.g. 2026)
  • --month <MM> — Restrict the scan to a single month (01..=12). Must be used with --year to be meaningful; standalone --month still filters across whichever years contain that month
  • --since-days <N> — Keep only entries whose directory was modified within the last N days. 0 means no limit. Combines with --year/--month. Used by the CI gate (.github/workflows/archive-verify.yml)
  • --ids-only — Emit one molecule id per line, skipping the table header / JSON envelope. Intended for shell pipelines (xargs cs archive verify)

cs archive show

Show the manifest + artifact inventory for one archived molecule

Usage: cs archive show <MOLECULE>

Arguments:
  • <MOLECULE> — Molecule id or unique prefix

cs archive verify

Verify artifact hashes — exits non-zero if tampered

Usage: cs archive verify <MOLECULE>

Arguments:
  • <MOLECULE> — Molecule id or unique prefix

cs archive prune

Apply the [archive.retention] policy; --dry-run shows the plan

Usage: cs archive prune [OPTIONS]

Options:
  • --dry-run — Show what would be deleted and exit — never touch disk

cs journal

Write down what you notice while you work; anything worth doing becomes a task without you stopping to file it

Usage: cs journal <COMMAND>

EXAMPLES: cs journal start # open a carnet cs journal start --galaxy example --root delib-example-0001 cs journal note "Torvalds elected path a" cs journal note --tag insight "the carnet is the primitive" cs journal note "!spark implémenter session-to-spark" # prefix auto-promotes cs journal end # seal with BLAKE3 + auto-commit cs journal end --no-seal # ephemeral scratch close

PROMOTE — turn journal notes into spark molecules: cs journal promote 10:46:55 # promote one note by timestamp cs journal promote 10:46:55 10:47:01 # promote several cs journal promote --all-spark-prefix # promote every !spark-prefixed note cs journal promote --dry-run # show what would be promoted cs journal promote --session session-2026-04-22T10-31-31Z 10:46:55

Notes beginning with !spark are automatically promoted by the session-to-spark LaunchAgent (when installed, fires every 5 min). Explicit cs journal promote <ts> works regardless of prefix and is idempotent — sidecar markers under .cosmon/state/journals/.promoted/ prevent duplicate sparks.

Exit codes: 2 a session is already open (on cs journal start) 3 no open session (on cs journal note / cs journal end)

Journals live under .cosmon/state/journals/ as append-only markdown files. The seal is a BLAKE3 hash of the body between the frontmatter and footer — a trace, not a lock (architectural-invariants.md §8b). Promotion never mutates a sealed journal — markers are sidecar-only.

Subcommands:
  • start — Open a journal — every note you take lands in it until you end it
  • note — Append a timestamped note to the open journal
  • end — Close the open journal, optionally sealing it with BLAKE3
  • promote — Turn journal notes into spark molecules (via the session-to-spark tick)
  • route — Route journal notes through the Tier-1 regex classifier (ADR-072)
  • review — Review router-staged molecules (verdict-door)

cs journal start

Open a journal — every note you take lands in it until you end it

Usage: cs journal start [OPTIONS]

Options:
  • --galaxy <GALAXY> — Galaxy this session belongs to (free-form label)
  • --root <MOL_ID> — Root molecule(s) this session is anchored on (repeatable)

cs journal note

Append a timestamped note to the open journal

Usage: cs journal note [OPTIONS] <TEXT>

Arguments:
  • <TEXT> — Free-form note body
Options:
  • --tag <TAG> — Optional tag rendered alongside the timestamp (e.g. insight, todo)
  • --cause-kind <KIND> — How the note was produced. One of direct (human typed), transcription (human spoke, agent transcribed), oracle-suggestion (agent proposed, human accepted), autonomous (agent authored alone). Omit to skip the cause: subline entirely — the note renders in the pre-schema format. Supplying any --cause-* flag enables the subline with defaults kind=direct, agent=null, channel=keyboard
  • --cause-agent <AGENT> — Identity of the mediating agent (e.g. apfel-oracle-<host>, matrix:@tenant_auditor:hs). Leave unset when --cause-kind direct
  • --cause-channel <CHANNEL> — Physical channel the note arrived on. Known variants: keyboard, voice, matrix, webhook. Any other value is accepted verbatim and round-trips as Other(<value>)

cs journal end

Close the open journal, optionally sealing it with BLAKE3

Usage: cs journal end [OPTIONS]

Options:
  • --no-seal — Skip the BLAKE3 seal — ephemeral scratch close. By default the session body is sealed (mirrors prompt_seal / briefing_seals)

cs journal promote

Turn journal notes into spark molecules (via the session-to-spark tick)

Usage: cs journal promote [OPTIONS] [NOTE_TIMESTAMPS]...

Arguments:
  • <NOTE_TIMESTAMPS> — Note timestamp to promote (HH:MM:SS, optionally prefixed by <session_id>@ to disambiguate across sessions). Repeatable.

    When omitted, behaviour depends on --all-spark-prefix (default: on) and --dry-run.

Options:
  • --session <SESSION> — Session file stem (e.g. session-2026-04-22T10-31-31Z) or an absolute path. Defaults to the currently open session; if no session is open, defaults to scanning every session file
  • --all-spark-prefix — Promote every note whose body begins with !spark . Default behaviour when no explicit timestamps are passed; when timestamps ARE passed, this is additive (promote both the prefixed notes and the explicit ones)
  • --dry-run — Print what would be promoted without nucleating or writing sidecars. Forwarded to the tick script
  • --tick-script <PATH> — Override the tick script location. Defaults to walk-up discovery from $PWD looking for scripts/session-to-spark-tick.sh

cs journal route

Route journal notes through the Tier-1 regex classifier (ADR-072).

Walks a journal file, computes blake3(body) for each note, applies the Tier-1 cascade, writes a sidecar under .cosmon/state/journals/.route/<sid>/<body_hash>.json, and (when confidence warrants) nucleates a temp:proposed molecule via cs nucleate. Tiers 2–4 are future work; low-confidence notes are marked tier4_pending and escalate to the verdict-door.

Usage: cs journal route [OPTIONS] [SESSION]

Arguments:
  • <SESSION> — Session file stem (e.g. session-2026-04-22T10-31-31Z) or an absolute path. When omitted, defaults to scanning every session file if --all is passed, or the currently-open session otherwise
Options:
  • --all — Process every session file under .cosmon/state/journals/

  • --dry-run — Print what would be classified without writing sidecars or nucleating molecules

  • --no-stage — Skip auto-nucleation of high-confidence temp:proposed molecules — write sidecars only. Useful when backfilling or debugging

  • --max <MAX> — Cap sidecars emitted this run (safety net for batch backfills)

    Default value: 500

cs journal review

Review router-staged molecules (verdict-door).

Renders temp:proposed molecules as a markdown review file at .cosmon/state/journals/.review/<sid>.md, opens it in $EDITOR, and — on --apply — translates each verdict: line into a keep / dismiss / undo transition. Silent when nothing is pending (no editor opens). See ADR-072 §7.

Usage: cs journal review [OPTIONS] [SESSION]

Arguments:
  • <SESSION> — Session id (e.g. session-2026-04-22T10-31-31Z). When omitted, review every session that has pending staged molecules
Options:
  • --apply — Parse the previously-composed review file and apply the verdicts. Without this flag, the verb composes the markdown review file and opens it in $EDITOR
  • --editor <CMD> — Override the editor (defaults to $EDITOR, then vi). Ignored with --apply and with --json

cs sessions

Two agent sessions — a Claude and a Codex, or two of either — work the same mission on this machine. One holds the controls and may change the mission; the other reads the same material, compares, and advises, and can change nothing. Both see each other, can write to each other, and leave a hand-over note when they stop, so the next session resumes without re-reading the whole conversation.

Passing the controls is never automatic. A session may ASK for them; only you, the human, hand them over, by signing the request with your key. No quota, timeout or heuristic moves them.

The verbs come in the order you meet them: find a session (discover, show), take a seat (attach, list, peers), talk (send, inbox), hand over (checkpoint, drift, takeover). hook wires the routine ones into the agent itself, so they happen without being typed.

Usage: cs sessions <COMMAND>

EXAMPLES: cs sessions discover # provider sessions in this repo cs sessions discover --all --provider codex # every Codex session on the host cs sessions show claude:4940f28e --tail 5 # one session, named exactly cs sessions attach --role copilot --follow claude-sid
--as codex:0198aabb --capability observe cs sessions list --role primary # who holds a seat cs sessions peers # who is around me, and which way cs sessions send --to claude-sid --message 'that evidence ref is circular' cs sessions inbox # read and consume; --peek to look

HAND-OVER: cs sessions checkpoint publish --mission task-20260731-e4d0
--include 'the cockpit' --exclude 'the probe'
--next 'merge-strategy:deny=do not merge before the doc gate'
--evidence 'merge-strategy=docs/adr/168.md' cs sessions checkpoint list --mission task-20260731-e4d0 cs sessions drift claude-sid codex-sid --mission task-20260731-e4d0 cs sessions takeover show --mission task-20260731-e4d0 cs sessions takeover trust # which key may seat a pilot cs sessions takeover request --mission task-20260731-e4d0 --reason 'quota'

THE OPERATOR GESTURE (the part an agent cannot type for itself): cs sessions takeover challenge --mission task-20260731-e4d0 --request req-… --by emmanuel > takeover.txt minisign -Sm takeover.txt # your passphrase, your gesture cs sessions takeover grant --mission task-20260731-e4d0 --request req-… --by emmanuel --attestation takeover.txt.minisig

--by is a label; the signature is the authority. A grant with no valid attestation seats nobody — including one appended straight into the ledger, because every line is checked when it is read. Pin the public key at .cosmon/takeover.pub and commit it, so a swapped trust root is a diff.

WITHOUT TYPING ANYTHING (the hook, mission M6): cs sessions hook install --provider claude # .claude/settings.local.json cs sessions hook install --provider codex # ~/.codex/config.toml notify cs sessions hook status # wired? and what has it cost cs sessions checkpoint stage --mission task-20260731-0d49
--next 'gate:affirm=run just gates before done' cs sessions hook uninstall --provider claude # leaves no residue COSMON_COPILOT_HOOK_OFF=1 # quiet now, still wired

The hook pings presence, drains the mailbox where the pilot can read it and publishes a staged checkpoint at a transition. It never claims a seat and never writes a checkpoint's content: a hand-over record is the pilot's own words, and only its moment is the hook's.

The canonical name of a session is <provider>:<native-session-id>, and nothing else ever breaks a tie: a title, a cwd and a modification time help you recognise a session, never choose one. A selector that matches zero or two sessions prints the candidates and refuses.

Exit codes (drift, matching cs diverge): 0 AGREE — the compared positions match 1 FINDING — a decidable test fired, both sides cited 2 INCONCLUSIVE — not comparable; never rendered as agreement

Authority is a lease with an epoch (ADR-168 §D6). A co-pilot may observe, message and checkpoint; only the operator grants the controls, and no quota reading transfers them.

SEE ALSO: cs presence (the substrate), cs journal (operator carnet), cs pilot (cognitive REPL), cs diverge.

Subcommands:
  • discover — Which agent conversations exist on this machine, and the exact name to refer to one by
  • list — Which of them have taken a seat, and in which role
  • show — Look inside one conversation — its last events, read-only
  • attach — Take a seat: say "I am here, in this role". Until you do, the others cannot see you
  • peers — Who is seated around this session, and which way each one faces
  • send — Write one message to another session. Delivered, and consumed, once
  • inbox — Read the messages addressed to this session (--peek to look without consuming them)
  • checkpoint — Leave — or read — the note that lets someone else resume this mission
  • drift — Compare what two sessions concluded — AGREE, FINDING or INCONCLUSIVE, never a score
  • takeover — The controls: who may change the mission, who asked for them, and the signature that hands them over
  • hook — Wire the routine gestures — take a seat, read the mailbox, leave a note — into the agent itself, so they happen without being typed

cs sessions discover

Which agent conversations exist on this machine, and the exact name to refer to one by

Usage: cs sessions discover [OPTIONS]

Options:
  • --repo <PATH> — Repository whose sessions to show. Defaults to the repository the current directory is in. Resolved to an exact checkout — a worktree is never its canonical checkout (REPO-EXACT)
  • --cwd <PATH> — Show sessions whose recorded working directory is exactly this path
  • --all — Show every session every adapter can see, from any repository
  • --provider <NAME> — Restrict to one provider (claude, codex, …)

cs sessions list

Which of them have taken a seat, and in which role

Usage: cs sessions list [OPTIONS]

Options:
  • --galaxy <GALAXY> — Filter to one galaxy
  • --role <ROLE> — Show only pilots in this seat (primary or copilot)
  • --follows <SID> — Show only pilots co-piloting this session
  • --all — Include snapshots whose heartbeat has gone stale

cs sessions show

Look inside one conversation — its last events, read-only

Usage: cs sessions show [OPTIONS] <SELECTOR>

Arguments:
  • <SELECTOR> — The canonical selector, <provider>:<native-session-id>
Options:
  • --tail <N> — Print the last N normalised events (kinds and sizes — never content)

    Default value: 0

  • --no-read — Skip reading the log; show only what discovery already knows

cs sessions attach

Take a seat: say "I am here, in this role". Until you do, the others cannot see you

Usage: cs sessions attach [OPTIONS]

Options:
  • --role <ROLE> — Seat to take: copilot (default) or primary. A primary seat is checked against the mission's lease ledger and refused if it is not this session's to take

    Default value: copilot

  • --follow <SID_OR_SELECTOR> — The pilot this session is co-piloting — a cosmon session id, or a <provider>:<native-session-id> selector that a live pilot advertises

  • --session <SID> — This session's cosmon id. Defaults to $COSMON_SESSION_ID

  • --as <SELECTOR> — The provider session this pilot is driving, as a canonical selector. Equivalent to --provider + --native-session-id

  • --provider <NAME> — Provider half of this session's key, when not using --as

  • --native-session-id <ID> — Native id half of this session's key, when not using --as

  • --mission <MOLECULE_ID> — Mission this seat is about. Required for a primary seat

  • --epoch <N> — The lease epoch this pilot believes it holds. Required for a primary seat: a claim that names no generation is not a claim

  • --capability <TOKEN> — A capability this pilot advertises. Repeatable

  • --headline <HEADLINE> — One line describing what this pilot is doing

  • --galaxy <GALAXY> — Galaxy label to record

    Default value: cosmon

cs sessions peers

Who is seated around this session, and which way each one faces

Usage: cs sessions peers [OPTIONS]

Options:
  • --session <SID> — The session whose neighbourhood to show. Defaults to $COSMON_SESSION_ID
  • --all — Include snapshots whose heartbeat has gone stale

cs sessions send

Write one message to another session. Delivered, and consumed, once

Usage: cs sessions send [OPTIONS] --to <SID_OR_SELECTOR> --message <TEXT>

Options:
  • --to <SID_OR_SELECTOR> — Destination — a cosmon session id, or a selector a live pilot advertises
  • --message <TEXT> — The message. Stored content-addressed; the envelope carries its hash
  • --from <SID> — Sender session id. Defaults to $COSMON_SESSION_ID
  • --expires-in <SECONDS> — Seconds after which an unread envelope reads as expired rather than as a fresh instruction

cs sessions inbox

Read the messages addressed to this session (--peek to look without consuming them)

Usage: cs sessions inbox [OPTIONS]

Options:
  • --session <SID> — Mailbox to read. Defaults to $COSMON_SESSION_ID

  • --peek — Show pending envelopes without acknowledging them

  • --all — Include already-acknowledged envelopes

  • --follow — Keep reading, printing each envelope as it arrives, until interrupted

  • --interval <SECONDS> — Seconds between polls under --follow

    Default value: 2

cs sessions checkpoint

Leave — or read — the note that lets someone else resume this mission

Usage: cs sessions checkpoint <COMMAND>

Subcommands:
  • publish — Publish this pilot's hand-over record for a mission
  • stage — Write the same record as a draft, for the hook to publish at the next natural transition. Takes exactly the flags publish takes
  • list — List the checkpoints published for a mission
  • show — Show one checkpoint in full

cs sessions checkpoint publish

Publish this pilot's hand-over record for a mission

Usage: cs sessions checkpoint publish [OPTIONS] --mission <MOLECULE_ID>

Options:
  • --mission <MOLECULE_ID> — The mission being flown
  • --session <SID> — Publishing session. Defaults to $COSMON_SESSION_ID
  • --epoch <N> — The authority epoch the publisher believes it is under. Defaults to the epoch on its own presence snapshot, then to 0
  • --id <ID> — Identifier for this checkpoint. Defaults to a timestamped id
  • --include <TEXT> — Something this mission covers. Repeatable
  • --exclude <TEXT> — Something this mission explicitly does not cover. Repeatable
  • --hypothesis <CLAIM> — A position currently held, as SUBJECT[:affirm|deny]=STATEMENT. Repeatable
  • --next <CLAIM> — An intended next move, in the same SUBJECT[:STANCE]=STATEMENT form. Repeatable — this is the list a co-pilot's contradiction is found in
  • --done <TEXT> — Something already done, in the pilot's words. Repeatable
  • --risk <TEXT> — A known risk. Repeatable
  • --question <TEXT> — A question the pilot could not answer. Repeatable — this is where uncertainty belongs, never inside a stance
  • --evidence <SUBJECT=LOCATOR> — Evidence for one claim, as SUBJECT=LOCATOR[#DIGEST]. Repeatable
  • --checkpoint-evidence <LOCATOR> — Evidence for the checkpoint as a whole, as LOCATOR[#DIGEST]. Repeatable

cs sessions checkpoint stage

Write the same record as a draft, for the hook to publish at the next natural transition. Takes exactly the flags publish takes

Usage: cs sessions checkpoint stage [OPTIONS] --mission <MOLECULE_ID>

Options:
  • --mission <MOLECULE_ID> — The mission being flown
  • --session <SID> — Publishing session. Defaults to $COSMON_SESSION_ID
  • --epoch <N> — The authority epoch the publisher believes it is under. Defaults to the epoch on its own presence snapshot, then to 0
  • --id <ID> — Identifier for this checkpoint. Defaults to a timestamped id
  • --include <TEXT> — Something this mission covers. Repeatable
  • --exclude <TEXT> — Something this mission explicitly does not cover. Repeatable
  • --hypothesis <CLAIM> — A position currently held, as SUBJECT[:affirm|deny]=STATEMENT. Repeatable
  • --next <CLAIM> — An intended next move, in the same SUBJECT[:STANCE]=STATEMENT form. Repeatable — this is the list a co-pilot's contradiction is found in
  • --done <TEXT> — Something already done, in the pilot's words. Repeatable
  • --risk <TEXT> — A known risk. Repeatable
  • --question <TEXT> — A question the pilot could not answer. Repeatable — this is where uncertainty belongs, never inside a stance
  • --evidence <SUBJECT=LOCATOR> — Evidence for one claim, as SUBJECT=LOCATOR[#DIGEST]. Repeatable
  • --checkpoint-evidence <LOCATOR> — Evidence for the checkpoint as a whole, as LOCATOR[#DIGEST]. Repeatable

cs sessions checkpoint list

List the checkpoints published for a mission

Usage: cs sessions checkpoint list [OPTIONS] --mission <MOLECULE_ID>

Options:
  • --mission <MOLECULE_ID> — The mission whose checkpoints to list
  • --session <SID> — Show only what this session published

cs sessions checkpoint show

Show one checkpoint in full

Usage: cs sessions checkpoint show [OPTIONS] --mission <MOLECULE_ID>

Options:
  • --mission <MOLECULE_ID> — The mission the checkpoint belongs to
  • --id <ID> — The checkpoint id. Omit to take the latest published by --session
  • --session <SID> — The publishing session, when selecting by recency rather than by id

cs sessions drift

Compare what two sessions concluded — AGREE, FINDING or INCONCLUSIVE, never a score

Usage: cs sessions drift [OPTIONS] --mission <MOLECULE_ID> <SESSION_A> <SESSION_B>

Arguments:
  • <SESSION_A> — The first session
  • <SESSION_B> — The second session
Options:
  • --mission <MOLECULE_ID> — The mission both sides checkpointed

  • --checkpoint <latest> — Which checkpoint of each session to compare. Only latest is a selector; name an exact record with --checkpoint-a / --checkpoint-b

    Default value: latest

  • --checkpoint-a <ID> — Exact checkpoint id for side A

  • --checkpoint-b <ID> — Exact checkpoint id for side B

cs sessions takeover

The controls: who may change the mission, who asked for them, and the signature that hands them over

Usage: cs sessions takeover <COMMAND>

Subcommands:
  • show — Who holds the controls, at which epoch, and what has been asked
  • request — Ask for the controls. Writes a request and confers nothing
  • grant — Hand the controls over — your signature, which no agent can produce
  • challenge — Print the exact bytes an operator signs to authorise one transfer
  • trust — Show which operator key this galaxy trusts to authorise a transfer
  • check — Ask whether a session may pilot: the ledger's verdict, plus whether its seat would actually present that epoch. Exits 0 or 1

cs sessions takeover show

Who holds the controls, at which epoch, and what has been asked

Usage: cs sessions takeover show [OPTIONS] --mission <MOLECULE_ID>

Options:
  • --mission <MOLECULE_ID> — Mission whose lease to inspect
  • --history — Print every grant ever recorded instead of only the head

cs sessions takeover request

Ask for the controls. Writes a request and confers nothing

Usage: cs sessions takeover request [OPTIONS] --mission <MOLECULE_ID>

Options:
  • --mission <MOLECULE_ID> — Mission the controls are being asked for

  • --to <SID> — Session that would become PRIMARY. Defaults to the requester

  • --from <SID> — Session doing the asking. Defaults to $COSMON_SESSION_ID

  • --reason <TEXT> — One line the operator reads before deciding

    Default value: ``

cs sessions takeover grant

Hand the controls over — your signature, which no agent can produce

Usage: cs sessions takeover grant [OPTIONS] --mission <MOLECULE_ID>

Options:
  • --mission <MOLECULE_ID> — Mission whose controls are being handed over
  • --request <REQUEST_ID> — Request being answered. The holder is taken from the request
  • --to <SID> — Session to seat, when granting without a request
  • --ttl <SECONDS> — Seconds after which the lease authorises nothing
  • --by <NAME> — Operator identity to record. Defaults to $USER. Covered by the attestation, so it is a signed claim and not a free string
  • --attestation <PATH> — The operator's detached minisign signature over the challenge, or - for stdin. Required: --by is a label, the signature is the gesture
  • --sign-with <PATH> — The operator's minisign secret key. Folds challenge, signature and grant into this one command: the transfer is printed for you to read, minisign(1) asks for your passphrase, and no .minisig is left behind. cosmon still owns no signer — it relays to yours

cs sessions takeover challenge

Print the exact bytes an operator signs to authorise one transfer

Usage: cs sessions takeover challenge [OPTIONS] --mission <MOLECULE_ID>

Options:
  • --mission <MOLECULE_ID> — Mission whose controls would be handed over
  • --request <REQUEST_ID> — Request being answered. The holder is taken from the request
  • --to <SID> — Session that would be seated, when there is no request to answer
  • --ttl <SECONDS> — Seconds after which the lease would authorise nothing
  • --by <NAME> — Operator identity the grant would claim. Defaults to $USER

cs sessions takeover trust

Show which operator key this galaxy trusts to authorise a transfer

Usage: cs sessions takeover trust

cs sessions takeover check

Ask whether a session may pilot: the ledger's verdict, plus whether its seat would actually present that epoch. Exits 0 or 1

Usage: cs sessions takeover check [OPTIONS] --mission <MOLECULE_ID>

Options:
  • --mission <MOLECULE_ID> — Mission the gesture would touch
  • --session <SID> — Session issuing the gesture. Defaults to $COSMON_SESSION_ID
  • --epoch <N> — The epoch the caller believes it holds. Omitting it is itself a refusal

cs sessions hook

Wire the routine gestures — take a seat, read the mailbox, leave a note — into the agent itself, so they happen without being typed

Usage: cs sessions hook <COMMAND>

Subcommands:
  • install — Wire this pilot's provider to run the co-pilotage hook
  • uninstall — Remove the co-pilotage hook, leaving the rest of the file untouched
  • status — Report whether the hook is wired, and what it has cost
  • run — The hook body — invoked by the provider, not usually by a human

cs sessions hook install

Wire this pilot's provider to run the co-pilotage hook

Usage: cs sessions hook install [OPTIONS] --provider <NAME>

Options:
  • --provider <NAME> — The pilot whose configuration to wire: claude or codex
  • --settings <PATH> — The settings file to edit. Defaults to the provider's own — for Claude .claude/settings.local.json beside the current directory, for Codex $CODEX_HOME/config.toml or ~/.codex/config.toml
  • --cs-bin <PATH> — The cs binary the hook should invoke. Defaults to this executable
  • --dry-run — Print what would be written without writing it

cs sessions hook uninstall

Remove the co-pilotage hook, leaving the rest of the file untouched

Usage: cs sessions hook uninstall [OPTIONS] --provider <NAME>

Options:
  • --provider <NAME> — The pilot whose configuration to wire: claude or codex
  • --settings <PATH> — The settings file to edit. Defaults to the provider's own — for Claude .claude/settings.local.json beside the current directory, for Codex $CODEX_HOME/config.toml or ~/.codex/config.toml
  • --cs-bin <PATH> — The cs binary the hook should invoke. Defaults to this executable
  • --dry-run — Print what would be written without writing it

cs sessions hook status

Report whether the hook is wired, and what it has cost

Usage: cs sessions hook status [OPTIONS]

Options:
  • --provider <NAME> — Restrict the report to one provider
  • --settings <PATH> — The settings file to inspect, when it is not the provider's default
  • --session <SID> — The session whose cost ledger to summarise. Defaults to $COSMON_SESSION_ID

cs sessions hook run

The hook body — invoked by the provider, not usually by a human

Usage: cs sessions hook run [OPTIONS] --event <EVENT> [PAYLOAD]

Arguments:
  • <PAYLOAD> — The provider's payload. Codex passes it as this trailing argument; Claude pipes it on stdin, which is read when this is absent
Options:
  • --event <EVENT> — Which moment fired: session-start, turn-start or turn-end
  • --provider <NAME> — The pilot this hook runs inside. Inferred from the payload when it names one; claude otherwise
  • --session <SID> — This session's cosmon id. Defaults to $COSMON_SESSION_ID

cs inbox

Inbox — vertical pile of atomic actions awaiting operator decision (cs inbox)

Usage: cs inbox [OPTIONS]

EXAMPLES: cs inbox # vertical pile of atomic actions cs inbox --json # NDJSON: one row per actionable molecule

The pile has four buckets, top to bottom: ✓ completed (awaiting cs done) 🔥 temp:hot pending ❓ frozen (question from a worker) ⚡ signal molecules

Keys: j/k move · Enter open briefing · d done · t tackle · w whisper · c collapse · r reload · q quit. One panel, one stack — no graph viewer, no chat, no split, no editor, no dashboard, no search bar — the deliberate non-features.

Success metric: 5 days out of 7 without opening Claude Code to pilot cosmon. See docs/guides/inbox-trial.md.

SEE ALSO: cs ensemble (full backlog), cs peek (fractal TUI portal), cs journal (operator carnet that inbox reads as its sticky top line).

Options:
  • --refresh-ms <REFRESH_MS> — Refresh cadence in milliseconds. Inbox reloads the stack on each tick or on r/R. Default: 2000ms (gentler than peek's 250ms — inbox is a decision surface, not a watchdog)

    Default value: 2000

  • --json — Print the inbox contents as NDJSON and exit (agent-first). Skips the TUI entirely. One JSON object per actionable row plus one session envelope when an unsealed session exists

cs panel

Panel — convene a hash-pinned supermajority panel to gate a constitutional amendment

Usage: cs panel <COMMAND>

EXAMPLES: git diff main | cs panel convene # seat the panel from the staged diff cs panel convene --diff change.patch # seat from a diff file cs panel convene --diff change.patch --json # NDJSON for scripting cs panel decide --diff change.patch
--vote wheeler=approve --vote torvalds=refuse:breaks I1
--vote feynman=approve --vote shannon=approve
--vote jobs=approve --out panel.role-log.json # tally + inscribe role-log

Convene a hash-pinned supermajority panel to gate a constitutional amendment — anything operator-uncapturable, a forbid_operator_* lint, or a new operator_* field. The cost of amendment rises from O(1 PR) to O(panel convocation): what was legislative becomes constitutional.

A panel is a fixed constitutional CORE (default wheeler,torvalds,feynman, shannon) plus rotating SEAT(S) drawn from a POOL by hashing the diff. The rotating seat is a pure function of the diff, so the convener cannot pick a friendly judge after seeing the test (audience-after-the-test, delib 20260503-5a74). decide refuses ballots from non-panelists and refuses to rule until every seat has voted. Verdict needs a 4/5 supermajority (--rule).

EXIT CODES (decide): 0 approve, 2 refuse, 1 error.

SEE ALSO: cs notarize (operator Ed25519 attestation), cs witness (quorum seal).

Subcommands:
  • convene — Seat the panel deterministically from the artifact hash and print it
  • decide — Tally ballots from the seated panel, emit verdict, inscribe role-log

cs panel convene

Seat the panel deterministically from the artifact hash and print it

Usage: cs panel convene [OPTIONS]

Options:
  • --core <CORE> — Comma-separated constitutional core (always seated)

  • --pool <POOL> — Comma-separated rotation pool (hash-pinned seats drawn from here)

  • --seats <SEATS> — Number of rotating seats filled from the pool by the diff hash

    Default value: 1

  • --rule <RULE> — Supermajority rule as NUM/DEN (default 4/5)

    Default value: 4/5

  • --diff <PATH> — Path to the artifact (e.g. PR diff). Reads stdin when omitted

  • --artifact-hash <HEX> — Use a precomputed artifact hash (64-char hex) instead of hashing bytes

cs panel decide

Tally ballots from the seated panel, emit verdict, inscribe role-log

Usage: cs panel decide [OPTIONS]

Options:
  • --core <CORE> — Comma-separated constitutional core (always seated)

  • --pool <POOL> — Comma-separated rotation pool (hash-pinned seats drawn from here)

  • --seats <SEATS> — Number of rotating seats filled from the pool by the diff hash

    Default value: 1

  • --rule <RULE> — Supermajority rule as NUM/DEN (default 4/5)

    Default value: 4/5

  • --diff <PATH> — Path to the artifact (e.g. PR diff). Reads stdin when omitted and no --artifact-hash is given

  • --artifact-hash <HEX> — Use a precomputed artifact hash (64-char hex) instead of hashing bytes

  • --vote <PERSONA=VOTE[:REASON]> — A ballot, repeatable: persona=approve / persona=refuse[:reason]

  • --out <PATH> — Where to inscribe the role-log JSON. Defaults to stdout (with --json) or no file (human mode prints a summary). Use - for stdout

cs notify

Notify — push a one-line message to every configured operator channel

Usage: cs notify [OPTIONS] <MESSAGE>

EXAMPLES: cs notify "v1.2.1 tenant-demo deploy ok" # default channels cs notify "worker quartz silent 240s" --level warn --molecule cs-20260426-a7e6 cs notify "hello" --channel macos --channel file-drop # override channels cs notify "automata gen 4096" --channel telegram # Telegram DM cs notify "dry test" --dry-run # don't dispatch

Pushes one line to every channel in [notify].channels of .cosmon/config.toml (macos | file-drop | element | telegram). Best-effort: a single channel failure is logged but the others still fire. Closes the silent-24h gap by giving the fleet a primitive to reach the operator's attention surface.

Arguments:
  • <MESSAGE> — The notification message (positional, single line)
Options:
  • --title <TITLE> — Optional title prefix. Channels render it as the first line / header

    Default value: cosmon

  • --channel <CHANNEL> — Override the configured channel set. May be repeated. Recognised values: macos, file-drop, element, telegram. When omitted, every channel declared in .cosmon/config.toml is used

  • --molecule <MOLECULE_ID> — Optional molecule id the notification is about. Surfaces in the JSON output and the file-drop body

  • --level <LEVEL> — Severity tag (advisory). One of info, warn, alert. Channels that support it (file-drop) pass it through; others ignore

    Default value: info

  • --dry-run — Treat dispatch as a dry-run: log what would be sent without invoking any side-effecting transport. Equivalent to setting COSMON_NOTIFY_DRY_RUN=1

cs opt-in-share

Opt-in-share — first-run consent prompt for encrypted developer bundles

Usage: cs opt-in-share [OPTIONS]

EXAMPLES: cs opt-in-share # first-run prompt (once per user) cs opt-in-share --status # show current consent state cs opt-in-share --decline # non-interactive: record decline cs opt-in-share --accept # non-interactive: record acceptance cs opt-in-share --json # NDJSON output for scripting

Deny-by-default. The first time cs init runs interactively, this prompt fires automatically (once) and the answer is persisted to ~/.config/cosmon/consent.toml. No trace in your project's git log.

The French prompt names the encryption (age), the sole recipient (the Noogram maintainer), and the no-trace-in-commits guarantee, then asks [o/N]. Anything but an explicit yes is recorded as a decline.

The question is asked only where an answer can arrive: stdin AND stdout must both be terminals. A captured stdout (CI, scripts, OUT="$(cs ...)") records a decline without asking and says so on stderr. cs tackle never asks — nothing on the dispatch path may block on a human (ADR-163).

SEE ALSO: cs init (the first-run hook site).

Options:
  • --status — Print the current consent state (accepted / declined / none) and exit
  • --decline — Bypass the TTY prompt and persist a declined record (non-interactive)
  • --accept — Bypass the TTY prompt and persist an accepted record (non-interactive)

cs demo

Demo — one-command end-to-end chatbot surface (first-contact experience)

Usage: cs demo [OPTIONS]

EXAMPLES: cs demo # interactive prompt → full cycle cs demo --prompt "Implement X" # skip TTY, classify as task-work cs demo --formula deep-think --prompt "Is X viable?" cs demo --adapter llama-cpp --prompt "Hello, world" # route through llama.cpp cs demo --no-teardown # leave worktree intact for inspection

Runs nucleate → tackle → wait → done in one shot. All artefacts persist.

The --adapter flag is threaded to cs tackle so the demo cycle exercises any registered Adapter (claude, aider, openai-chat, llama-cpp, …). Per ADR-106 the legacy alias llama canonicalises to llama-cpp at the CLI seam — both invocations route to the same in-process adapter.

Options:
  • --prompt <PROMPT> — Skip the interactive prompt; use this text as the demo input

  • --formula <FORMULA> — Force a specific formula instead of auto-classifying.

    The named formula must already exist under .cosmon/formulas/. No new formulas are registered by cs demo.

  • --no-teardown — Skip the final cs done teardown — useful for debugging.

    When set, the molecule remains Completed (or Collapsed) but its worktree, tmux session, and fleet worker are left intact for post-mortem inspection.

  • --timeout <TIMEOUT> — Maximum seconds to wait for the molecule to reach a terminal state.

    Mirrors the cs wait --timeout default so cs demo does not silently allow a runaway demo to hang the operator's terminal.

    Default value: 600

  • --adapter <NAME> — Worker-Spawn Port Adapter to dispatch (ADR-079 / ADR-097 / ADR-106).

    Mirrors cs tackle --adapter: when set, the value is threaded through to the cs tackle invocation that cs demo spawns under the hood, so the demo cycle can exercise any registered Adapter (e.g. llama-cpp, claude, aider, openai-chat). Optional — the default resolution path (.cosmon/config.toml::[adapters.default] → built-in BUILTIN_FLOOR_ADAPTER, currently "local", the Ollama-backed in-process loop — never Claude) is preserved when the flag is omitted.

    Per ADR-106 the canonical name for the in-process llama.cpp adapter is llama-cpp; the legacy alias llama is accepted at the CLI seam (canonicalises via cs tackle's validate_adapter_name).

  • --model <MODEL_ID> — Model to run, threaded verbatim to cs tackle --model (COSMON #23).

    For the default local adapter this is the Ollama model tag, e.g. --model qwen2.5:32b or --model llama3.2:3b. It must already be pulled (ollama pull <id>); the dispatch preflight refuses rather than collapsing a molecule against a model the daemon cannot serve.

    Precedence for the local adapter, highest first: this flag → formula-step model = pin → [adapters.local].default_model in .cosmon/config.tomlCOSMON_LOCAL_MODEL → the built-in default qwen3:8b. Every local dispatch prints the model it resolved and its origin on stderr, so the effective choice is never a guess. Point the adapter at another daemon with [adapters.local].base_url, COSMON_LOCAL_BASE_URL, or the native OLLAMA_HOST. Full guide: docs/guides/local-model-selection.md.

cs whisper

Whisper — inject a perturbation payload into a live worker's tmux pane (v0)

Usage: cs whisper [OPTIONS] [MOLECULE_ID]

EXAMPLES: cs whisper --message "check the latest ADR before merging" cs whisper --file hint.md echo "nudge" | cs whisper --stdin cs whisper --message "…" --dry-run # validate, do not paste

Experimental v0. Perturbation port, not a control-plane event. Refuses unless the target pane's foreground command is in [whisper] allowed_commands (default: ["claude"]).

Arguments:
  • <MOLECULE_ID> — Molecule whose worker pane will receive the whisper.

    Optional because --to-session is an alternative destination; enforced at runtime so clap's error text points at the mutual exclusion rather than an unsatisfied positional.

Options:
  • --to-session <SID> — Target a Claude session by id — appends one line to .cosmon/state/presence/<sid>.log instead of pasting into a tmux pane. Mutually exclusive with the positional <molecule_id>.

    CEILING: whispers accumulate in the log; beyond ~10 per session the signal drowns in the tail. Past that, fall back to cs drop / cs tail.

  • -m, --message <TEXT> — Inline payload. Mutually exclusive with --file / --stdin

  • -f, --file <PATH> — Read payload from a file. Mutually exclusive with --message / --stdin

  • --stdin — Read payload from stdin (conventional -). Mutually exclusive with --message / --file

  • --dry-run — Validate and log the payload without actually pasting into tmux.

    In --to-session mode, skips the append (and the seek bump) — useful for CI-style sanity checks.

Formula reference

These commands use physics-inspired names (nucleate, evolve, decay, spore, …). New to the vocabulary? See The physics vocabulary.

A formula is a TOML template that defines a workflow: the ordered steps a molecule advances through, its kind prefix, and (for decomposition formulas) the child molecules it nucleates. Formulas are the only extension point; you extend cosmon by writing a formula, not by adding a command.

This page is a hand-written stub (ADR-B1′ open-Q4). The formula schema is stable enough to document by hand today; a future revision may generate it from the formula type via schemars. It is covered by the link check, not the generated golden diff.

Where formulas live

Formulas are discovered from .cosmon/formulas/*.formula.toml in the galaxy (walk-up from the worker's worktree, same as every cs command). cs nucleate <formula> looks the name up there.

For the catalog of formulas cosmon ships — which ones cs init writes into that directory for you, and which ones you copy in from the repository — see the Formula catalog.

Anatomy of a formula

formula = "task-work"          # the name passed to `cs nucleate`
version = 1
description = """
Human-readable summary rendered into briefing.md.
"""
id_prefix = "task"             # molecule ids become task-YYYYMMDD-xxxx

# Optional. What these steps need of the worker that runs them.
requires_capabilities = ["shell", "vcs"]

[tier]
level = 0                       # 0 = leaf (no child nucleation)

[[steps]]
id = "implement"
title = "Implement the solution"
description = "What the worker does in this step."
acceptance = "The exit criterion the step must meet before advancing."

[[steps]]
id = "verify"
title = "Verify and validate"
description = "..."
acceptance = "cargo check + test + clippy + fmt all pass"
FieldRole
formulaThe name cs nucleate <name> resolves.
versionSchema/version of this formula.
descriptionRendered into the molecule's briefing.md.
id_prefixPrefix of every molecule id nucleated from this formula.
[tier] level0 = leaf (no children); higher tiers may decompose.
[[steps]]Ordered steps. Each cs evolve advances one step.
steps.acceptanceThe exit criterion sealed into briefing.md per step.
requires_capabilitiesOptional. Worker faculties these steps need: shell, vcs, cs-cli.

requires_capabilities

A formula whose steps are shell work — run the gate toolchain, execute a producer script, resolve a merge conflict — cannot be satisfied by a chat-only adapter, however carefully its prompts are worded. Declaring the requirement makes cs tackle refuse the pairing up front (exit code 17) instead of spending a run on a mission that could never complete: no worktree, no pane, no model call, and the molecule stays pending and re-tacklable.

Today the split is exactly chat-loop versus coding agent — a local adapter (local / ollama / llama-cpp / llama) has none of the three, every other adapter has all three. The field is opt-in: a formula that omits it dispatches everywhere it did before. An unrecognised token fails the formula load rather than being ignored, because a silently-dropped requirement is a formula claiming a gate it does not enforce.

COSMON_SKIP_CAPABILITY_GATE=1 dispatches anyway, for an operator deliberately experimenting on the local floor.

Variables

cs nucleate <formula> --var topic="…" binds template variables. Each variable is rendered into prompt.md (sealed at nucleation) and made available to the step descriptions.

Decomposition formulas

A formula whose steps nucleate child molecules (e.g. deep-think step 4, mission-controller decompose) must tag each child temp:warm immediately after nucleation: preventive backlog curation. See the temperature-tag how-to and the composability principle in the project CLAUDE.md.

  • cs nucleate: create a molecule from a formula.
  • cs evolve: advance a molecule one step.
  • cs spore: germinate a whole polymer from a shareable spore.toml template.

Formula catalog

These commands use physics-inspired names (nucleate, evolve, decay, spore, …). New to the vocabulary? See The physics vocabulary.

Formulas: the only extension point says what a formula is; the Formula reference gives the schema you write one against. This page answers the third question: which formulas do you already have?

Two sets, and the difference matters:

  • Built-in formulas are compiled into the cs binary. cs init writes them into .cosmon/formulas/, so cs nucleate <name> resolves on the very first invocation of a brand-new project.
  • Repository formulas live in the cosmon source tree only. They are not in the binary, so cs nucleate will not find them until you copy the .formula.toml into your own .cosmon/formulas/.

The Tier column is the [tier] level field. Tier 0 is a leaf: it runs its steps and completes, never creating child molecules. A higher tier may decompose — its steps nucleate children, and the ordinal guard requires each child's tier to sit strictly below its parent's.

Built-in formulas

These nine arrive with every cs init.

FormulaWhat it's forTier
task-workExecute one concrete engineering task: implement, then verify against the project's build/test/lint gates. The default for code.0
editorial-workThe prose counterpart of task-work: draft, then verify. For deliverables that are a document rather than compiled code, where the exit criteria are editorial, not a compiler.0
deep-thinkStructured multi-perspective deliberation. Frames a question, runs a panel of expert personas in parallel, synthesizes convergences and divergences, then nucleates the follow-up work the panel identified.1
deep-think-inlineThe same panel, run inline by a single worker, producing a synthesis and a recommendation but never nucleating children. The leaf variant a Tier-1 controller can commission without violating the tier guard.0
idea-to-planTake a raw idea through capture and feasibility assessment, then turn it into a small, finite set of actionable child molecules.1
mission-planCompile a goal plus a fleet template into a DAG of task molecules assigned to fleet roles. Completes once the decomposition is done.1
mission-controllerA mission planner that persists. It freezes after decomposing rather than completing, and downstream agents thaw it to feed results back and spawn new work across the mission's lifetime.1
temp-reviewSweep the backlog: scan every pending molecule, triage it by age and temperature tag, and report the backlog's shape. See Curate the backlog with temperature tags.0
verify-surfaceRender a visual surface and observe it from an independent molecule. Built in because the surface_visual gate refuses cs complete until a sibling verify-surface has landed green — a project without this formula could not satisfy the refusal.0

Repository formulas

These ship in the cosmon repository under .cosmon/formulas/, but not in the binary. Copy the file into your project's .cosmon/formulas/ before nucleating it. They are listed here because they are general-purpose; the repository also carries formulas wired to cosmon's own maintenance workflow, which are deliberately out of scope for this catalog.

FormulaWhat it's forTier
producer-workBuild a runner, pipeline, harness, or ingester — anything whose promised value is an output record. Adds a smoke-dispatch gate that executes the real production path and refuses to advance unless it leaves a non-empty output artifact. Compilation and unit tests cannot establish that a producer produced.0
bug-closureAfter a fix lands, walk the bug's whole semantic surface — help text, tests, docs, callers, invariants — and return a verdict: closed, or reopened naming the surfaces still uncovered. The companion ritual that stops a verb being repaired one half at a time.0
merge-conflictResolve a merge conflict on a feature branch as a typed molecule, with a bounded retry count instead of unbounded escalation.0
visual-qaThe gate for deliverables that are seen rather than compiled — decks, posters, rendered diagrams. Renders, rasterises, reads the pixels, runs an adversarial layout checklist, and fails closed. Neither task-work nor editorial-work ever looks at the rendered page.0
fleet-reviewRead the event log and molecule state over the last N days, compute vital signs (collapse rate, duration per step, backlog pressure), and emit a health report. Observation only: no suggestions, no config changes.0
retrospectiveRead the event log, ensemble snapshot, and patrol diagnostic; classify deviations into typed dysfunctions; and propose each fix as a temp:warm child for human triage. Proposes, never auto-fixes.1
mapThe fan-out pattern: apply a per-item formula to each element of a collection, nucleating N children in parallel.1
reduceThe fan-in counterpart of map: consolidate N children's outputs into a single synthesis, ordered behind them on the DAG.0
whileThe iteration pattern: nucleate a body formula repeatedly until a condition holds or max_iterations is exhausted, recording each turn of the loop as a DAG edge.1
sparkCapture a one-line intent as an untackled molecule on the backlog, with no worktree and no worker. The formula companion to the cs spark verb.0

map, reduce, and while are worth reading together: they are cosmon's demonstration that control flow needs no new machinery. Each is a plain TOML formula over cs nucleate --blocked-by, not a new molecule kind and not a new Rust type.

Writing your own

None of these is privileged. A formula is a TOML file you drop into .cosmon/formulas/, and cs nucleate resolves it by walk-up exactly as it resolves the built-ins — see the Formula reference for the schema. Starting from the closest formula here and editing it is usually faster than starting from the schema.

See also

Exit codes & JSON output

These commands use physics-inspired names (nucleate, evolve, decay, spore, …). New to the vocabulary? See The physics vocabulary.

Every cs command is scriptable: it returns a typed exit code and, with --json, machine-readable output. This page is the contract a worker or external scheduler branches on.

This page is hand-written (it documents runtime behaviour, not a command signature) and is covered by the command-name grep + link check, not the generated golden diff. See the CLI overview for the generated command pages.

The --json convention

--json is accepted on every command (an agent-first interface). Human output goes to stdout as a rendered view; --json replaces it with JSON: one object, or NDJSON (one object per line) for list-shaped commands. Errors under --json are emitted to stderr as {"error": "<message>"}; the exit code still carries the typed reason.

Exit codes

CodeMeaning
0Success.
1Generic failure (an unclassified error; the message is on stderr).
2A session is already open (cs journal start when one is live).
3No open session (cs journal note/end with nothing to write to).
10Guard refusal: missing parent link (a decay/merge child lacks its typed edge back to the parent).
11Guard refusal: a decay produced a homogeneous count that the type-tightening guard rejects.
12Guard refusal: dirty-backlog runtime refusal (a greedy runtime would resurrect stale pendings; ADR-048).
13Guard refusal: broker-spawn refusal (a self-referential spawn the Gödel guard forbids).
14Guard refusal: decomposition depth-limit exceeded (the Gödel depth guard).
15Guard refusal: governance tier does not descend (ordinal stratification: a child may not out-rank its parent).
16Guard refusal: briefless dispatch (cs tackle on a molecule whose formula's required, default-free variables are missing or blank — a worker would spawn with no Mission).
17Guard refusal: the formula requires worker capabilities the resolved adapter lacks (requires_capabilities = ["shell", …] on a chat-only local adapter). Re-run with a coding-agent --adapter, or set COSMON_SKIP_CAPABILITY_GATE=1.

Codes 10 to 17 are the typed CLI guard refusals: a script can branch on the specific invariant that fired rather than treating every non-zero exit as the same failure. Codes 2 to 3 are the session-carnet guards. Any other error falls through to the generic 1.

16 and 17 are additionally the permanent refusals: unlike the others, an identical retry reproduces them exactly, so the resident runtime (cs run) parks such a molecule rather than re-dispatching it every tick. A non-zero permanently_parked in the run summary counts them.

Example

$ cs decay <mol> --into 1        # homogeneous count → guard refusal
cs: decay would produce a homogeneous 1-child result …
$ echo $?
11

The physics vocabulary

Cosmon names its commands after physics: you nucleate a molecule, evolve it one step, let it decay into children, freeze and thaw a worker. This page is the one place the metaphor is explained in full. Every generated Reference page links back here through a banner, and every tutorial glosses a term the first time it appears, but the why lives here, once.

Why physics names

A unit of tracked work in cosmon really does behave like a physical object. It is created out of a template, it changes state one step at a time, it can be suspended and later resumed, it can split into smaller pieces, and when it is finished it leaves a trace on disk that you can inspect long after. Those are the same verbs physics uses for a particle: create, evolve, freeze, decay, observe. So instead of inventing bland words like create-task and advance-task, cosmon borrows the words that already fit, and the borrowed word carries an intuition that transfers for free. When you read decay, you already expect "one thing becomes several," and that is exactly what it does.

The names are the model, not decoration. This is the important part. The command names are how cosmon describes what a piece of work is. You cannot strip the metaphor out and keep the meaning, because the meaning is the metaphor. That is why the vocabulary is taught, not hidden away in an appendix.

Naming, not physics. One honest caveat: cosmon borrows physics words, not physics equations. Early design notes tried to run real thermodynamic formulas (free energy, Carnot cycles, three "laws of cosmon thermodynamics") and those were later demoted as cargo cult: they made no prediction that would fail if the numbers were wrong. What survives is genuine on its own (a token budget is a real resource tracker; worker-status entropy is a real Shannon measure of how spread out the fleet's states are). So read the vocabulary as a naming scheme with good intuitions, not as a claim that a molecule obeys Schrödinger's equation.

Two registers

Not every command has a physics name, and that is deliberate. Cosmon's verbs split into two registers:

  • Lifecycle verbs (physics register): nucleate, evolve, complete, collapse, decay, freeze, thaw, merge. These act on a molecule's state and follow the physics model above.
  • Operator verbs (vernacular register): tackle, done, wait, peek, patrol, run, reconcile. These are the human's toolkit for steering the fleet. They are plain CLI words on purpose: peek is your window into the system, not a physics act on a molecule.

The split resolves what looks like inconsistency. nucleate is physics because it transforms a molecule; peek is vernacular because it is you looking. Once you know which register a verb lives in, the naming stops feeling arbitrary.

The core glossary

TermWhat it means in cosmon
moleculeThe fundamental unit of tracked work: one running instance of a formula, bound to a task. It has a state (Active / Frozen / Completed / Collapsed), a current step, and a durable trace on disk.
formulaThe recipe a molecule follows: a TOML template of ordered steps with exit criteria. A formula is a template; a molecule is the running instance of it.
nucleateCreate a new molecule from a formula. Pure creation; nothing runs yet.
evolveAdvance a molecule one step along its formula, recording evidence. On the last step it auto-completes.
completeMove a molecule from Active to Completed. Idempotent; running it twice is the same as once.
collapseTerminate a molecule permanently, recording a final reason. Cannot be undone by complete.
decayOne molecule spawns N child molecules mid-flight (e.g. a plan splitting into tasks). The parent does not block on them.
mergeCombine several molecules' outputs into one synthesis.
freeze / thawSuspend a worker with its state preserved / resume it later.
ensembleThe whole fleet of molecules and workers, seen at a glance (cs ensemble).
workerA running agent instance bound to a molecule: a process in a tmux pane. Ephemeral; the molecule's state on disk outlives it.
sporeA shareable template of an entire wired DAG of molecules (formulas + fleet config + a proof), not just one. It germinates into a running polymer. Where a formula nucleates one molecule, a spore germinates the whole set.
polymerThe running DAG of linked molecules a spore germinates into, also called a mission.
tackle / doneStart a worker on a molecule / tear it down after merging its branch. Operator verbs, not physics.
peekThe operator's TUI window into the fleet. Vernacular.

If you come from knowledge representation, this table is cosmon's domain ontology in Gruber's sense — an explicit specification of a conceptualization: a controlled set of entity types (molecule, formula, worker, spore, polymer) and the generative relations between them (nucleate, germinate, decay, merge).

The template/instance table

The clearest way to see how formula, molecule, spore, and polymer fit together is a two-by-two:

template (immutable)instance (lives / dies)
one unitformulamolecule
whole DAGsporepolymer / mission

The verb for the top row is nucleate (formula ─nucleate→ molecule); the verb for the bottom row is germinate (spore ─germinate→ polymer). Same generative relation, one scale up.


For the full command reference grouped by role, see the CLI overview. For the honest record of which physics metaphors were kept and which were demoted, see the design-phase appendix in the repository (docs/appendix-physics-inspiration.md).

Noogram & the Cosmon kernel

Noogram is the distribution; Cosmon is its kernel.

That one sentence is the whole relationship. This page unpacks it: what a distribution is, what the kernel is on its own, and why "kernel" is the right word.

What Noogram is: the distribution

Noogram is an open-source distribution for composing, piloting, and auditing missions you hand to AI systems. A distribution is not a single tool; it is a curated whole built around a core: the kernel, plus the adapters that let it drive different agentic systems, the fleets that run many agents together, the spores that package whole mission shapes, and the pilot surfaces you watch it through. Noogram is the larger system: the place where work is delegated to AI, wired together, watched over, and later reviewed with its full reasoning intact.

What Cosmon is: the kernel

Cosmon is the kernel: the load-bearing core, and the subject of most of this book. It is the part you install today: a stateless command-line tool that gives AI agents an identity (this worker, on this task), a typed lifecycle (work moves through well-defined states, and only valid transitions are allowed), and crash-recovery (state lives on disk, so a crashed agent resumes rather than restarts). No daemon, no server, no scheduler: just a binary and a directory of files.

The kernel runs fully standalone. You do not need the Noogram distribution to get value from Cosmon. If all you ever want is to run several AI coding agents in parallel on one codebase and keep track of who is doing what, Cosmon does that fully, by itself. It is not a trial edition or a client stub. Like SQLite, it is complete on its own and embeddable in something larger; both readings are true at once.

The analogy: a kernel and its distribution

The cleanest way to see the relationship is the one the words already name: a kernel and the distribution built around it.

The Linux kernel is a complete, load-bearing core. Debian and Ubuntu are distributions that compose that kernel with everything a usable system needs. The kernel runs without the distribution: it is not incomplete; the distribution is a convenience built on top, not a requirement. Cosmon is the kernel; Noogram is the distribution built around it. Adopt the kernel alone and it is complete. Add the distribution and the kernel becomes the core inside it: the part that handles identity, lifecycle, and recovery while the larger system composes, pilots, and audits missions around it.

"Kernel" means exactly this: the essential core others build upon, that also stands on its own.

Boundary honesty

A few deliberate limits on how this page talks:

  • No private names. Cosmon and Noogram are attributed to Noogram (noogram.org) and to no one else — no other organization or individual name appears here.
  • Mechanism over adjectives. Cosmon earns its description by what it does (identity, typed lifecycle, crash-recovery), not by adjectives like "powerful" or "revolutionary."
  • The distribution does not complete the kernel. Naming Cosmon a "kernel" must never be read as "Cosmon needs Noogram to be useful." It does not; the disarm is written into the analogy above, not left to inference.
  • No claim of a running autonomous engine. Today Cosmon is a stateless, one-shot CLI: it does not run itself. A resident runtime that walks work unattended is on the roadmap (see The three regimes), not something shipping finished. This page will not imply otherwise.
  • The lineage claim travels with the reader, not the stranger. "Kernel of Noogram" is a crisply falsifiable statement, and it belongs where the reader has already run cs and can see Cosmon standing on its own. It carries no outbound link while the public Noogram site is not yet live; a dead link would refute the claim on first contact. The sentence and any link to it go public together, gated on the site actually resolving, not on a date.

For the physics vocabulary that names cosmon's commands, see The physics vocabulary. For the design bet underneath the "kernel," see Why a stateless CLI. For the seam that lets one kernel drive many agentic systems, see Agent adapters.

Why a stateless CLI (no daemon)

These commands use physics-inspired names (nucleate, evolve, decay, …). New to the vocabulary? See The physics vocabulary.

Most orchestration tools are a server you run. There is a scheduler process, a database process, maybe a message broker, and your tasks live inside them. If that process dies, or you did not start it, nothing works. Cosmon takes the opposite bet: there is no process in the loop. The cs binary is a one-shot tool, like git. You run it, it reads some files, changes them, and exits. When it is not running, cosmon is just a directory of JSON files sitting on disk.

What "stateless" actually means here

Every cs command is discrete: read state, mutate, write, exit. Nothing lingers. There is:

  • No daemon: no background process that has to be alive for the system to work.
  • No database server: the local registry is embedded SQLite, a library linked into cs, not a server you start. (JSON files on disk remain the source of truth.)
  • No scheduler process: cosmon does not own a clock. A human at a terminal, a cron job, or a shell loop drives it.

The source of truth is the filesystem. A molecule's authoritative state is a state.json file; its history is an append-only events.jsonl; its proof-of-work is a handful of tracked markdown files. You can read all of it with cat, jq, and git diff. Nothing is hidden inside a running server's memory.

Why this is the whole wedge

Temporal, Airflow, and Prefect orchestrate functions: deterministic code that runs, returns, and is forgotten. Cosmon orchestrates entities with identity and state: AI agents that crash, lose their context window, and need to resume as the same worker on the same task. That difference is why the stateless design is the point, not a limitation.

  • It survives crashes by construction. If state lived in a running process's RAM, a crash would lose it. Because state is on disk after every command, a crash loses nothing; you re-run the next cs command and it picks up exactly where the files say you were. (See Crash recovery.)
  • It needs no broker. Molecules do not talk through mailboxes or queues. Ordering flows through typed links on disk; content flows through shared files. (See Control plane vs data plane.)
  • It composes with any scheduler. Because cs is just a binary, you can drive it from cron, launchd, a Makefile, a CI job, or your own hands. Cosmon does not fight your infrastructure because it has no infrastructure to defend.
  • It is git-composable. State on disk means state in git. A molecule's trace is a diffable, mergeable, revertable set of files.

For a team running three to ten AI agents on a single codebase, this is radically simpler than any cluster-based alternative. There is nothing to deploy, nothing to keep alive, nothing to page you at 3am when it falls over, because there is no it, only files and a binary you invoke.

The two layers

Cosmon is honest that a long-lived orchestrator is sometimes useful: walking a large DAG of dependent work without a human tending each step. So the architecture reserves room for one, as a strictly optional second layer:

  1. Transactional Core (today). The stateless CLI. Every cs command you can run now. Files on disk are the truth. Never a daemon.
  2. Resident Runtime (optional, additive). One long-lived process (cs run) that polls the on-disk state and dispatches ready work through the same commands a human would type. It is a client of the core, not a replacement. It owns no private state; kill it and restart it and it rebuilds everything from disk.

The inviolable rule is that Layer B never becomes the only path to anything. Every capability is reachable from the plain CLI, human-driven. The runtime is pure convenience layered on top of a system that works fully without it. That discipline is what keeps the crash-recovery guarantee true: you can always cat cosmon's state, because there is never a process that holds truth the files do not.

See Architecture: the two layers for how this maps onto the crate structure, and The three regimes for the clock-and-observer model that formalizes when each layer is in charge.

Formulas: the only extension point

A formula is the recipe a molecule follows. It is a TOML template of ordered steps, and it is the one way you extend cosmon. This page says what a formula is and why it is the only extension point; for the full field table, it hands you off to the Formula reference.

Template and instance

A formula is a template; a molecule is one running instance of it. The formula is immutable text on disk: the same task-work.formula.toml describes every task molecule ever nucleated from it. The molecule is the thing that lives and dies: it has a state, a current step, and a durable trace of what happened. Writing the formula does not run anything; cs nucleate <formula> stamps out a molecule that does.

The relation is exactly the one the glossary draws for the whole vocabulary; see the template/instance table in The physics vocabulary. formula ─nucleate→ molecule is the single-unit case; a spore germinating a polymer is the same relation one scale up.

Why formulas are the only extension point

You extend cosmon by writing a formula, not by adding a command, a daemon, a plugin interface, or a new state store. Everything cosmon tracks is a molecule, and every workflow is a formula over molecules. A bug report, a design decision, a multi-perspective deliberation, a backlog sweep: each is a molecule running some formula. This is the composability principle: one concept, and the extension surface is the formulas you write on top of it.

The discipline that follows: before reaching for new machinery, ask whether the thing can be a formula over existing molecules. It almost always can. A formula whose steps exist only to satisfy the system (a single trivial step wrapping one command) is the signal that the abstraction is being over-applied, not that cosmon needs a new primitive.

Anatomy at a glance

A formula names itself, declares an id prefix for the molecules it produces, and lists ordered steps with exit criteria:

formula = "task-work"
id_prefix = "task"

[tier]
level = 0            # 0 = leaf; higher tiers may nucleate children

[[steps]]
id = "implement"
title = "Implement the solution"
acceptance = "Implementation complete, compiles clean"

[[steps]]
id = "verify"
title = "Verify and validate"
acceptance = "cargo check + test + clippy + fmt all pass"

Each cs evolve advances the molecule one step and seals that step's acceptance criterion into its briefing. The full field table (version, [tier] level, variables, per-step fields) lives in the Formula reference.

Decomposition formulas

A formula whose steps nucleate child molecules (a plan splitting into tasks, a deliberation fanning out into follow-ups) is a decomposition formula. Its higher [tier] level says it may produce children rather than just advance itself. Such a formula must tag each child as it creates it, so no spawned molecule sits untagged on the backlog; see Curate the backlog with temperature tags.

See also

Agent adapters: a harness over harnesses

Cosmon does not replace the agentic systems you already use. It sits above them. An adapter is the plug that names which system actually does the work: Claude Code, aider, codex, an OpenAI or Anthropic endpoint, llama-cpp, a local model. Cosmon is a harness over harnesses: it gives a piece of work an identity, a lifecycle, and crash-recovery, then hands the actual agent loop to whichever harness you picked.

What an adapter is

When you cs tackle a molecule, cosmon creates the worktree, the tmux pane, and the fleet bookkeeping, and then it has to launch something inside that pane to be the agent. The adapter is that named choice: claude, aider, openai, anthropic, llama-cpp, local. The kernel stays agnostic about which one runs; the adapter is the seam where a concrete system attaches.

This is what makes cosmon provider-agnostic. Cosmon is not a competitor to Claude Code or aider; it is the layer that composes above any of them and lets you run several at once under one identity and one lifecycle.

Why this is the wedge

Because the choice is per-molecule, your context, your data, and your model choice stay yours. One mission can route to a hosted frontier model; the next molecule can run entirely on a local model, decided by changing a single word. You are not locked to one vendor's loop, and you are not rewriting anything to switch. The molecule, its state, and its trace are identical whichever harness ran it.

How an adapter is chosen

At tackle time cosmon resolves the adapter through a fixed order, highest priority first:

  1. the --adapter <name> flag on cs tackle;
  2. a formula step's adapter = "<name>" pin;
  3. the $COSMON_DEFAULT_ADAPTER environment variable;
  4. the per-galaxy .cosmon/config.toml default;
  5. the global ~/.config/cosmon/config.toml default;
  6. the built-in local adapter.

An unknown name aborts the dispatch; it never silently falls back to some other harness. The exact chain, the --model sibling that pins a model within an adapter, and the events each dispatch emits are documented in the Execution commands reference.

The seam is typed, not stringly

The choice of adapter and the harness that actually launches are guaranteed to be the same thing. Cosmon's spawn seam refuses to compile if handed a bare string: the validated adapter name is the only value the launch site accepts, so "adapter aider selected" and "worker spawned with aider" are the same bytes by construction, not by a hopeful runtime check. A smoke test once showed a worker report aider and then route through Claude; that class of bug is now a type error rather than a possibility. The lineage is recorded in ADR-099 and its successors; the Execution commands reference documents the public dispatch behavior.

What ships today, and what is roadmap

Per-molecule adapter and model choice ships today: you can point any molecule at any registered harness, hosted or local, right now. The stronger reading (long, unattended runs entirely on local models with no human in the loop) reaches into the Autonomous regime, which is roadmap, not shipping. See The three regimes for where present capability ends and the roadmap begins.

See also

Fleets: many agents, one portal

A fleet is the set of workers running together and the fleet.toml that configures them. It is what makes "ten agents in parallel" a single first-class object rather than ten unrelated terminals you have to remember by hand.

What a fleet is

The whole reason cosmon exists is to run many agents at once and keep track of who is doing what. The fleet is that "many agents" made into one tracked thing: the running set of workers and the molecules they are bound to, held together so you can start them, watch them, and tear them down as a group. Each worker still gets its own worktree, its own tmux pane, and its own git branch; they never collide, but the fleet is the roster that knows they all belong together.

fleet.toml: the config

One file declares the fleet's shape: which adapters its workers use, how many, and what roles they play. This is the file the spore how-to leans on when it bundles "fleet config" alongside recipes; a fleet's config is what pins the adapters a germinated polymer's workers will run under.

You do not write fleet.toml from scratch. cs fleet init <template> scaffolds one from a named template, and cs fleet resolve flattens a composable fleet.toml (one that includes others) into the effective configuration. Both are documented in the Fleet management commands.

Fleet versus ensemble

Two words sit close together and are worth separating:

  • The fleet is the configured set: the roster of workers and the fleet.toml that shapes it.
  • The ensemble is that set seen at a glance: the dashboard read of it, what cs ensemble prints and cs peek shows.

One is the roster, the other is the live view of the roster. You configure a fleet; you observe an ensemble.

Cross-examination

A fleet is not only agents working beside each other; it is agents working on each other's output. Reviewing is itself molecule-shaped, so the reviewer is a different molecule, run by a different worker, in a different worktree — never the author grading its own homework.

Three shapes recur:

  • A panel frames one question, dispatches several personas in parallel who never see each other's drafts, and synthesizes where they converge and where they disagree. That is the deep-think formula.
  • A pre-mortem is an independent audit molecule ordered behind the work. It reads the merged code against its spec and returns NO-GO or GO with numbered findings. NO-GO does not revert; it nucleates the remediation, which faces another round.
  • A verification molecule re-checks a specific claim the gates cannot — what a surface actually renders, whether a bug is closed everywhere.

Each is an ordinary cs nucleate --blocked-by edge. There is no reviewer registry and no privileged molecule kind.

Adversarial review works all three through, with the artifacts they leave on disk, the structural guard that stops a panel dodging its own question, a four-round NO-GO→GO example, and the honest limit: a panel of personas over one provider is channel-independent, not error-independent.

A naming footgun, said once

The config file is fleet.toml, singular. The on-disk state directory is .cosmon/state/fleets/, plural. Same word, two different objects: one is the configuration you edit, the other is where cosmon keeps the running fleet's state. Knowing this once means no page trips you later.

See also

Adversarial review: agents that cross-examine each other

A single agent that reviews its own work grades its own homework. Everything on this page exists to break that loop: the reviewer is a different molecule, run by a different worker, in a different worktree, and its verdict is written down where you can read it.

Nothing here is a new command or a new runtime. Every mechanism below is either a formula (a TOML recipe over molecules) or a plain dependency edge in the DAG. That is the point: cross-examination is a shape of work, not a feature.

The panel: one question, several perspectives

The deep-think formula turns a question into a structured deliberation instead of an answer. Its four steps leave four artifacts in the molecule's directory:

StepArtifactWhat it holds
Frameframe.mdThe question broken into numbered sub-questions Q1…Qn, plus the panel roster
Dispatchresponses/<persona>.mdOne file per panelist, written in parallel and independently
Synthesizesynthesis.mdConvergences, divergences, and why they diverge
Outcomesoutcomes.mdThe follow-up work the panel identified

The panel is a roster of named personas — an architect, a systems pragmatist, a first-principles skeptic, a product voice — each dispatched as its own subagent with its own brief. They do not see each other's answers while writing. The disagreement in synthesis.md is therefore real disagreement, not one agent performing both sides of a debate.

deep-think-inline is the same panel run by a single worker: it produces the synthesis and a recommendation but never nucleates children. Both are in the formula catalog.

The coverage table stops the panel from dodging

The natural failure of any panel is that it answers an easier question than the one asked and nobody notices. deep-think closes this structurally: the synthesis step must end with a frame-question coverage table that accounts for every Qn declared in the frame, marked exactly one of:

  • Treated — the panel answered the question as framed.
  • Substituted — it answered an adjacent, easier question instead (and the synthesizer must name what was swapped, and by whom).
  • Declined-with-rationale — deliberately out of scope, reason stated.
  • Silent — nobody addressed it and no reason was given.

Silent is the alarm. It means the question was forgotten or dodged, and the synthesizer must flag it and recommend either another round or an explicit decline from you. cs evolve refuses to advance off this step until synthesis.md actually exists in the molecule directory — a hard artifact gate, not a convention.

The pre-mortem: an independent molecule that tries to sink the work

A panel is a deliberation before the work. A pre-mortem is an adversarial audit after it, and it is a separate molecule with a separate worker: it reads the merged commit and the binding spec, and it is briefed to find the reasons this will fail in production, not to confirm that it compiles.

It returns a verdict — NO-GO or GO — with numbered findings, each with a severity, a concrete file:line, a deterministic counter-example, and a "what would close this" clause. A NO-GO does not revert anything. It nucleates the remediation work, which then goes back through another audit round.

This runs for as many rounds as it takes. The realized-model attribution feature (the ~> drift glyph you see in cs peek) is the worked example, and it took four:

  1. Round 1 — NO-GO. The audit found the announced runtime capture existed for only one adapter, and only when a human happened to open cs peek. The journal was a side effect of the UI, not a runtime trace.
  2. Round 2 — NO-GO. Findings partially closed, new ones opened.
  3. Round 3 — NO-GO. Two of three conditions closed; the third only partially, and the auditor named exactly why: the new test inverted the critical order, forcing the capture before simulating the crash — so it could not fail on the case it claimed to cover.
  4. Round 4 — GO. All conditions closed, with one operational reservation recorded outside the code.

Round 3 is the part worth staring at. The implementation was green — build, test, clippy, and fmt all passed, and the audit says so explicitly before returning NO-GO. Gates prove the suite still passes. An adversary asks whether the suite would notice if the code were wrong.

The verification molecule: the reviewer is not the author

The general pattern the pre-mortem is an instance of: the thing that checks the work is a different molecule from the thing that did it. cosmon ships this in several shapes.

  • verify-surface renders a visual surface and observes it from an independent molecule. It is a built-in formula for a structural reason: the surface_visual gate refuses cs complete until a sibling verify-surface has landed green, so a project without the formula could not satisfy the refusal.
  • visual-qa is the gate for deliverables that are seen rather than compiled — decks, posters, rendered diagrams. It rasterises the output, reads the pixels, runs an adversarial layout checklist, and fails closed. Neither task-work nor editorial-work ever looks at the rendered page.
  • bug-closure runs after a fix lands and walks the bug's whole semantic surface — help text, tests, docs, callers, invariants — returning either closed or reopened, naming the surfaces still uncovered. It exists because a verb repaired in one place and left stale in three others reads as fixed.

Each is ordered behind the work it audits with an ordinary cs nucleate --blocked-by edge. There is no reviewer registry and no special molecule kind.

The judge: a seated panel that cannot be picked after the fact

For changes to the rules themselves — constitutional amendments rather than ordinary code — cross-examination gets a voting procedure. cs panel seats a fixed core of four personas plus a rotating seat drawn from a pool by hashing the diff. Because the rotating seat is a pure function of the artifact under review, the person convening the panel cannot look at the change and then choose a friendly judge. cs panel decide refuses ballots from non-panelists, refuses to rule until every seat has voted, and needs a 4-of-5 supermajority. The full grammar is in Tools & introspection commands.

Where a panel votes, cs witness seals. A separate agent reads a sealed prior file, hashes its bytes, and emits a SealAttested event — and refuses if the witness identity matches the tackler's own session. That refusal is a cheap structural independence check: it makes "I reviewed myself" fail loudly rather than silently.

The honest limit: independence is a spectrum

Cross-examination buys you less than it looks like if every seat is the same model wearing a different name.

A deep-think panel fans out through the harness's own subagent mechanism, which means every persona is one provider's weights under a different brief. That gives channel independence — separate sessions, separate contexts, no shared scratchpad — and channel independence is genuinely worth having: it stops one agent from anchoring on its own earlier sentence. What it does not give is error independence. A model auditing itself under a different name shares its own blind spots. If the failure is one the family does not see, five seats do not see it five times; they miss it once, together.

The axis that actually buys error independence is provider diversity: pinning a refuter seat to a different model family, so the reviewer's failure modes are uncorrelated with the author's by construction rather than by label. Adapters are pinnable per step, which is what makes such a committee expressible as a formula rather than a new primitive — see Agent adapters.

Worth saying plainly, because the distinction is easy to lose: a panel of five personas over one provider is a real check against sloppiness and a weak check against a systematic blind spot. Read a unanimous panel accordingly.

See also

Dynamic workflows or cosmon fleets?

Picture two kinds of work.

In the first, a foreman opens twenty temporary benches, gives each bench one box to inspect, compares the answers, and clears the room before lunch. The useful output is the final report. Nobody needs a permanent identity for bench seventeen.

In the second, an expedition leaves for several days. Each team carries a logbook, follows another team's map, may be interrupted, and must return its samples on a separate manifest. Losing the leader's notebook must not erase where every team got to.

A Claude Code dynamic workflow is the temporary workshop. A cosmon fleet is the expedition register. Neither is a more powerful version of the other. Choose the one whose failure boundary matches the work.

The short decision

Ask one question:

If this Claude Code session vanished now, would restarting the whole job as one unit be acceptable?

If yes, use a dynamic workflow. If no, put the durable boundaries in cosmon molecules and connect them with a DAG.

NeedDynamic workflowCosmon fleet
LifetimeOne Claude Code sessionAcross sessions, crashes, and long missions
Recovery unitThe workflow runEach molecule and formula step
CoordinationJavaScript phases, loops, and fan-outTyped DAG between durable molecules
Operator view/workflows for the current runcs peek and cs ensemble for the fleet
Worker identityEphemeral subagentPersistent molecule plus worker incarnation
IsolationFresh context; optional temporary worktreeDedicated branch and worktree per worker
DeliveryUsually one aggregated resultIndependent artifacts, gates, and merges
Size controlPrompt/config guidance; runtime capsAdmission and parallelism before dispatch

When a dynamic workflow is enough

Use a dynamic workflow when the orchestration is internal detail and the final answer is the only durable object you care about. Typical shapes include:

  • audit many files and return one ranked report;
  • ask several researchers for independent views, cross-check them, and synthesize;
  • apply the same bounded transformation across a large list;
  • repeat a checker/fixer loop until it passes or stops making progress.

Claude Code keeps intermediate values in the workflow script and shows phases, agents, token use, and progress in /workflows. Its subagents normally start with fresh contexts and return results to the parent. This is exactly the right trade when permanent per-agent identity would be bookkeeping without benefit.

The Dynamic workflow size setting is guidance to Claude, not a hard quota. small, medium, and large aim for fewer than 5, 15, and 50 agents. A prompt can request another size. Runtime caps still apply. See the official Claude Code workflow documentation.

When a cosmon fleet is justified

Use cosmon when a subtask deserves to exist after its current executor is gone. That is usually true when one or more of these apply:

  • work must resume after a session crash or context loss;
  • one result gates another through a typed dependency;
  • different tasks need independent branches, reviews, or merges;
  • the operator must see several live responsibilities in one durable view;
  • evidence and lifecycle transitions matter as much as the final synthesis;
  • workers use different adapters or models;
  • the mission lasts long enough that “start the run again” is not recovery.

The lifecycle is explicit:

cs nucleate → cs tackle → cs wait → cs done

Each tackled worker gets its own worktree and branch. The DAG carries ordering, not content: an edge says only whether a predecessor is done. Files and git history carry the actual output. Cosmon merges a predecessor before dispatching its dependent, so the dependent starts from a checkout that already contains the work it needs.

Use both without fusing them

The common combination is simple: make one cosmon molecule the durable recovery boundary, then let its Claude adapter use a dynamic workflow internally.

cosmon molecule (durable lifecycle)
└── Claude dynamic workflow (temporary fan-out)
    ├── subagent
    ├── subagent
    └── verifier subagent

Cosmon owns the molecule state, branch, merge, and durable artifact. Claude Code owns the temporary workflow phases and subagent execution. There is no need to turn every subagent into a molecule unless the operator needs to recover, schedule, merge, or audit it independently.

If that need appears, do not create “shadow molecules” after agents have already started. A true one-to-one bridge must let cosmon admit each spawn before it runs, assign its durable identity and worktree, and remain the only owner of its lifecycle. That is an architectural change, not an adapter convenience.

Rule of thumb

Use the smallest durable boundary that would make a failure boring.

  • If rerunning one workshop is boring, use a dynamic workflow.
  • If rerunning one team would be acceptable but rerunning the expedition would not, make each team a molecule in a cosmon fleet.
  • If a dynamic workflow is only an implementation detail inside one team, keep it there and let cs peek show the durable boundary.

Durability has a cost. Pay it where recovery, isolation, or accountability needs it—not for every temporary pair of hands.

Control plane vs data plane

These commands use physics-inspired names (nucleate, evolve, decay, …). New to the vocabulary? See The physics vocabulary.

When people first meet a multi-agent system, they reach for the obvious picture: agents send each other messages. Agent A finishes, mails its result to Agent B, B reads the mail and starts. That picture needs a mailbox, a queue, a broker: another running thing to keep alive, another place state can be lost.

Cosmon has no mailboxes. It separates two questions that the mailbox picture tangles together:

  • When should the next piece of work start? (the control plane)
  • What does it read to do that work? (the data plane)

These two flow through completely different channels.

The control plane is the DAG: one yes/no per molecule

Cosmon links molecules with typed edges: Blocks, BlockedBy, DecayProduct, Refines, Entangled. Together they form a directed graph: the DAG. But look at how little information an edge carries. A Blocks edge between molecule A and molecule B says exactly one thing: is A done yet, yes or no? A single yes/no signal — done or not-done. Information theory has a precise name for a yes/no answer, and that name is one bit.

That is the entire control signal. cs evolve writes the bit (A moved forward); cs wait and the ready-frontier computation read it (is B allowed to start?). Ordering, the when, is the only thing that travels on this channel. No payload, no content, no message body. Just done / not-done, edge by edge.

"One bit" describes the signal, never the delivery. This is worth spelling out, because a cs done clearly hands the next worker far more than a yes/no: a merged branch, a report, evidence files, however many megabytes of code. All of that is real — it just travels on the other channel. The data plane is arbitrarily large; the control plane is one bit. The point of the split is exactly that contrast: the DAG says go, and the filesystem holds everything you go and read.

The data plane is the filesystem: all the content

Everything a downstream worker actually reads (the predecessor's report, its code changes, its evidence files) flows through shared state on disk:

  • .cosmon/state/ JSON files,
  • git worktrees and branch lineage,
  • a molecule's response and synthesis files,
  • evidence attachments.

Workers read and write these files directly. The DAG never carries the content; it only tells a worker when it is allowed to go look. When molecule B becomes ready, it reads molecule A's output straight off the disk, because A's branch was merged into B's worktree base before B was dispatched (this is merge-before-dispatch, and it is why the git history a worker sees already contains its predecessor's work).

Why split them this way

Collapsing the two planes into one messaging channel is where distributed systems get their hardest bugs. Keeping them separate buys three concrete things:

  • It survives crashes. State is on disk, never in a broker's RAM. Kill everything, restart, and the DAG bit plus the files on disk fully reconstruct where you were. (See Crash recovery.)
  • It needs no broker. There is no queue process to run, secure, scale, or lose messages in. One fewer moving part, one fewer failure mode.
  • It makes reconciliation a pure projection. Because the authoritative content is all on disk, cs reconcile can rebuild every derived surface (status files, issue lists, dashboards) as a deterministic function of the files. Run it twice, get the same result.

The rule of thumb

When you feel the urge to add "messaging" between molecules, stop and ask the two questions instead:

  1. Which typed link expresses this dependency? (control plane: the when)
  2. Which file on disk carries the payload? (data plane: the what)

Every real need answers cleanly in those two terms. If it seems to need a third thing, a mailbox, that is almost always a dependency edge and a file wearing a disguise.

The channels at a glance. Cosmon actually distinguishes six channels: the service registry, the DAG (1 bit, authoritative ordering), the filesystem (authoritative content), the artifact chain (proof of work), propulsion (a zero-byte wake-up from pilot to worker), and whisper (advisory text a human pilot can send to a live worker). The first three are the load-bearing pair described above plus their registry; the rest are thin signals layered on top.

The three regimes: Inert / Propelled / Autonomous

These commands use physics-inspired names (nucleate, tackle, evolve, …). New to the vocabulary? See The physics vocabulary.

A molecule is a piece of tracked work. At any moment it sits in exactly one of three regimes, and the regime is not really about the molecule itself. It is about a simpler question: who holds the clock? Who has the right to move this work forward, right now?

Asking "is the system alive?" leads nowhere; you end up inventing words like semi-alive that fall apart on the first edge case. The sharp question is: who is entitled to perform the next step? The three regimes are the three answers.

RegimeWho holds the clockWho performs the next stepWhen it applies
InertNobody, external onlyA human, next time they type a cs commandPending molecules; finished molecules
PropelledA human, plus fuelThe worker running in a tmux paneA tackled molecule actively running
AutonomousAn internal runtimeA policy inside cs runA DAG being walked by the runtime

Inert: the parked car

An inert molecule has state but no motion. It sits on disk and does absolutely nothing until something outside it reaches in and pushes.

Two very different molecules are both inert. A freshly nucleated molecule that nobody has started yet is inert; it is waiting to begin. And a completed molecule is also inert; it is finished, but its shell stays on disk so you can still read its trace. One is inert before its life, the other after. Neither has a clock of its own. The only way an inert molecule ever changes is when a human runs a command against it.

A parked car. It has everything it needs to move, but it will sit in the driveway forever until someone gets in and turns the key.

Propelled: the car with a driver and a tank of fuel

You cs tackle a molecule and it enters the propelled regime. Now it has momentum. A worker (an AI agent in its own tmux pane and git worktree) is driving it forward, step by step, along the formula's predetermined path. It keeps going until the fuel runs out (all steps complete) or the motion dies (it stalls on a blocker).

The clock here is external plus fuel: a human lit the fuse with cs tackle, and now the worker carries the work along a fixed trajectory. If the worker stalls, a watchdog (cs patrol --propel) can give it a nudge from outside, the way you would tap a stuck toy back into motion. But the trajectory was fixed the moment the molecule was nucleated; the steps do not change mid-drive.

This is the regime you spend almost all your time in today. The full loop is nucleate → tackle → wait → done: create the molecule, start a worker on it, wait in the background for it to finish, then tear it down and merge its work.

Autonomous: the self-driving fleet (the north star)

In the autonomous regime the clock moves inside cosmon. A long-lived process (cs run) walks a whole DAG of dependent molecules, and a policy decides what to start next: a DAG scheduler, a decay-aware re-planner, or an external planner speaking over MCP. No human types each cs tackle; the runtime does it, and calls cs done on each node as it finishes.

Two honest notes about this regime:

  • The runtime is a client, not a new brain. It cannot do anything a human could not do at the CLI. It owns no private truth; it reads the same JSON files, emits the same cs evolve / cs done calls. Kill it and restart it, and it rebuilds everything from disk. That is why it never threatens the crash-recovery guarantee.
  • Full autonomy is still the north star, not the whole sky. cs run walks DAGs today; the deeper self-directed regime (long unattended missions with a pluggable planner) is on the roadmap (ADR-016), not something that ships finished. When you read "autonomous," read it as the direction cosmon is built to grow into, with the guardrails already in place.

Bounded autonomy: free inside a fence, stopped at the gates

The autonomous regime is exactly where the fear of runaway lives: if I hand over the clock, what stops it doing something I would never have allowed? The answer is that autonomy in cosmon is always bounded: free movement inside a real fence, with a leash you never let go of.

Think of a dog in a fenced yard. Inside the fence it runs free: it tidies up finished work, picks up the next obviously-ready job, jots a note about something it noticed. All small, safe, reversible chores. But at the edge of the yard there are gates it will never push open alone; it sits and barks for you instead:

  • A new direction: a whole new area of work outside the job you posed.
  • A real fork: a design choice with genuine trade-offs.
  • Anything it cannot take back: pushing, deleting, publishing, changing DNS.
  • Rewiring the house: installing a service, editing the rules it itself obeys, touching shared config.

And you always hold the leash. Any one of three tugs freezes it where it stands: you speak (any message pauses it), you drop a stone in the yard (touch ~/.cosmon/autopilot.off, which it checks at every decision point), or it trips three times on the same rock (three failures in a row and it stops itself). Autonomy is never "the robot takes over" and never "you watch it like a hawk"; it is calibrated trust: a fence you can see, gates it always knocks on, and a leash you always hold.

Why the regimes matter

Every cosmon command operates on one or more regimes, and mixing them up is where design goes wrong. cs nucleate only ever produces an inert molecule; nothing runs. cs tackle is the sole doorway from inert into propelled, and it is human-only. cs done is the doorway back out. The autonomous regime, when it is active, uses the very same doorways; it just walks through them on its own schedule.

So the regime is really a statement about delegation: cs tackle delegates the next observation to a worker; cs patrol --propel delegates it to an external scheduler; cs run delegates it to the runtime's policy. Name the regime and you know who holds the clock, and once you know who holds the clock, every command's behaviour follows.

Crash recovery: state on disk, not in RAM

These commands use physics-inspired names (nucleate, evolve, reconcile, …). New to the vocabulary? See The physics vocabulary.

This is the headline wedge. AI agents crash. They run out of context window, the laptop reboots, a tmux session dies, a model call times out. In a system that kept its truth inside a running process, a crash would lose that truth. Cosmon is built so that a crash loses nothing, and the reason is one sentence: the authoritative state is always on disk, never only in RAM.

The mechanism, in one loop

Every cs command is a discrete transaction: read the files, change them, write them back, exit. After the command returns, the full truth of the system is sitting on disk in .cosmon/state/: a molecule's state.json, its append-only events.jsonl, its tracked markdown trace. There is no in-memory invariant that the files do not also record.

So recovery is not a special mode you switch into. It is just: run the next command. The next cs evolve, the next cs wait, the next cs run re-reads the files and continues from exactly where they say you were. A restarted resident runtime is indistinguishable from a fresh one; it rebuilds its whole picture from the same JSON the CLI reads. There is no crash-recovery procedure because statelessness makes recovery the default.

Desired vs Observed vs Effective: telling wish from reality

A crash creates a gap between what you wanted and what is actually true. You asked for a worker to be running; the process died; the tmux pane may or may not still linger as a zombie. Cosmon resolves this gap by never storing a single muddy "status." It computes health fresh, from three separate axes:

  • Desired is what you asked for, and the only thing persisted: Running, Paused, or Stopped. Stored in fleet.json.
  • Observed is what reality says right now, computed fresh and never stored: is the transport (tmux) alive, dead, or unknown? is the session idle, working, or blocked? is the agent's own cognitive trace fresh or stale?
  • Effective is the honest verdict, reconcile(desired, observed): Healthy, Diverged, Suspect, Blocked, Paused, Stopped, or Error.

Because desired is the only thing written down, and observed is always recomputed, a crash cannot leave a lie on disk. If you asked for Running and the process is Dead, reconcile reports Diverged, and it says so every time, because it re-measures reality rather than trusting a stored flag.

What happenedDesiredTransportEffectiveWhat cosmon does
Agent working normallyRunningAlive, workingHealthyNothing, reality matches intent
Agent crashedRunningDeadDivergedRespawn (until the restart limit)
Zombie: killed but tmux lingersStoppedAlive, idleDivergedKill the stray session
Stuck on a permission promptRunningAlive, blockedBlockedSurface it; a human is needed
Restart limit hitRunningDeadErrorCircuit-break; stop retrying

That last row matters: recovery is bounded. A worker that keeps dying is not respawned forever; after a set number of failures the circuit breaks and the molecule is flagged Error for a human, rather than looping on a broken task.

Reconcile is a pure projection

Because all the authoritative content lives on disk, rebuilding every derived view is a deterministic function of the files. cs reconcile takes the state and re-projects it onto the surfaces humans and other tools read (status files, issue lists, dashboards) and it is idempotent by construction: run it once or run it ten times, you get the same result. This is enforced by tests. A projection that could drift on a second run would be a bug, because there is exactly one source of truth and reconcile only ever reads it.

Why this is the wedge, not a feature

Other orchestrators can restart a failed function: re-run the code and hope it was idempotent. Cosmon restarts a failed entity: the same worker, on the same molecule, resuming the same task with its predecessors' work already merged into its worktree. That is only possible because identity and state were never trapped in a process that could die. They were on disk the whole time, waiting for the next command to pick them up.

See Why a stateless CLI for the design bet this rests on, and Control plane vs data plane for why no message was ever in flight to lose.

Architecture: the two layers

These commands use physics-inspired names (nucleate, evolve, tackle, …). New to the vocabulary? See The physics vocabulary.

How cosmon runs — four bands: the human pilot advances the lifecycle with a one-shot CLI; a molecule DAG whose edges encode ordering (done/not-done), never content; the .cosmon/ disk as the single source of truth that carries content, BLAKE3-sealed and tamper-evident; and three execution modes — local (built), remote via a cosmon-remote thin client talking HTTPS to a cosmon-rpp-adapter service on a host (a server exists), and peer-to-peer sharing marked as a planned roadmap.
How cosmon runs — pilot, control plane (ordering), disk (content), and execution modes.

Cosmon is organized as two cooperating layers that share one state store. The first is everything you can touch today; the second is an optional process that sits on top without ever becoming load-bearing. Understanding this split explains most of cosmon's design choices at once.

Layer A: the Transactional Core (today)

The core is the stateless CLI. Every cs command is git-like: read state, mutate, write, exit. No daemon, no lingering process. State lives on disk as JSON files in .cosmon/state/, and that is the source of truth. Because each command is a complete one-shot transaction, the core composes with any scheduler: cron, launchd, a shell loop, a CI job, or a human at a terminal.

This is the load-bearing layer. Every capability cosmon offers is reachable here, human-driven, with nothing else running.

Layer B: the Resident Runtime (optional, additive)

The runtime is one long-lived process, cs run, with an event loop. It polls the on-disk state, asks a pluggable policy what to do next (a DAG scheduler today; a decay-aware re-planner or an external LLM-backed planner in the future), and applies the answer through the very same commands the CLI exposes.

Four rules keep Layer B honest, and they are non-negotiable:

  • It is a client, never a substrate. The runtime cannot mutate state through any channel the CLI does not also expose. A human can cs observe or cs freeze a molecule while the runtime works on it; they are clients of the same file-based truth.
  • It owns no state. JSON on disk stays authoritative. Kill the runtime, restart it, and it rebuilds its entire picture from the files. There is no RAM it is afraid to lose.
  • It is deletable in one move. Layer B is a separate build target; removing it never touches the core. Layer A does not require the runtime to exist.
  • It is never the only path. Anything the runtime does, a human can do at the CLI. The runtime is pure convenience layered on a system that already works without it.

The three regimes formalize when each layer is in charge: Layer A drives the inert and propelled regimes; Layer B, when running, drives the autonomous regime, using Layer A's own doorways.

Inside the core: pure core, impure shell

The code mirrors the two-layer discipline at a smaller scale. cosmon-core contains the domain (the state machines, the identity types, the validation) and has zero I/O: no filesystem, no network, no async runtime. All the messy outside world (reading files, spawning tmux, tracking tokens) lives behind traits, implemented in separate crates.

graph TD
    CLI["cosmon-cli<br/>(the binary: clap)"]
    CORE["cosmon-core<br/>Pure domain logic<br/>State machines · types · validation<br/><b>ZERO I/O</b>"]
    CLI --> CORE
    CORE -->|trait: StateStore| SS["JSON files / SQLite"]
    CORE -->|trait: Transport| TR["tmux / process"]
    CORE -->|trait: EnergyTracker| ET["token accounting"]

This buys three things: the core is testable without mocks (it is pure functions over domain types), the backends are swappable (flat files today, SQLite tomorrow, without touching the core), and the transport layer can be hardened independently of the AI cognition it carries.

Two patterns worth knowing

Two Rust patterns do most of the structural work, and both trade a little verbosity for compile-time safety:

  • Typestate for the molecule lifecycle. Each lifecycle state (Active, Frozen, Completed, Collapsed) is a distinct type, and transition methods exist only on the states that allow them. Trying to evolve a frozen molecule is not a runtime error checked with an if; it simply does not compile. The type system makes invalid transitions unrepresentable.

  • Newtype IDs. Every identifier (MoleculeId, WorkerId, AgentId) is its own wrapper type with validation on construction, not a bare String. Passing a WorkerId where an AgentId is expected is a compile error, and an ID that exists is guaranteed valid because it could not have been built otherwise.

The through-line of every one of these choices is the same physics framing: minimize the gap between what the system claims to do and what it actually does. Every invariant pushed into the type system is one fewer runtime surprise, and one fewer thing that can drift when an agent crashes.

For the design bet the whole architecture rests on, see Why a stateless CLI; for how it survives failure, see Crash recovery.

Versioning policy

Cosmon is pre-1.0. Its version numbers follow semantic versioning, read the way every 0.x project reads it: while the leading number is zero, the minor number carries the weight a major number normally would.

  • 0.x.y0.x+1.0: a minor bump may include breaking changes. Before 1.0, the API surface (CLI verbs, flags, JSON output shape, on-disk state format) can shift between minor releases. Read the changelog before upgrading.
  • 0.x.y0.x.y+1: a patch bump is fixes and additive changes only.
  • 1.0.0 onward: once cosmon reaches 1.0, the usual semver contract applies: breaking changes wait for a major bump, and the CLI surface, --json output, and state format become stable promises.

What "stable" will mean at 1.0

Three surfaces are the public contract, and they are what 1.0 will freeze:

  1. The CLI: command names, their flags, and their semantics. The generated reference is a projection of the actual tool, so the reference and the binary cannot silently disagree.
  2. The --json output: the agent-first interface. Every command honours --json, and its shape is part of the contract because other tools parse it.
  3. The on-disk state format: the JSON files in .cosmon/state/. Because these files are the source of truth (see Why a stateless CLI), their format is as much a public API as any function signature.

No version switcher, yet

This documentation site describes one version: the one on main. There is deliberately no multi-version switcher on the site today. Building one is premature until there is a real 0.x → 1.0 break worth navigating between; the scheme is stated here in prose now, and the switcher is deferred to the first version boundary that actually needs it. This is the same "document the policy first, build the tooling when the need is concrete" discipline cosmon applies everywhere.