Auto-generated — do not edit. Run go run ./cmd/genschema to regenerate.
Global Flags
gc
Gas City CLI — orchestration-builder for multi-agent workflowsgc agent
Manage agent configuration in city.toml. Runtime operations (attach, list, peek, nudge, kill, start, stop, destroy) have moved to “gc session” and “gc runtime”.gc agent add
Add a new agent scaffold under agents/<name>/. Creates agents/<name>/prompt.template.md and, when needed, agents/<name>/agent.toml. These files live in the city directory and do not append [[agent]] blocks to city.toml. Use —prompt-template to copy prompt content from an existing file into the canonical prompt.template.md location. Schema-2 convention agents are city-scoped; define rig-scoped agents in pack config or [[patches.agent]]. Use —suspended to scaffold the agent in a suspended state.gc agent is-foreign
Report whether this city can vouch for a claim’s assignee identity. An identity is local when it resolves against this city’s roster (configured agents, named sessions, pool and namepool instances), or when one of this city’s own session records, open or closed, answers to it under its bead ID, session name, alias, configured named identity or sole alias-history entry. Anything else is foreign: on a shared rig store, another city’s claims look exactly like this. Every identity shape is checked, qualified or bare. Exit codes: 0 local this city can vouch for the identity 1 foreign this city cannot vouch for it; protect the claim 2 unknown this city cannot answer (no roster, a failed lookup, bad usage); protect the claim “local” is not a liveness claim: a dead local claimant is still local, and the caller has to establish liveness itself. Callers that reap claims on this verdict must fail closed: treat a missing verb, exit 2, or unparseable output as “protect”, never as “local”. Pass the identity after ”—” when it is untrusted text.gc agent list
List configured agents from the resolved city configuration. Use —json to inspect agent routing fields, including effective work_query and sling_query values.gc agent resume
Resume a suspended agent by clearing suspended in its durable config. The reconciler will start the agent on its next tick. Supports bare names (resolved via rig context) and qualified names (e.g. “myrig/worker”).gc agent suspend
Suspend an agent by setting suspended=true in its durable config. Suspended agents are skipped by the reconciler — their sessions are not started or restarted. Existing sessions continue running but won’t be replaced if they exit. Use “gc agent resume” to restore.gc agent-script
Run a deterministic YAML agent script for examples and demos. The runner probes gc hook once, selects the matching turn, and executes the configured actions. It is intentionally small and generic: role behavior stays in the YAML script. Status: experimental. Gas City owns this runner so repository examples can be tested without external helper binaries; the YAML action surface may change until a stable SDK boundary exists. For k8s-backed agent-script agents, set lifecycle = “one_shot” in the agent config so the runtime treats a clean script exit as expected work completion instead of startup death.gc analyze
Analyze produces correlated reports over the events log and bead state. All subcommands are read-only and safe to run alongside a live controller.gc analyze reliability
Reliability reports per-(model, prompt_version, rig) counts of the tracked session-lifecycle events: session.crashed session.quarantined (reserved; current production paths do not emit it) session.idle_killed session.draining Worker.operation events from #1252 supply the (model, prompt_version, agent_name) tuple per session. Lifecycle events get attributed via the session id or producer aliases from worker.operation payloads. Sessions with worker.operation events but no lifecycle events count toward the per-group total — they’re the denominator side of crash-rate calculations. Model and prompt_version are best-effort dimensions; the report warns when the source event stream is missing them. Read-only: this command never writes events or beads.gc bd
Run a bd command routed to the correct rig directory. When beads belong to a rig (not the city root), bd must run from the rig directory to find the correct .beads database. This command resolves the rig automatically from the —rig flag or by detecting the bead prefix in the arguments. Use —rig <name> to pin a specific rig store, or —city <path> to pin the city (HQ) store. An explicit —city is a true scope override: it forces the city store and disables rig auto-detection (GC_RIG, cwd, bead prefix), so a deliberate city-scoped query is never silently downgraded to a rig store. On a city that serves a coordination class from its own [storage] binding, a by-id read or write of a bead that binding owns is answered in process from the binding, not by bd against a work store that does not hold it. —rig is refused for those beads rather than ignored or honored: it names a work scope, and a relocated class is not partitioned by rig, so there is nothing to narrow within. Drop —rig for a class-owned id. Auto-detected scope (GC_RIG, -C, cwd) is unaffected, and —city still selects which city’s binding answers. “gc bd ready” is refused outright on such a city, whatever arguments it is given, and so is “gc bd list —ready”, which bd documents as the same semantics: both compute a frontier over one ledger and take no selector that could reach another, so the answer is the work-class subset of the city’s ready set with no way to tell. Use “gc ready”, which federates every store the city spreads work across. It is flag-compatible with the “bd ready” invocation the generated work query builds, not with all of “bd ready” — “gc ready —help” lists what it takes. A city that relocates no class is unaffected. All arguments after “gc bd” are forwarded to bd unchanged, with one exception: a “list” that filters on the wisps (ephemeral) tier — “—type=molecule”, “—type=wisp”, “—mol-type”, “—wisp-type” — also gets “—include-infra”. bd skips that tier on any list without the flag, so those filters would otherwise return [] and exit 0 on a ledger full of live molecules. Every other list is forwarded as written. “heartbeat <issue-id>” forwards to bd’s native heartbeat, which refreshes the claim’s lease and fails loudly when the caller no longer owns it. “show <id> —watch” (or “show —current —watch”, or the “view” alias) is served by gc on two kinds of scope: one that uses bd’s proxied-server transport (the default for a new city), where bd refuses watch mode, and one whose store bd reaches over http, where enterprise bd refuses it and OSS bd would poll the shared server every 2 seconds. gc re-runs “bd show” every 2 seconds on a proxied scope and every 10 to 12 seconds on an http scope, and redraws when the bead’s status or update time changes, until Ctrl+C. A failing read is reported once, with bd’s error; the last view stays up and the wait between reads doubles, up to 5 minutes, until a read succeeds, which is reported too. Like bd’s own watch, it renders the plain form and ignores show’s display flags (—json, —short, —long, —refs, —children). gc adds one subcommand of its own: “release-if-current <issue-id> <assignee>”, which conditionally resets an in-progress assignment only when the bead still has that assignee. gc bd forces BD_EXPORT_AUTO=false to prevent bd’s git auto-export hook from wedging the wrapper after printing command output. To write a JSONL snapshot, run “gc bd export”.gc beads
Manage the beads provider (backing store for issue tracking). Subcommands for topology operations, health checking, diagnostics, exact-store metadata compare-and-set, and read-only list/show routed through the supervisor API with transparent fallback to direct bd reads.gc beads city
Manage the canonical city endpoint topology for bd-backed beads stores. Use use-managed to make the city GC-managed again. Use use-external to pin the city to an external Dolt endpoint and rewrite inherited rig mirrors. Use migrate-proxied to move a legacy GC-managed city onto bd’s proxied-server topology. use-managed and use-external manage gc-owned endpoint topology only. They refuse a city whose store the beads provider owns — one journaled in .gc/scope-ownership.json, one transferred by the ownership handoff, or one bd’s metadata binds to the proxied-server path — because that endpoint lives in bd’s own files and is bd’s to change.gc beads city migrate-proxied
Migrate a legacy GC-managed city, and the rigs that share its Dolt data directory, onto bd’s proxied-server topology. The city’s gc-manageddolt sql-server must already be stopped: run gc stop
first. bd cannot see a server gc started (it looks only for its own pid file),
so migrating against a live one commits the mode flip and leaves the scope
unusable until the server dies.
Each scope is migrated with bd’s own bd migrate from-server-to-proxied-server,
city first. The command is idempotent — an already-proxied scope reports
“already migrated” — so a partially failed run can simply be rerun. It also
retires gc’s own runtime publication for the city it just handed over.
On bd v1.3.0 this is the only supported migration for a legacy GC-managed city.
Procedure, refusals and recovery: engdocs/runbooks/beads-migrate-proxied.md.
gc beads city use-external
Set the city endpoint to an external Dolt servergc beads city use-managed
Set the city endpoint to GC-managedgc beads health
Check beads provider health and attempt recovery on failure. Delegates to the provider’s lifecycle health operation. For exec providers (including bd/dolt), the script handles multi-tier checking and recovery internally. For the file provider, always succeeds (no-op). Also used by the beads-health system order for periodic monitoring.gc beads list
List beads across all rigs, routed through the supervisor API when the controller is alive and falling back to a direct multi-store read otherwise. Supports —label, —status, —all, and —format. —format=json emits JSON (API-path JSON includes _cache_age_s; fallback-path JSON omits it). The bare —json flag is reserved by the CLI’s JSON-contract layer and is not wired for this command; use —format=json.gc beads metadata-cas
Atomically compare and set one metadata key in one exact local bead store. The store must be selected explicitly with —store-ref=city:<name> or —store-ref=rig:<name>. This command never scans other stores, follows a cross-store fallback, or operates on a remote city. A conflict is an ordinary zero-exit outcome; capability, transport, readback, and validation failures are non-zero. Legacy file-provider cities created before scope-local file stores may map city and rig references to the same shared city file. That provider-layout alias is preserved for compatibility; it is not a search or cross-store fallback. Use —json for the canonical machine-output contract. —format=json remains accepted for compatibility. Combining —json with an explicit —format=text is a usage error.gc beads show
Show one bead by ID, routed through the supervisor API when the controller is alive and falling back to a direct multi-store lookup otherwise. Supports —format. —format=json emits JSON (API-path JSON includes _cache_age_s; fallback-path JSON omits it). The bare —json flag is reserved by the CLI’s JSON-contract layer and is not wired for this command; use —format=json.gc build-image
Assemble a Docker build context from city config, prompts, formulas, and rig content, then build a container image with everything pre-staged. Pods using the prebaked image skip init containers and file staging, reducing startup from 30-60s to seconds. Configure with prebaked = true in [session.k8s]. Secrets (Claude credentials) are never baked — they stay as K8s Secret volume mounts at runtime.gc cities
List all cities registered with the machine-wide supervisor.gc cities list
List registered citiesgc completion
Generate the autocompletion script for gc for the specified shell. See each sub-command’s help for details on how to use the generated script.gc completion bash
Generate the autocompletion script for the bash shell. This script depends on the ‘bash-completion’ package. If it is not installed already, you can install it via your OS’s package manager. To load completions in your current shell session: source <(gc completion bash) To load completions for every new session, execute once:Linux:
gc completion bash > /etc/bash_completion.d/gcmacOS:
gc completion bash > $(brew —prefix)/etc/bash_completion.d/gc You will need to start a new shell for this setup to take effect.gc completion fish
Generate the autocompletion script for the fish shell. To load completions in your current shell session: gc completion fish | source To load completions for every new session, execute once: gc completion fish > ~/.config/fish/completions/gc.fish You will need to start a new shell for this setup to take effect.gc completion powershell
Generate the autocompletion script for powershell. To load completions in your current shell session: gc completion powershell | Out-String | Invoke-Expression To load completions for every new session, add the output of the above command to your powershell profile.gc completion zsh
Generate the autocompletion script for the zsh shell. If shell completion is not already enabled in your environment you will need to enable it. You can execute the following once: echo “autoload -U compinit; compinit” >> ~/.zshrc To load completions in your current shell session: source <(gc completion zsh) To load completions for every new session, execute once:Linux:
gc completion zsh > ”${fpath[1]}/_gc”macOS:
gc completion zsh > $(brew —prefix)/share/zsh/site-functions/_gc You will need to start a new shell for this setup to take effect.gc config
Inspect, validate, and debug the resolved city configuration. The config system supports multi-file composition with includes, packs, patches, and overrides. Use “show” to dump the resolved config and “explain” to see where each value originated.gc config explain
Show the resolved configuration with provenance. For agents (default): displays every resolved field with an annotation showing which config file provided the value. Use —rig and —agent to filter. For providers (—provider): displays the resolved ProviderSpec along with per-field and per-map-key attribution — which chain layer (builtin:X or providers.Y) contributed each value. Useful for debugging base-chain inheritance. Use —json to emit machine-readable output (providers only).gc config show
Dump the fully resolved city configuration as TOML. Loads city.toml with all includes, packs, patches, and overrides, then outputs the merged result. Use —validate to check for errors without printing. Use —provenance to see which file contributed each config element. Use -f to layer additional config files.gc context
Manage the client-side registry of named remote cities. A context names a remote city the gc CLI can operate over the HTTP+SSE control plane: its URL, the remote city name, and an optional credential command. Select a context per-invocation with —context <name>, or set a sticky default with ‘gc context use <name>’ (a discoverable local city always wins over the default).gc context add
Add a named remote city to ~/.gc/contexts.toml. —url is required and must be https for a non-loopback host. —city sets the remote city name (defaults to <name>). At most one credential technique applies: —grant-command mints an X-GC-City-Write grant for a direct hardened self-host; —credential-command mints a transport bearer consumed by an edge/proxy.gc context current
Dry-run the target resolver and report the winning tier. Applies the same precedence as every command — explicit flag > explicit env > local city discovery > sticky default — and prints the target it would use, noting what was shadowed. Makes no network call.gc context list
List named remote citiesgc context remove
Remove a named remote citygc context show
Show a named remote citygc context use
Set the sticky default remote city. The default is used only when no local city is discoverable from the current directory — a local city always wins (git-like). Clear it with ‘gc context use’ with no arguments is not supported; remove the default by removing the context.gc converge
Convergence loops are bounded multi-step refinement cycles. A root bead + formula + gate = repeat until the gate passes or max iterations are reached. The controller processes wisp_closed events and drives the loop automatically.gc converge approve
Approve and close a convergence loop (manual gate)gc converge create
Create a convergence loopgc converge iterate
Force next iteration (manual gate)gc converge list
List convergence loopsgc converge retry
Retry a terminated convergence loopgc converge status
Show convergence loop statusgc converge stop
Stop a convergence loopgc converge test-gate
Dry-run the gate condition (no state changes)gc converge test-trigger
Dry-run the trigger condition (no state changes)gc convoy
Manage convoys — graphs of related work beads. A convoy is a named graph of beads with dependencies. Convoys group related issues via tracks dependencies. Convoys are distinct from workflows — the DAGs compiled from v2 formulas and managed by the dispatch subsystem. The convoy lifecycle subcommands (create, list, status, target, add, close, check, stranded, land) do not operate on workflow roots; the dispatch subcommands (control, delete, delete-source, reopen-source) manage workflow trees and their control beads.gc convoy add
Link an existing issue bead to a convoy. Adds a tracks dependency from the convoy to the issue, making it appear in the convoy’s progress tracking without changing the issue parent.gc convoy check
Scan open convoys and auto-close any where all child issues are resolved. Evaluates each open convoy’s children. If all children have status “closed”, the convoy is automatically closed and an event is recorded. The check skips a suspended rig’s store, naming the rig on stderr, and checks its convoys once the rig resumes. A store it cannot open or list, or a convoy it cannot read or close, is named on stderr and the check goes on with the rest, then exits 1. The exception is a city whose convoys moved to a class binding: if the binding cannot be read, the check closes nothing and exits 1. A convoy that changed or disappeared after the check listed it is left for the next run and does not fail the check.gc convoy close
Close a convoy bead manually. Marks the convoy as closed regardless of child issue status. Use “gc convoy check” to auto-close convoys where all issues are resolved.gc convoy control
Process a single control bead, or run the control-dispatcher loop with —serve to continuously process ready control beads. Use —follow <agent> to filter the serve loop to a specific agent template.gc convoy create
Create a convoy and optionally link existing issues to it. Creates a convoy bead and tracks any provided issue IDs. Issues can also be added later with “gc convoy add”.gc convoy delete
Close all open beads in a convoy, or delete them. Searches all stores (city + rigs) for the convoy root and all beads with matching gc.root_bead_id. Without —force, shows a preview. By default, beads are closed with gc.outcome=skipped. Use —delete to remove them from the store via bd delete —cascade —force.gc convoy delete-source
Find every live workflow root sourced from the given bead and close its subtree. By default this is a preview. Use —apply to mutate. Use —delete with —apply to also delete closed beads.gc convoy land
Land an owned convoy, verifying all children are closed. Landing is the natural lifecycle termination for owned convoys created via “gc sling —owned”. It verifies all children are closed (or uses —force), closes the convoy bead, and records a ConvoyClosed event.gc convoy list
List all open convoys with completion progress. Shows each convoy’s ID, title, and the number of closed vs total child issues.gc convoy reopen-source
Reopen a source bead after workflow cleanupgc convoy status
Show detailed status of a convoy and all its child issues. Displays the convoy’s ID, title, status, completion progress, and a table of all child issues with their status and assignee.gc convoy stranded
Find open issues in convoys that have no assignee. Lists issues that are ready for work but not claimed by any agent. Useful for identifying bottlenecks in convoy processing.gc convoy target
Set the target branch metadata on a convoy. Child work beads can inherit this target branch when slung with feature-branch formulas such as mol-polecat-work.gc costs
Aggregate recorded usage facts (model tokens and compute wall-seconds) by run for local cost insight. Reads .gc/usage.jsonl (the local usage sink) and groups facts by run id. This reflects facts only under the default “local” usage provider; with an “exec:” or “discard” provider the facts are forwarded out of process or dropped, so gc costs shows nothing local. Cost is a list-price estimate for decision support, not an authoritative charge; invocations with no pricing are flagged “unpriced” and excluded from the cost total. With —by-formula, model usage is grouped by the formula the acting bead’s run was compiled from instead of by run; usage with no formula appears as ”-”. Compute wall-seconds are not attributed to a formula, so that table has no WALL_S column.gc dashboard
Open the GC dashboard in your browser. The dashboard SPA is embedded in the gc binary and served same-origin by the supervisor; it is no longer a separate static server. This command resolves the supervisor URL, opens it in your default browser, and prints it too (or tells you how to start the supervisor). Use —no-open to print the URL without launching a browser.gc dashboard serve
Report the URL where the GC dashboard is served. The dashboard SPA is embedded in the gc binary and served same-origin by the supervisor; “gc dashboard serve” no longer starts a static server. It resolves and prints the supervisor URL (or tells you how to start the supervisor).gc doctor
Run diagnostic health checks on the city workspace. Checks city structure, config validity, binary dependencies (tmux, git, bd, dolt), controller status, agent sessions, zombie/orphan sessions, bead stores, Dolt server health, event log integrity, formula compiler requirements (deprecated contract = “graph.v2” opt-ins, missing [requires] formula_compiler = ”>=2.0.0” declarations, and requirements the host’s [daemon] formula_v2 setting cannot satisfy), v2 config deprecations such as legacy [formulas].dir, and per-rig health. Use —fix for the canonical remediation path, including any safe mechanical legacy-to-current pack rewrites that are available on this branch. —check runs only the checks you name, so a caller after one verdict does not pay for the whole sweep. It is repeatable and also accepts a comma list, results keep their normal run order rather than the order you asked for, and the exit code reflects the selected checks alone. A name that no registered check matches fails the run: an empty result set would read as a clean bill of health to a caller filtering by name. Which names exist depends on the workspace, because doctor registers checks conditionally — run without —check to see them, or name a nonexistent check to have them listed.gc dolt-cleanup
gc dolt-cleanup is the Go-side implementation of the operational Dolt cleanup tool. It resolves the Dolt server port via the AD-04 chain (—port > city dolt.port > live managed dolt [runtime handle, then process table] > 3307); .beads/dolt-server.port is a bd compatibility status file and is never consulted for endpoint selection (it is read protect-only, to fence a recorded port, when live resolution is unavailable). It drops stale test/agent databases, calls DOLT_PURGE_DROPPED_DATABASES to reclaim disk, and reaps orphaned dolt sql-server processes left over from leaked test harnesses. Invalid explicit ports, invalid city port settings, and live-resolution errors (ambiguous listeners, discovery failures) fail closed before cleanup stages run; only a clean live-resolution miss can reach the legacy default. Nothing proves the city’s server listens on the legacy default, so a run that reaches it opens no SQL connection, drops and purges nothing, and records a legacy-fallback-port force blocker (—force then exits nonzero). Start the city’s managed dolt; for an external server, pass —port or pin it with “gc beads city use-external”. The legacy default does not protect port 3307 from orphan-process reaping. Dry-run by default. Pass —force to actually drop, purge, and kill. Pass —max-orphan-dbs with —force to refuse all destructive cleanup stages if the live apply-time stale database count exceeds the scan-time threshold. The default 0 disables this guard; negative values are rejected before any city lookup or cleanup stage runs. Protection is conservative and checked first: active rig dolt servers (matched by listening port), registered rig databases, and active test temp roots are always protected, and any process whose state cannot be determined degrades to protected. A dolt sql-server is reaped only when its scope is provably gone — its working directory is an unlinked inode (the kernel “(deleted)” cwd marker), or its —config path is on the test-config-path allowlist (/tmp/Test*, os.TempDir()/Test*, known Gas City test prefixes, ~/.gotmp/Test*, /var/tmp/gotmp/Test*, $GOTMPDIR/Test*). A server whose —config has merely vanished while its working directory is still live is protected, not reaped, until an operator confirms; a lone missing-config observation is not proof of scope deletion. See the PROTECTED section of the report. Destructive drops are limited to known stale test database name shapes and conservative SQL identifier characters; skipped stale matches are reported in dropped.skipped. Rig dolt_database names used for purge must use the same identifier shape: ASCII letters, digits, underscores, and non-leading hyphens. Missing or silent rig metadata disables forced drop/purge because the live database name cannot be proven safe. JSON envelope schema is stable: gc.dolt.cleanup.v1. Automation that uses —json must inspect summary.errors_total and errors, and must also refuse to invoke —force when dry-run force_blockers is non-empty. force_blockers reports conditions that would block forced cleanup without incrementing errors_total. The rig-protection blocker is intentionally global: missing or silent rig metadata prevents forced drop/purge because the command cannot prove all registered rig databases are protected. Cleanup stage errors are reported in the envelope even when the command can still return successfully after emitting the report.gc event
Event operationsgc event emit
Record a custom event to the city event log. Recording is best-effort: once an event is accepted, a provider or payload error is reported on stderr and the command still exits 0, so bead hooks never fail on it. JSON summaries report whether submission to the configured provider was attempted; the event bus does not acknowledge durable persistence. Four requests are refused with exit 1 and nothing is recorded. In —json mode the failure object carries the code.- reserved_actor: —actor starts with “cache-”, or the default actor is one of the controller cache’s own actors (cache-local, cache-reconcile).
- bead_payload_refused: —payload on bead.created, bead.updated, bead.closed or bead.deleted. Their payload is the bead row; use —bead-payload <id> so gc reads it from the store.
- journal_derived_refused: op.changed or fact.recorded, which the controller derives from operation-journal rows; no command records one.
- bead_payload_not_found: —bead-payload names a bead the store it resolves to does not hold (bead.deleted excepted: the event is recorded with its subject alone). Any other failure to read it is reported on stderr and the event is still recorded, without the payload.
gc events
Show events from the GC API with optional filtering. The API is the source of truth for both city-scoped and supervisor-scoped events. In a city directory (or with —city), this command reflects the city’s /v0/city/{cityName}/events and /stream endpoints. Without a city in scope, it reflects the supervisor’s /v0/events and /stream endpoints. List, watch, and follow output are always JSON Lines. Each line is one API DTO or SSE envelope.gc events reemit-execution
Project exactly one stopped local graph.v2 execution run into execution facts. The default is a dry run. Pass —apply to append the projected snapshot to the default city event log.gc events rotate
Force rotate the city event log through the running supervisor. Output is one JSON line. Empty active logs are successful no-ops.gc extmsg
Manage bindings between external conversations (telegram, discord, …) and gc sessions or configured agents. A conversation bound to an agent name survives session restarts: inbound messages resolve a live session for the agent at delivery time, cold-waking one when none is live. “handoff” rebinds a conversation to another agent — the front-desk pattern: a default-routed agent inspects the conversation and hands it to the right specialist. These commands require the city API server; they have no local fallback.gc extmsg bind
Bind an external conversation to a concrete session (—session) or to a configured agent (—agent). Agent bindings survive session restarts: delivery resolves a live session for the agent each time, cold-waking one when none is live. Binding an actively-bound conversation conflicts; use “gc extmsg handoff” to rebind.gc extmsg handoff
Rebind an external conversation to another configured agent, replacing the active binding. Run from inside an agent session to hand a conversation to the right specialist — the routing judgment lives in the agent’s prompt, this verb is pure transport.gc extmsg unbind
Remove active external-conversation bindings. Filter by conversation (—provider/—conversation-id), by —agent, by —session, or a combination. At least one filter is required.gc formula
Manage and inspect formulas. A formula is a reusable TOML method for how multi-step work should be done (a bead is the work itself). See docs/reference/specs/formula-spec-v2.md for the file format, the formulas v2 contract, and the [requires] formula_compiler opt-in.gc formula cook
Compile and instantiate a formula as real beads in the current store. This is a low-level workflow construction tool. It creates the formula root and all compiled step beads without routing any work. With —attach=<bead-id>, the given bead gains a blocking dependency on the sub-DAG root, so it won’t close until the sub-DAG completes. This is a “blocks” dependency only, not a parent-child relationship — the sub-DAG root does not become a child of the attached bead (gc bd list —parent will not find it), and convoy auto-close, which watches parent-child children and “tracks” members rather than blocks dependents, is not triggered by the sub-DAG completing. This is the core primitive for late-bound DAG expansion — any agent, script, or workflow step can call it to expand a bead into a sub-workflow at runtime. With —attach on a v2 formula — one declaring [requires] formula_compiler = ”>=2.0.0” — the invocation runs under a per-source workflow lock and is idempotent: a repeat cook for the same source bead reuses the live workflow instead of duplicating it, and a conflicting live workflow from the same source is an error. A repeat cook still writes its —meta pairs to the workflow root it reuses, under the same lock, so the pairs of the last cook to take the lock are the ones that stay. On a city that serves the graph class from its own [storage] binding, most of —attach is NOT SUPPORTED YET, in city and rig scope alike, and refuses rather than serving. A graft is graph class whatever the formula’s version — every bead it creates carries gc.root_bead_id — so the sub-DAG belongs in the binding while the blocking dependency belongs beside the attach bead, and a split city cannot have both:- attach bead in the city’s WORK ledger — refused. Writing the sub-DAG beside it strands graph-class beads in the work store, which gc storage status reports and exits non-zero on; writing it into the binding leaves the work store holding a blocks row naming an id it cannot resolve, which never clears. Representing that block across the store boundary needs a cross-class membership edge: ga-2orlf.
- attach bead in the BINDING, v2 (graph.v2) formula — refused. It normalizes its target into a synthetic input convoy, which is a work bead that can live in neither store; its membership edge to the target would be cross-class. Same remedy: ga-2orlf.
- attach bead in the BINDING, v1 formula — served. The sub-DAG and its blocking dependency are both written to the binding.
- attach bead in a RIG’s own store (RIG scope: —rig, GC_RIG, or a cwd inside a rig) — refused for a work bead, for the city work ledger’s reason: every graph bead of every rig lives in the binding, so a rig’s own store holds only work. Launch the formula against the bead with gc sling <target> <bead> —on <formula> instead. The one graft served there is a v1 formula onto a graph bead of a tree created before the rig’s graph beads moved to the binding, which extends that tree where it lives; a v2 formula is refused, because it starts a new workflow root in the binding and its attach edge would cross stores.
gc formula list
List all formulas available in the city’s formula search paths. Formulas are discovered from the well-known formulas/ directories of city and rig pack layers, the city’s own formulas/ directory, and the rig-local formulas_dir directory. Later layers win for same-named formulas.gc formula show
Compile and display a formula recipe. By default, shows the recipe with {{variable}} placeholders intact. Use —var to substitute variables and preview the resolved output. When —rig is set (or cwd is inside a rig), rig-scoped formula_vars from city.toml are shown as “(rig default=…)” alongside each applicable var. An explicit —city pins city scope, which has no rig-scoped formula_vars. Examples: gc formula show mol-feature gc formula show mol-feature —var title=“Auth system” —var branch=main gc formula show mol-polecat-work —rig mogc formula version-check
Compare the formula content hash stored on a molecule/workflow bead against the current on-disk formula file. Exits 0 if they match, 1 if they diverge. The bead must have gc.formula_hash metadata (set during instantiation). The formula is located via the bead’s Ref field and the current formula search paths. Use this to detect whether a running session’s formula has been updated since it was spawned.gc github
GitHub integration commandsgc github pr
GitHub pull-request monitor commandsgc github pr backfill
Query configured GitHub PR readiness monitors. The command reads [[github.pr_monitor]] entries from the resolved city configuration, queries open pull requests from GitHub, and reports PRs that need repair: failed checks, merge conflicts, blocked mergeability, or branches behind their base. By default clean and pending-only PRs are omitted; pass —all to include every observed PR.gc graph
Show the dependency graph for a set of beads or a convoy. Resolves dependencies via the bead store and prints each bead with its status and what blocks it. Convoys are expanded to their children automatically. Readiness is computed within the displayed set. By default prints a table. Use —tree for a Unicode tree view or —mermaid for a Mermaid.js flowchart you can paste into Markdown.gc handoff
Convenience command for context handoff. Self-handoff (default): sends mail to self. If the current session is controller-restartable, requests a restart, pokes the controller for an immediate reconcile tick, and returns without waiting for the controller to act. For on-demand configured named sessions, sends mail and returns without requesting restart: handoff intentionally leaves the user-attended session running instead of restarting it out from under the user. The controller can restart such a session via gc runtime request-restart; handoff deliberately does not. For controller-restartable sessions, equivalent to: gc mail send $GC_ALIAS <subject> [message] gc runtime request-restart The restart request is recorded on this session’s row, bound to this session’s incarnation: it is recorded only while the session row, or the live runtime under the session’s name, still carries the GC_INSTANCE_TOKEN this process runs under. A check before the mail refuses the restart, and sends no mail, when this process has no GC_INSTANCE_TOKEN (an agent CLI that scrubs TOKEN variables from the shells it spawns removes it), when the session row and the live runtime name another incarnation, or when the session store cannot compare-and-swap where the request needs it (below). The write after the mail decides again: a row that moved after the check can still refuse it there, with the mail already sent. Outside a worker site the runtime’s GC_RESTART_REQUESTED hint follows, then the controller poke. gc handoff exits 0 once the request is recorded, even when the controller could not be signaled: a warning says so, and the controller acts at its next pass. It exits 1 with no restart requested and no runtime hint set when the request cannot be recorded: no GC_INSTANCE_TOKEN, an unreachable session store, a session whose row and live runtime name another incarnation, or a session store that cannot compare-and-swap where the request needs it: a v2 city records the request only by compare-and-swap, and [beads] conditional_writes = “require” refuses any write the store cannot fence. Auto handoff (—auto): sends mail to self and returns without requesting a restart. This is for PreCompact hooks, where the provider is already managing the context compaction lifecycle. Remote handoff (—target): sends mail to a target session. If the target is controller-restartable, kills it so the reconciler restarts it with the handoff mail waiting. For on-demand configured named targets, sends mail and returns without killing the session. For controller-restartable targets, equivalent to: gc mail send <target> <subject> [message] gc session kill <target> While the op journal records ops, a restartable self-handoff is recorded as a restart{fresh} op and a notice op to self; a rerun with the same —key reports the first run’s outcome without sending the mail again. The key covers neither the subject nor the message: a rerun under it sends no mail whatever they say, and its —json result leaves the subject out. The key is the handoff’s own: gc runtime request-restart or gc session reset under the same —key records another op. The restart stops this session, and so can stop the run before it closes its restart op: a rerun with the same —key is then refused as in progress until the op’s deadline passes, and after that replays the first run’s success when its notice op succeeded and the session row shows that the restart is still pending or has run, else reports the op’s failure. The notice op rides the restart op: when the restart op is not recorded (ops.lifecycle off), no notice op is recorded either, even under ops.content = “require”. —auto and —target record no ops and refuse —key. A self handoff of a session the controller does not restart records no ops and warns that —key is not recorded. Self-handoff requires session context (GC_ALIAS or GC_SESSION_ID, plus GC_SESSION_NAME and city context env). Remote handoff accepts a session alias or ID. Subject is required unless —auto is set.gc help
Help provides help for any command in the application. Simply type gc help [path to command] for full details.gc hook
Finds routed work using the agent’s work_query config. Without —inject: prints normalized ready-only output, exits 0 if work exists, 1 if the queue is empty, and 2 if the work query itself failed (for example bd missing from PATH, a store bd could not read, or a store environment that could not be built); the failure is named on stderr. A suspended city, rig or agent, and an error before the work query is built (no agent named, a city or config that cannot be loaded, an unknown agent), also exit 1. With —inject: silent legacy Stop-hook compatibility; skips the work query and always exits 0. With —claim: runs the standard startup claim protocol for one work item. A failed work query is an error (nothing on stdout), never a drain result. A work query that gets no answer from the bead store (a connection error, a timeout, a killed query, a locked database, or bd’s circuit breaker failing fast) exits 2 and prints GC_HOOK_STORE_UNAVAILABLE on stderr: the answer is unknown, not empty. This applies with and without —claim. The answers that count as “no answer” are shared with the storage gate’s transient faults and include a hosted bd serve answering 502, 503 or 504, “cannot reach bd serve”, a killed bd (“signal: killed”), “too many open files”, network timeouts and unreachable hosts (EHOSTUNREACH), and EMFILE/EAGAIN; each of these exits 2 with the token (stdout keeps any partial output). Any other work-query failure exits 2 without —claim and 1 with —claim. Neither writes a drain result. When another store the hook searches serves work, a store that failed is named on stderr and the work is served; when no store has work, a failed read of any of them is a failed query, not an empty queue, so a rig store that cannot be read keeps every city-scoped agent that searches it from draining until it answers again. Two kinds of rig are exceptions: a suspended rig is not searched at all (gc ready does not read it either), and a rig whose managed Dolt server is not running is named on stderr but does not hold the answer up. A failed query is also recorded as a session.work_query_failed event, one per store that failed, naming it. Before the work query, a session keyed by $GC_SESSION_ID is checked for a pending drain (the drain fence), with and without —claim. A draining session gets the drain result instead of work. If the session row cannot be read, the fence depends on why. A store fault that may clear on its own (a timeout, a locked database, a work store the storage gate could not read) fails open: the hook proceeds, names the fault on stderr, and records a session.drain_fence_unavailable event. A standing storage refusal (the city’s storage gate refuses to serve its relocated classes, for example a retained work store holding infrastructure beads the binding cannot read) fails closed: nothing is claimed or served, GC_HOOK_STORE_UNAVAILABLE is printed on stderr with the refusal, the hook exits 2, and the event says the fence failed closed. The agent is determined from $GC_AGENT or a positional argument.gc hook current
Prints the work bead this session most recently claimed with gc hook —claim. The claim protocol stamps the claimed bead id onto the calling session’s own bead, because the environment alone cannot reliably name it: GC_TRIGGER_BEAD_ID — exported to demand-spawned pool seats as a pool-level spawn marker — is absent on other seats (e.g. a warm seat bound after start) and never decides what a session claims; the pool is pull. Named singleton sessions can carry a stale $GC_TRIGGER_BEAD_ID for their entire lifetime, pointing at a different bead than the one currently claimed, so it must never be consulted ahead of the claim. A formula step that must close the bead it is running reads the stamp back here: BEAD_ID=“{GC_BEAD_ID:-(gc hook current —id-only)}” The calling session is taken from $GC_SESSION_ID. Exits 1 when there is no session identity and when the session has claimed nothing, so a caller that cannot name its bead fails loudly instead of skipping its own work.gc hook run
Runs a managed gc hook command in a child process with a hard timeout. This protects provider hook callbacks from wedged data-plane commands. The child process is the current gc executable, and <gc args…> are passed to it verbatim.gc import
Manage pack importsgc import add
Add a pack import. The source argument is resolved once and written as a durable [imports.<name>] entry using source plus optional version. Supported sources are:- local paths outside git worktrees: stored as plain paths, with no lock entry
- local paths inside git worktrees at HEAD: promoted to a file:// repo source with the pack subpath and locked to the current commit
- remote git repositories: cloned and locked; —version accepts a semver constraint or sha:<commit>. Without —version, a source the city already imports or locks keeps the constraint the city holds for it, so its packs.lock entry does not move (a local path inside a git worktree is still locked to its current commit)
- packs published in a configured pack registry: a semver —version (or no —version) resolves against the registry’s release entries, not git tags; the constraint is kept, the lock records the release version and commit, and the fetched content must match the release’s content hash
- remote GitHub repository subpaths: use dereferenceable tree URLs such as https://github.com/org/repo/tree/main/packs/foo
gc import check
Validate installed pack import stategc import credential
Manage pack-source git credentialsgc import credential add
Register a pack-source credentialgc import credential list
List registered pack-source credentialsgc import credential remove
Remove a registered pack-source credentialgc import install
Install imports from pack.toml and packs.lockgc import list
List imported packsgc import prune
Remove unreferenced clones from the machine-wide pack cache. The pack cache (~/.gc/cache/repos) is shared by every city on the machine and is keyed by (source, commit), so commit churn accumulates stale clones over time. A clone is “referenced” when some city’s packs.lock still pins it; prune keeps every referenced clone and removes only the rest. By default prune considers every city in the supervisor registry plus the city resolved from the current directory; pass —all-cities to reference the full registry set and ignore the current directory. Prune is a dry run unless —apply is given. The —keep-days guard never removes an unreferenced clone whose directory was modified more recently than N days ago, protecting in-flight installs from a race.gc import remove
Remove a pack importgc import status
Report declared imports and packs.lock pins. Covers every import scope (root pack [imports.], [defaults.rig.imports.], and rig-scoped [rigs.imports.*]) plus the full packs.lock closure and the lockfile content hash. With —json the output is a stable machine-readable document for drift checkers.gc import upgrade
Upgrade imported packs within their constraintsgc import why
Explain why an import is presentgc init
Create a new Gas City workspace in the given directory. With no path, the current directory is used only when stdin is an interactive terminal; otherwise pass an explicit path (”.” for the current directory). Runs an interactive wizard to choose a config template and coding agent provider. Creates the .gc/ runtime directory plus pack.toml, city.toml, the standard top-level directories, and .template.md prompt templates, and pins the builtin pack imports (resolved from the user-global pack cache). Use —template with —default-provider and an explicit path to create a city non-interactively, or —file to initialize from an existing TOML config file. Pass —preserve-existing to keep any pre-authored pack.toml, city.toml, or agent prompt files in the target directory (useful when bootstrapping a committed workspace — e.g. from a bootstrap.sh shipped in the repo).gc lint
Validate a pack before merge. gc lint <pack> validates the pack.toml file, reports non-fatal loader warnings, and parses prompt templates with the same missing-key behavior used by runtime prompt rendering. Use gc lint . to recursively find every pack.toml below the current directory.gc login
Log in to a hosted Gas City service and store a local API token. By default this targets https://gascity.com; pass —at <url> to log in to any server that implements the Gas City Service Protocol v0. It opens a browser to sign in; use —device for headless shells, or —token to store an existing token. The token is stored per service under ~/.gc/credentials.json.gc logout
Log out of a hosted Gas City service: revoke the session server-side, then remove the stored token. Because the session is the only long-lived credential, this is the kill switch for a leaked ~/.gc/credentials.json — the local token is always removed even if the server-side revoke fails or is not yet supported.gc mail
Send and receive messages between agents and humans. Mail is implemented as beads with type=“message”. Messages have a sender, recipient, subject, and body. Use “gc mail check —inject” in agent hooks to deliver mail notifications into agent prompts.gc mail archive
Remove one or more message beads without displaying their contents. Use this to dismiss messages without reading them. Each message is removed and will no longer appear in mail check or inbox results. When multiple IDs are passed, they are archived in input order. For large advisory backlogs, use —to or —all-recipients with —subject-prefix, —subject-contains, or —from to archive a bounded matching slice without enumerating IDs by hand.gc mail check
Check for unread mail addressed to a session alias or mailbox. Without —inject: prints the count and exits 0 if mail exists, 1 if empty. With —inject: outputs a <system-reminder> block suitable for hook injection (always exits 0). The recipient defaults to GC_ALIAS, $GC_AGENT, or “human”.gc mail count
Show total and unread message counts for a session alias or human. The recipient defaults to GC_ALIAS, $GC_AGENT, or “human”.gc mail delete
Delete one or more messages by closing the beads. Same effect as archive but with different user intent. When multiple IDs are passed, they are deleted in a single batch round-trip.gc mail inbox
List all unread messages for a session alias or human. Shows message ID, sender, subject, and body in a table. The recipient defaults to GC_ALIAS, $GC_AGENT, or “human”. Pass a session alias to view another inbox.gc mail mark-read
Mark one or more messages as read without displaying them. They will no longer appear in inbox results. When multiple IDs are passed (as separate arguments, or as one whitespace-separated argument such as an unsplit “$IDS”), each is marked in input order; a failure on one is reported and the rest are still marked.gc mail mark-unread
Mark a message as unread. The message will appear again in inbox results.gc mail peek
Display a message without marking it as read. Same output as “gc mail read” but does not change the message’s read status. The message will continue to appear in inbox results.gc mail read
Display a message and mark it as read. Shows the full message details (ID, sender, recipient, subject, date, body). The message stays in the store — use “gc mail archive” to remove it.gc mail reply
Reply to a message. The reply is addressed to the original sender. Inherits the thread ID from the original message for conversation tracking. Use —notify to request a recipient turn after replying. In a managed city, it can request a wake for a non-running recipient. Unread mail alone does not request a wake. Use -s/—subject for the reply subject and -m/—message for the reply body.gc mail send
Send a message to a session alias or human. Creates a message bead addressed to the recipient. The sender defaults to GC_ALIAS, $GC_AGENT, or “human”. Use —notify to request a recipient turn after sending. In a managed city, it can request a wake for a non-running recipient. Unread mail alone does not request a wake. Use —from to override the sender identity. Use —to as an alternative to the positional <to> argument. Use -s/—subject for the summary line and -m/—message for the body text. Use —all to broadcast to all live sessions (excluding sender and “human”). Use —dedup <key> for repeating notifications (patrol and cooldown orders that re-detect the same condition every run): the send is suppressed while a previous message with the same key is still live (un-archived) in the same mailbox, and an alias and the session behind it count as one mailbox. Suppression exits 0. Once the recipient archives the message the stream may alert again; senders that want a longer re-alert cadence keep their own last-sent state. Dedup needs a provider that can query its own message history. The built-in provider can; one that cannot sends normally and says so on stderr, because a duplicate notification beats a dropped one.gc mail thread
Show all messages sharing a thread ID or message ID, ordered by time.gc maintenance
Manage periodic Dolt store maintenance (see docs/adr/0002-dolt-store-maintenance-runbook.md). The weekly loop runs inside the supervisor process when [maintenance.dolt] enabled=true in city.toml. ‘status’ shows loop state and recent runs; ‘dolt-gc’ triggers a manual run.gc maintenance dolt-gc
Trigger a Dolt store maintenance rungc maintenance status
Show Dolt store maintenance statusgc mcp
Inspect the projected MCP catalog for a concrete target. Projected MCP is target-specific. Use “gc mcp list —agent <name>” when the agent has a single deterministic projection target from config, or “gc mcp list —session <id>” for a live session target.gc mcp list
Show the precedence-resolved MCP servers that Gas City would project into the provider-native config for one agent or session target. Servers from a shared layer (the city or rig pack, or an import) that the target’s provider cannot receive are listed separately under “Not projected”, with the reason: the agent starts without them.gc metrics
Inspect or control Gas City command usage metricsgc metrics example
Print the fixed state-independent command-usage request examplegc metrics off
Disable command usage metrics and delete local queued datagc metrics on
Read and accept the command-usage disclosure on a verified TTYgc metrics status
Show redacted local command-usage metrics statusgc nudge
Inspect and deliver deferred nudges. Deferred nudges are reminders that were queued because the target agent was asleep or was not at a safe interactive boundary yet.gc nudge drop
Dead-letter one or more pending or in-flight nudges by ID. Each dropped nudge is terminalized through the same dead-letter path a failed delivery attempt uses, so it lands in “gc nudge status” as dead rather than disappearing silently. Find IDs with “gc nudge status”. Dropping an in-flight nudge dead-letters it even if it was already injected into the session but not yet acked. This only accepts explicit nudge IDs; it does not do bulk or age-based selection.gc nudge status
Show queued and dead-letter nudges for a session. Defaults to GC_SESSION_ID when run inside a session.gc order
Manage orders — scheduled or event-driven dispatch of formulas and scripts. Orders live in flat orders/<name>.toml files. Each order pairs a trigger condition (cooldown, cron, condition, event, or manual) with an action (a formula or an exec script). The controller evaluates triggers on each tick and dispatches work when a trigger opens.gc order check
Evaluate trigger conditions for all orders and show which are due. Prints a table with each order’s trigger, due status, and reason. Returns exit code 0 if any order is due, 1 if none are due.gc order history
Show execution history for orders. Queries bead history for past order runs. Optionally filter by order name. Use —rig to filter by rig. The read is bounded by default: only the most recent runs are fetched. Widen it with —limit (0 fetches every retained run) or bound it by time with —since. On a city with a long order-run history an unbounded read costs tens of seconds, so prefer keeping a bound when triaging.gc order list
List all available orders with their trigger type, schedule, and target. Scans orders/ directories for flat .toml files defining trigger conditions, scheduling parameters, and target pools.gc order run
Execute an order manually, bypassing its trigger conditions. Formula orders instantiate a wisp from the order’s formula and route it to the configured target (if any). Exec orders run their script directly — no wisp is created, and —json is rejected because the exec body may write arbitrary stdout. Useful for testing orders or triggering them outside their normal schedule. Use —rig to disambiguate same-name orders in different rigs. Use —var key=value (repeatable) to pass args to the order: formula orders receive them as formula vars, exec orders as environment variables. A param declared required in [order.params] must be supplied or the run fails. An order whose requires_backend does not name its scope’s backend is refused; —force runs it anyway.gc order show
Display detailed information about a named order. Shows the order name, description, formula reference, trigger type, scheduling parameters, check command, target, and source file. Use —rig to disambiguate same-name orders in different rigs.gc order sweep-nudge-mail
Close stale delivered nudge beads and read mail beads. Nudge beads that are past —nudge-ttl and not in the live nudge queue are closed. Read mail beads past —mail-ttl are closed. Closing unread mail is opt-in: when —unread-mail-ttl (or [mail] unread_retention_ttl) is set, unread mail beads past it are also closed, so mail nobody ever reads ages out instead of accumulating forever. A budget cap of 50 closes per invocation prevents runaway sweeps under load. Use —dry-run to log what would be closed without making any changes. The controller watchdog also runs this sweep automatically every 5 minutes.gc order sweep-tracking
Close stale open order-tracking beads and prune expired closed history. This is intended for maintenance exec orders. It only closes tracking beads older than —stale-after so a fresh in-flight order is not interrupted. Closed order-tracking history is deleted after [beads.policies.order_tracking].delete_after_close, defaulting to 7d, while always retaining at least the latest 10 closed tracking beads per order. The manual command runs to completion; controller startup and watchdog sweeps use bounded cleanup to avoid spending an unbounded tick on stale work. Use —include-wisps for operator recovery of abandoned order-run wisp subtrees whose open descendants are also older than —stale-after. Pass one or more scoped order names when —include-wisps is set; wisp recovery is order-scoped to avoid scanning unrelated beads. When the number of eligible closed-bead deletions exceeds GC_BULK_DELETE_CONFIRM_THRESHOLD (default 20), —confirm is required to proceed. This guard prevents accidental mass-deletes without an explicit operator acknowledgement.gc pack
Manage remote pack sources that provide agent configurations. Packs are git repositories containing pack.toml files that define agent configurations for rigs. They are cached locally and can be pinned to specific git refs.gc pack fetch
Clone missing and update existing remote pack caches. Fetches all configured pack sources from their git repositories, updates the local cache, and writes a lockfile with commit hashes for reproducibility. Automatically called during “gc start”.gc pack list
Show configured pack sources with their cache status. Displays each pack’s name, source URL, git ref, cache status, and locked commit hash (if available).gc pack registry
Manage configured Gas City pack registries, inspect cached catalog entries, authenticate to the hosted Registry, and publish packs. Native Registry login stores a per-registry API token. When no explicit, environment, stored native, development, or GitHub Actions credential applies, the canonical hosted Registry uses the existing Gasworks login through “gasworks credential-provider”. Set GC_CREDENTIAL_PROVIDER to a JSON argv array to configure that command without invoking a shell. Gasworks credentials are never persisted by gc and are never sent to custom Registry origins.gc pack registry add
Add a pack registrygc pack registry list
List configured pack registriesgc pack registry login
Log in to Gas City Registry and store a local API token. By default this opens a browser for GitHub or Google Workspace sign-in. Use —device for headless shells, or —token to store an existing registry token.gc pack registry publish
Submit a pack publish request to Gas City Registry. The command requires a clean Git checkout whose current HEAD matches its configured upstream branch, then submits the GitHub repository, commit, pack path, pack name, and version to the registry API. Registry pack names are scoped as <github-owner>/<pack>, where <github-owner> is the lowercased GitHub owner of the source repository. [pack].name must already carry that scoped name: the registry compares it byte-for-byte with the requested name, and reserves unscoped names for packs it already holds a claim for. —allow-unscoped-name submits such a legacy unscoped name anyway. —dev-auth (localhost only) replaces all other credentials. Otherwise, authentication precedence is —token, GC_REGISTRY_TOKEN, a complete session cookie and CSRF-token pair from flags or the environment, a stored native Registry token, GitHub Actions OIDC, then the existing Gasworks login for the canonical hosted Registry. Run “gasworks login” once before using the provider, or use “gc pack registry login” to create a separate native Registry token.gc pack registry refresh
Refresh cached pack registry catalogsgc pack registry remove
Remove a pack registrygc pack registry requests
Show recent publish requests you submitted to Registry, or one request with its feedback comments. This command is read-only. Use a personal Registry token; run “gc pack registry login” if you have not logged in yet.gc pack registry search
Search cached pack registry catalogsgc pack registry show
Show one pack registry entrygc pack registry whoami
Show the Registry account for the active credential. Explicit, environment, and stored native Registry tokens take precedence. For the canonical hosted Registry, gc otherwise uses the existing Gasworks login through the configured credential provider without storing its credential.gc pack release
Author pack registry release metadata, including canonical pack content hashes.gc pack release hash
Compute a pack release content hashgc pack release stamp
Stamp a registry release entry with a computed content hashgc pack release validate
Validate registry release content hashesgc pack release verify
Verify a pack release content hashgc prime
Outputs the behavioral prompt for an agent. Use it to prime any CLI coding agent with city-aware instructions: claude “(gc prime worker)” Runtime hook profiles may callgc prime --hook.
When agent-name is omitted, GC_ALIAS is used (falling back to GC_AGENT).
If agent-name matches a configured agent with a prompt_template,
that template is output. Otherwise outputs a default worker prompt.
Pass —strict to fail on debugging mistakes instead of falling back to
the default prompt. Strict errors on:
- no city config found
- city config fails to load
- no agent name given (from args, GC_ALIAS, or GC_AGENT)
- agent name not in city config (typo detection — the main use case)
- agent’s prompt_template points at a file that cannot be read
- agent’s prompt_template fails to parse or execute
gc prompt
Subcommands for authoring agent prompt templates. Currently the only subcommand is ‘synth’, which invokes the configured provider in one-shot mode to generate a prompt template for a given role.gc prompt synth
Renders a meta-prompt with the given parameters, invokes the configured provider in one-shot mode, and emits the generated prompt template. The default behavior prints the generated prompt to stdout. Pass —write to save it directly to <city>/agents/<role>/prompt.template.md (use —force to overwrite an existing file). Context type is determined by —rig: (no —rig) City context. The agent is HQ-only and operates at the city level (e.g. mayor, deacon). The meta-prompt emphasizes coordination, dispatch, monitoring. —rig <name> Rig context. The agent is attached to the named rig (looked up in city.toml). The meta-prompt includes the rig path, default branch, and project-aware guidance (git operations, branch management, etc.). Auto-detection: —provider defaults to workspace.provider in city.toml Baseline: The synth pulls in an existing prompt template as a refinement baseline so the LLM iterates on a known-good shape rather than designing from scratch. Resolution priority:- <city>/agents/<role>/prompt.template.md (user customization)
- <composed pack dirs>/agents/<role>/ (pack default)
- embedded prompts/<role>.md (built-in fallback)
- embedded prompts/mayor.md (structural reference, used only when no role-specific source exists)
gc ready
List ready, claimable work as a JSON array, federating the city store, the rig stores, and — on a split city — the relocated graph store where molecule roots, step beads and control beads live. It is the in-process, city-wide drop-in for the single-store “bd ready” work query, so workers and the control plane see graph-class work instead of an authoritative-looking short answer. On a city that relocates no coordination class there is no graph store to add: it reads the city store and the rig stores. The flags mirror the “bd ready” contract the default work_query builds: gc ready —metadata-field “gc.routed_to=$target” —unassigned—exclude-type=epic —exclude-label “hold:mayor”
—exclude-label “hold:external” —exclude-label “human”
—json —limit=20 Rows are emitted in canonical ready order (priority, created_at, id) unless —sort selects a created_at order, and —limit is applied last, so a bounded read is the true top-N of the merged set rather than the top-N of whichever store answered first. The rows of —status in_progress carry their blockers (blocked_by), and a row whose blockers cannot be resolved fails the read. —until-unblocked ends that answer at its first unblocked row, the one a crash-recovery read resumes, and resolves no row past it, so a later row’s unresolvable blocker does not fail the read. Every leg is read across both storage tiers, so the wisp/ephemeral rows an orchestration step runs as are claimable work here whether or not —include-ephemeral is passed. Suspended rigs are not read: rigs suspended with “gc rig suspend”, or declared suspended_on_start and not resumed. Their agents claim nothing and the controller counts no demand in them, so this reads the same rigs the controller does; their work comes back when the rig is resumed. The city store and a relocated graph store are always read. When the city’s controller is running, it answers the query from the stores it already holds open (GET /v0/city/{cityName}/work/ready), with the reader this command runs, reading every store live, never from a cache. It reads the rigs of the config the controller has loaded: a rig added, removed or rebound in the city’s config takes effect in its answer at the controller’s next config reload. It refuses while a config reload or an API config write is in progress, and after a failed reload until one succeeds; a [storage] change fails every reload until it is reverted or the city restarts. If the controller is not running, refuses, or does not answer within 10s, this command loads the config and reads the stores itself. GC_NO_API=1 forces the local read.
gc register
Register a city directory with the machine-wide supervisor. If no path is given, registers the current city (discovered from cwd). Use —name to set the machine-local registration alias. The alias is stored in the machine-local supervisor registry and never written back to city.toml. When —name is omitted, the current effective city identity is used (site-bound workspace name if present, otherwise legacy workspace.name, otherwise the directory basename) — in every case city.toml is not modified. Registration is idempotent — registering the same city twice is a no-op. The supervisor is started if needed and immediately reconciles the city.gc reload
Force the current city controller to re-read effective config and process one reload tick without restarting the city/controller. Reload may fetch configured remote packs before recomputing effective config. By default, per-session restarts may still happen if normal config drift rules require them. With —soft, the controller accepts any detected per-session config drift instead of draining the drifted sessions: each open session’s recorded config hash is updated to the hash the freshly reloaded config produces for it, the matching hash breakdown is refreshed, and any already queued config-drift drain for that session is canceled. The immediately-following reconcile tick sees no drift and no config-drift drains fire. Useful when editing a running city’s .gc/settings.json without disrupting in-flight work. Sessions whose template no longer maps to a configured agent are NOT updated; normal orphan/suspended drain handles them on the next tick.gc restart
Restart the city by stopping it then starting it again. Equivalent to running “gc stop” followed by “gc start”. Under supervisor mode this unregisters the city, then re-registers it and triggers an immediate reconcile.gc resume
Resume a suspended city by recording an explicit “resumed” preference in .gc/runtime/suspension-state.json. The override sticks across city restarts even when [workspace] declares suspended_on_start = true. Restores normal operation: the reconciler will spawn agents again and gc hook/prime will return work. Use “gc agent resume” to resume individual agents, or “gc rig resume” for rigs.gc rig
Manage rigs (external project directories) registered with the city. Rigs are project directories that the city orchestrates. Each rig gets its own beads database, agent hooks, and cross-rig routing. Agents are scoped to rigs via their “dir” field.gc rig add
Register an external project directory as a rig. Initializes beads database, installs agent hooks if configured, generates cross-rig routes, and appends the rig to city.toml. If the target directory doesn’t exist, it is created. Use —include to import a pack into the rig; repeat the flag to compose multiple packs for one rig. Each —include becomes a [rigs.imports.<binding>] entry in city.toml, resolved the way “gc import add —rig <rig>” resolves an import: a bundled pack is pinned to the version shipped with gc; any other remote source gets the version constraint gc import add would write (the constraint the city already holds for that source, else the newest registry release, else the newest semver tag, else the remote HEAD commit) plus a packs.lock entry; a remote source with an embedded “#ref” and a local path are imported as given, with no packs.lock entry. If a version cannot be resolved, nothing is written. Imports do not honor a “#ref”: the city fails to load until gc import install locks such a source, at a commit chosen without the ref; use gc import add —rig <rig> —version to pin a version. —include takes a pack source (local path or remote URL) or a pack name: a bundled pack (“gastown”), or a registry pack resolved from the cached registry catalogs, including a scoped community name (“owner/pack”). A ”./” prefix or a “packs/<name>” token is never read as a registry name (a bundled pack still canonicalizes, so ”./gastown” resolves to the bundled source), and an existing directory always wins over a registry pack of the same name. The binding defaults to the pack’s name (its [packs] key or the source’s last path segment). Write —include <binding>=<source> to choose it, for example —include gt=gastown. A binding is letters, digits, ”-” and ”_”, starting with a letter or digit, and an explicit binding may not name a different pack than another —include. Prefix a path with ”./” if its name itself contains ”=”. Use —name to set the rig name explicitly (default: directory basename). Use —prefix to set the bead ID prefix explicitly (default: derived from name). Use —default-branch to set the rig’s mainline branch explicitly. By default, gc rig add probes the repo’s remote HEADs — origin first, then any other configured remote — and falls back to the currently checked-out branch, then stores the result in city.toml so polecats and the refinery target the right branch without manual metadata patching. The banner reports which remote answered, or says the branch was inferred when no remote HEAD is set. Use —start-suspended to add the rig in a suspended state (dormant-by-default). The rig’s agents won’t spawn until explicitly resumed with “gc rig resume”. Use —adopt to register a directory that already has a fully initialized .beads/ directory (must include both metadata.json and config.yaml). For managed-Dolt rigs, runs an idempotent config sync (registers types.custom and other config into the DB, never destructively reinitializes). The git repo check remains informational.gc rig list
List all registered rigs with their paths, prefixes, default branches, and beads status. Shows the HQ rig (the city itself) and all configured rigs. Each rig displays its bead ID prefix, recorded default branch when set, and whether its beads database is initialized.gc rig remove
Remove a rig from the current city’s configuration. Removes the rig entry from city.toml and removes its machine-local path binding from .gc/site.toml.gc rig restart
Kill all agent sessions belonging to a rig. The reconciler will restart the agents on its next tick. This is a quick way to force-refresh all agents working on a particular project.gc rig resume
Resume a suspended rig by recording an explicit “resumed” preference in .gc/runtime/suspension-state.json. The override sticks across city restarts even when the rig declares suspended_on_start = true. The reconciler will start the rig’s agents on its next tick.gc rig set-endpoint
Set the canonical endpoint ownership for a rig. Use —inherit to make a rig derive its endpoint from the current city topology. Use —external to pin the rig to its own external Dolt endpoint. Use —self to mark the rig as running its own local Dolt server on 127.0.0.1 at the given —port; while the city is in managed_city mode the command requires —force because the rig’s .beads/dolt-server.port mirror will no longer track the managed city Dolt. This command owns the rig’s canonical .beads/config.yaml topology state. It refuses a rig whose store the beads provider owns: that rig’s endpoint lives in bd’s own files and is bd’s to change. It also refuses a rig whose .beads/metadata.json records embedded Dolt storage: that rig serves its own store and has no server endpoint.gc rig status
Show rig status and agent running stategc rig suspend
Suspend a rig by recording the suspension in the runtime state file (.gc/runtime/suspension-state.json). All agents scoped to the suspended rig are effectively suspended — the reconciler skips them and gc hook returns empty. The rig’s beads database remains accessible. Use “gc rig resume” to restore. Suspension state is stored in the runtime directory, not city.toml, so it is local to this machine and does not need to be committed.gc runtime
Process-intrinsic runtime operations called by agent code from within sessions. These commands read and write session metadata to coordinate lifecycle events (drain, restart) between agents and the controller. They are designed to be called from within running agent sessions, not by humans. The exceptions are “gc runtime check” and “gc runtime conformance”, which validate a Runtime Provider Protocol executable — run by humans and runtime-pack CIs — and “gc runtime workdir-export”, which runtime packs call to list the work-dir entries they may copy off the orchestrator host.gc runtime check
Validate a runtime executable against the Runtime Provider Protocol (RPP v0). Runs the protocol handshake, the required lifecycle round-trip (start, is-running, stop, idempotent stop), exercises every capability the handshake declares, and probes optional operations. Optional operations that are absent (exit 2) are reported but never fail the run; everything else that misbehaves does. Exits non-zero if any check fails, so a runtime pack’s CI can gate on it directly. One exception: when the argument resolves to a pack-declared runtime whose [runtimes.<name>] entry declares prompt_delivery = “nudge-fallback”, the nudge probe is reported as “required: nudge” and an absent or broken nudge op fails the run — the declaration is smoke-tested, not trusted. The argument is an executable (path or PATH name) or a pack-declared runtime name: when it names a [runtimes.<name>] entry from the current city’s packs, the check runs against that pack’s declared command. Arguments containing a path separator, or matching an existing file, are always treated as the executable itself. The protocol contract is docs/reference/exec-session-provider.md.gc runtime conformance
Run the golden Runtime Provider Protocol conformance suite against an executable. Every requirement is requirement-coded (RPP-<GROUP>-NNN) and mirrors the in-tree provider contract (RunProviderTests); a run that passes every required requirement is guaranteed to behave like a gascity runtime. Unlike “gc runtime check” (a lighter smoke test), each requirement is proven to gate: the suite is kept honest by negative tests in which a broken reference fails exactly its requirement’s check. The argument is an executable (path or PATH name) or a pack-declared runtime name from the current city’s packs. Path-like or existing-file arguments are always the executable itself. Use —json for a machine-readable report (CI artifacts). Exits non-zero if any required requirement fails.gc runtime drain
Signal a session to drain — wind down its current work gracefully. Sets a GC_DRAIN metadata flag on the session. The agent should check for drain status periodically (via “gc runtime drain-check”) and finish its current task before exiting. Pass a session alias or ID. Use “gc runtime undrain” to cancel. Under the v2 session reconciler it also marks the session row, so the agent’s drain-ack stops the session even on a min_active_sessions floor.gc runtime drain-ack
Acknowledge a drain signal — tell the controller to stop this session. Sets GC_DRAIN_ACK metadata on the session, then pokes the controller socket so the reconciler stops the session immediately rather than on its next patrol tick. Call this after the session has finished its current work in response to a drain signal. Under the v2 session reconciler the ack is first written to the session row, bound to its current incarnation. A session acking itself must carry a GC_INSTANCE_TOKEN that matches the row; an operator acking a session from outside it passes —operator and a target, and the ack binds to the incarnation the command read. A missing or stale token, or a store that is unreachable or keeps changing, exits 1 with nothing acknowledged. Under the legacy reconciler the ack behaves as it always has.gc runtime drain-check
Check if a session is currently draining. Consults two sources: the runtime’s GC_DRAIN metadata flag, which “gc runtime drain” sets, and the session row’s state, which reads draining once the controller has begun stopping the session. Controller drain intents recorded before that point are not consulted yet. Designed for use in conditionals: “if gc runtime drain-check; then finish-up; fi”. Without arguments, uses the current session context. Exit codes: 0 draining: a source that answered says draining 1 not draining: both sources answered and neither says draining; or there is no current session context; or the named session does not exist in a session store that opened; or the —json result could not be written 3 unknown: a source could not be read, or the named session could not be resolved, and no source says draining; one stderr line names the source that failed A runtime that reports the session absent, or keeps no metadata, counts as an answer of “no GC_DRAIN”; any other runtime error, including a runtime that is not running, is a failure to answer. With —json, the result carries a “source” field naming the deciding source; an unknown result is the JSON error envelope with code “drain_state_unknown” and exit code 3.gc runtime heartbeat
Extend the idle-timeout and max-session-age windows during a long operation. Sets held_until on the current session’s bead, suppressing the idle-timeout and max-session-age timers until the hold expires. Call this at the start of slow operations that produce no terminal output and would otherwise trigger a false-alarm watchdog kill. The hold is automatically cleared by the reconciler once held_until passes. This is the agent-facing API for the held_until bead-metadata mechanism; it does not put the session into a suspended state or change its sleep_intent. The default duration (45m0s) covers long-running operations. Pass —duration to override.gc runtime request-restart
Ask the controller to stop this session and start it again fresh. Records the restart request on this session’s row (the request the controller acts on). Outside a worker site it then sets the runtime’s GC_RESTART_REQUESTED hint. Then it pokes the controller for an immediate reconcile. It returns without waiting for the restart. The request is bound to this session’s incarnation. It is recorded only while the session row, or the live runtime under the session’s name, still carries the GC_INSTANCE_TOKEN this process runs under, so a process left over from an earlier incarnation cannot restart its successor. An agent CLI that scrubs TOKEN variables from the shells it spawns (for example Claude Code with CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1) removes GC_INSTANCE_TOKEN, and the request is refused; keep that variable in the agent’s subprocess environment. Exits 0 once the request is recorded, even when the controller could not be signaled: a warning says so, and the controller acts at its next pass. Exits 1 with no restart requested and no runtime hint set when the request cannot be recorded: no session context or GC_INSTANCE_TOKEN, an unreachable session store, a session whose row and live runtime name another incarnation, or a session store that cannot compare-and-swap where the request needs it: a v2 city records the request only by compare-and-swap, and [beads] conditional_writes = “require” refuses any write the store cannot fence. While the op journal records lifecycle ops, the request is recorded as a restart{fresh} op, which closes with the request’s outcome, a refusal included; a rerun with the same —key reports the first run’s outcome instead of requesting again. The key is request-restart’s own: gc handoff or gc session reset under the same —key records another op. The restart stops this session, and so can stop the run before it closes its op: a rerun with the same —key is then refused as in progress until the op’s deadline passes, and after that replays the first run’s success while the session row still records the restart as pending, else reports the op’s failure, also once the restart has run, since the op records no context to tell it by. This command is designed to be called from within a session context. It emits a session.draining event once the request is recorded.gc runtime undrain
Cancel a pending drain signal on a session. Clears the GC_DRAIN and GC_DRAIN_ACK metadata flags, allowing the session to continue normal operation. Pass a session alias or ID. Under the v2 session reconciler it also clears the session row’s drain-ack and its operator drain mark.gc runtime workdir-export
List the entries of a session work dir that a runtime may copy into another filesystem (a remote sandbox, a container image). Orchestrator-local state named by the work_dir_exclude start-config field (secrets, the event log, the nudge queue, ledger stores, sockets, other sessions’ worktrees) is left out; an excluded directory is pruned with everything below it. Paths are relative to <work_dir> and slash-separated, in depth-first walk order with each directory’s entries sorted by name. Every surviving file and symlink is listed, plus every surviving directory that is empty on disk. A non-empty directory is never listed, so a consumer that recurses into listed entries still copies nothing excluded. Symlinks are listed, never followed; copy them as links. Scripts must use —null, which terminates entries with NUL. The default newline-terminated output is for humans only: no byte filter makes it safe for a consumer that splits on blanks or quotes, such as xargs. As a backstop it fails, printing nothing, when an entry contains a newline, a carriage return, or a backslash (GNU tar -T reads “\057” as ”/”), or starts with ”-”. Run the gc that produced the start config (its env.GC_BIN) and check its exit status, for example: set -o pipefail “WORK_DIR” | tar -C “$WORK_DIR” —null —no-recursion -T - -czf - GNU tar reads a —null list verbatim only from 1.30; bsdtar always does. Older GNU tar unquotes backslash escapes even with —null, so a crafted file name can make it archive .gc/controller.token or a file above the work dir. Where GNU tar may predate 1.30, use the form below: 1.29 reads the list verbatim with it, and older releases reject its options, which fails the pipeline. bsdtar rejects those options, so keep the form above there. set -o pipefail “WORK_DIR” | tar -C “$WORK_DIR” —null —verbatim-files-from —no-unquote—no-recursion -T - -czf - The protocol contract is docs/reference/exec-session-provider.md.
gc service
Inspect workspace servicesgc service doctor
Show detailed workspace service statusgc service list
List workspace servicesgc service restart
Stop and restart a workspace service by name. The controller closes the current service process and starts a fresh one. Useful after updating pack scripts without a full city restart.gc session
Create, resume, suspend, and close persistent conversations with agents. Sessions are conversations backed by agent templates. They can be suspended to free resources and resumed later with full conversation continuity.gc session attach
Attach to a running session or resume a suspended one. If the session is active with a live tmux session, reattaches. If the session is suspended or the tmux session died, resumes using the provider’s resume mechanism (if supported) or restarts. Accepts a session ID (e.g., gc-42) or session alias (e.g., mayor).gc session close
End a conversation. Stops the runtime if active and closes the bead. Accepts a session ID (e.g., gc-42) or session alias (e.g., mayor). A rerun with the same —key replays the close only when it names the session by its ID: a closed session’s alias no longer resolves to it, and once another session holds the alias (a configured named session is created again under its name), a rerun by the alias closes that session.gc session kill
Force-kill the runtime process for a session without discarding its work. The kill syncs the session’s lifecycle state to asleep and pokes the controller, so the reconciler observes the dead process promptly and restarts the session according to its lifecycle rules. This keeps Gas City bead continuity: hooks, assignments, and work still point at the same session bead. If the provider has resume metadata, Gas City may attempt provider resume, but provider conversation continuity is not guaranteed; confirm it with the agent or provider after restart. An idle pool seat (no started work and no ready work) is replaced: the reconciler releases the routed work it had not started so another seat can pick it up, closes it, and the pool starts a fresh seat in its slot. A pool seat holding started or ready work restarts in place on its bead; while its started work is blocked, it holds its slot asleep. A task assigned directly to the seat with no route is kept, not released, and the seat holds its slot until that task is ready. With —key, a rerun after the controller restarted the session under the same ID reports the first kill, noting the restart, instead of killing the new run. A pool seat replaced as above is a new session with a new ID, though it may keep the killed seat’s alias: a rerun must name the killed session by its ID, since by the alias it would kill the replacement. While the ops.lifecycle gate is require, a kill whose session row cannot be read, or names no session generation, is refused (op_journal_unavailable, naming unreadable_target and the read error, or no_generation) and nothing is killed. At auto, or with GC_OPS_LIFECYCLE=auto set to break glass, it runs the best-effort kill unrecorded. A recorded kill (the gate at auto or require) names the session generation it read before taking the session’s runtime lease. If a start runs while it waits for that lease, the kill stops nothing and exits 1, its op closed failed{refused:target_moved}: rerun it without —key to kill the new run. A rerun with the same —key replays that failure, noting the restart. Accepts a session ID (e.g., gc-42) or session alias (e.g., mayor).gc session list
List all chat sessions. By default shows active and suspended sessions. With —json the output is one JSON document that validates against “gc session list —json-schema=result”. It has one of two renderings, and the route a command takes decides which one it gets:- Local rendering (a supervisor-hosted city, a city with no reachable API, or GC_NO_API set for a local target; a remote target rejects GC_NO_API): filters, sessions and summary. Each row carries closed, and agent_name when the session has one, and no liveness.
- API rendering (a remote target such as —city-url, a standalone controller’s [api] port, or a supervisor serving a city that has no controller): _cache_age_s and sessions. Each row carries running, and no agent_name or closed.
gc session logs
Show structured session log messages from a session’s JSONL file. Reads the session log, resolves the conversation DAG, and prints messages in chronological order. Searches default paths (~/.claude/projects/) and any extra paths from [daemon] observe_paths in city.toml. Use —tail to print only the last N transcript entries (0 = all). Semantics match Unix ‘tail -n’: ‘—tail 5’ prints the final 5 entries, not the first 5. A single assistant turn with multiple tool-use blocks still counts as one entry. Compact-boundary dividers count as entries when they fall inside the final window. Compatibility note: before 1.0, —tail mapped to compaction segments. As of 1.0, —tail trims the displayed transcript entry window instead. The HTTP API’s tail query parameter still uses compaction-segment semantics. Use -f to follow new messages as they arrive.gc session new
Create a new persistent conversation from an agent template defined in the loaded city configuration. By default, attaches the terminal after creation. When —title-hint is provided without —title, the session title is auto-generated from the hint text: a short version is set immediately and refined by the title model in the background. If the template config sets tmux_alias, it controls the runtime tmux session_name. —alias still sets the public command and mail alias.gc session nudge
Send text input to a running session via the runtime provider. The message is delivered as text content to the session’s input. This is equivalent to typing the message into the session’s terminal. Accepts a session ID or session alias. Multi-word messages are joined automatically. When [ops] authoritative lists message, a nudge to a session a conversation lane can type into is recorded as a lane op instead. wait-idle delivers it as a prompt at an idle boundary only, never into a running turn. immediate delivers it as a prompt at an idle boundary or, when the session’s runtime can steer, into its running turn; a busy session whose runtime cannot steer gets it at the next boundary. queue delivers it as a notice at the next boundary and never wakes the session. When this process can type into the session, wait-idle and immediate deliver at once what their mode allows now, with or without a running controller; otherwise the nudge is reported queued, and the lane host serving the session delivers it as its mode says. The [ops] content gate does not govern such a nudge, and one whose op cannot be written is refused.gc session peek
View session output without attachinggc session pin
Keep a session awake by setting its durable pin override. Pinning does not clear suspend holds or other hard blockers. If the target is a configured named session that has not been materialized yet, pin creates its canonical bead so the reconciler can start it when unblocked.gc session prune
Close dormant sessions older than a given age. By default only suspended sessions are affected — active sessions are never pruned. Pass —state to opt asleep or drained sessions into the same cleanup pass; multiple states may be comma-separated.gc session rename
Rename a sessiongc session reset
Request a fresh restart for an existing session without closing its bead. The controller stops the current runtime and starts the same session again with fresh provider conversation state. Session identity, alias, mail, and queued work remain attached to the existing session bead. For named sessions, reset also clears any tripped named-session respawn circuit breaker before requesting the fresh restart. One case is not an in-place restart. A session whose create never completed, is past its start lease, and has no running runtime cannot be restarted in place, because its unfinished create is what blocks it. Reset rolls that session back instead: it closes the bead as a failed create and releases the alias so the controller can create a replacement. A create that is still starting, or whose runtime is running, is never rolled back. Accepts a session ID (e.g., gc-42) or session alias (e.g., mayor). A rerun with the same —key of a reset that rolled back replays it only when it names the session by its ID: the rollback released the alias, and once the replacement the controller creates holds it, a rerun by the alias resets that session. A —key may not start with handoff: or request-restart:, where gc handoff and gc runtime request-restart keep the keys of the restart ops they record. Such a key is invalid: under ops.lifecycle = “require” the reset is refused, and under “auto” it runs unrecorded with a warning.gc session submit
Submit a user message to a session without choosing provider transport details. The runtime decides whether to wake, inject immediately, or queue the message according to the selected semantic intent.gc session suspend
Suspend an active session by stopping its runtime process. The session bead persists and can be resumed later. Accepts a session ID (e.g., gc-42) or session alias (e.g., mayor).gc session unpin
Remove only the durable pin override from a session. Unpinning does not force an immediate stop. The reconciler will apply the normal wake/sleep rules on its next pass.gc session wait
Register a dependency wait for a sessiongc session wake
Request wake for a session and release user hold or crash-loop quarantine metadata. After waking, the reconciler will start the session on its next tick if it has wake reasons (e.g., a matching config agent). If the session has no wake reasons, it remains asleep. When a configured named session has no session to wake or reopen, the wake creates one as it resolves the target, before the wake is recorded. While the ops.lifecycle gate is require, a wake whose op the journal then cannot record is refused (op_journal_unavailable): the wake did not run, but the session it created stays and may start. Accepts a session ID (e.g., gc-42) or session alias (e.g., mayor).gc shell
The shell integration adds a completion hook to your shell RC file that provides tab-completion for gc commands and flags. Subcommands: install, remove, status.gc shell install
Install or update the gc shell completion hook. If no shell is specified, the shell is detected from $SHELL. The completion script is written to ~/.gc/completions/ and a source line is added to your shell RC file.gc shell remove
Remove the gc shell completion hook from your shell RC file and delete the completion script.gc shell status
Show shell integration statusgc skill
List skills visible to the current city. Output includes:- City pack skills (skills/<name>/SKILL.md under the city root)
- Imported pack shared skills (binding-qualified, e.g. ops.code-review)
- Compatibility bootstrap skills, when legacy implicit imports still exist
- With —agent/—session: that agent’s agents/<name>/skills/ catalog
gc skill list
List the current shared and agent-local visible skills, optionally scoped to an agent or session.gc sling
Route a bead to a session config or agent using the target’s sling_query. The target is an agent qualified name (e.g. “mayor” or “hello-world/polecat”). The second argument is a bead ID, a formula name when —formula is set, or arbitrary text (which auto-creates a task bead). When target is omitted, the bead’s rig prefix is used to look up the rig’s default_sling_targets (or default_sling_target) from config and one is chosen at random. Requires —formula to have an explicit target. Inline text also requires an explicit target. With —formula, the formula is instantiated and its root bead is routed to the target. v2 formulas — those declaring [requires] formula_compiler = ”>=2.0.0” — start a workflow; v1 formulas instantiate a wisp (ephemeral molecule). A v2 formula that references {{convoy_id}} or contains a drain step requires a target convoy: route it with gc sling <target> <bead> —on <formula>, or attach it with gc formula cook —attach. Formula slings to a pool (multi-session) target are rejected unless the compiled root is Ready-visible — a v2 workflow root or a root-only wisp. See docs/reference/specs/formula-spec-v2.md for the formula format and contract details. Examples: gc sling my-rig/claude BL-42 # route existing bead gc sling my-rig/claude “write a README” # create bead from text, then route gc sling mayor code-review —formula # instantiate formula, route its root echo “fix login” | gc sling mayor —stdin # read bead text from stdingc start
Start the city under the machine-wide supervisor. Requires an existing city bootstrapped by “gc init”. Fetches remote packs as needed, registers the city with the machine-wide supervisor, ensures the supervisor is running, and triggers immediate reconciliation. Use “gc supervisor run” for foreground operation.gc status
Shows a city-wide overview: controller state, suspension, all agents with running status, rigs, and a summary count.gc stop
Stop all agent sessions in the city with graceful shutdown. Sends interrupt signals to running agents, waits for the configured shutdown timeout, then force-kills any remaining sessions. Also stops the Dolt server and cleans up orphan sessions. If a controller is running, delegates shutdown to it. If the city is registered with the machine-wide supervisor, stop also unregisters it (equivalent to a following “gc unregister”) — the city will not be found by name or auto-started again until it is re-registered with “gc register”. Use “gc unregister” directly to remove a registration without stopping sessions. gc stop reports “City stopped.” only when it could confirm that every session stopped. If it could not list the runtime’s sessions completely, or could not check whether a session is still running, it names what it could not verify, still stops every session it did see, and exits non-zero; a supervisor registration is restored. Resolve the reported error and run gc stop again. Use —timeout=DURATION to cap the wall-clock time gc stop will spend before giving up; the default budgets configured session interrupt and stop waves, the configured shutdown grace wait, and a second orphan cleanup pass. Use —force to skip the interrupt grace period and go straight to kill.gc storage
Move this city’s storage-class layout, and report on it. These are operator commands. Nothing here runs on boot: a city whose [storage.classes] name a binding it has not converged on refuses to start and names the migrate command, because the source’s writer set is something an operator arranges rather than something a program can observe.gc storage migrate
Copy this city’s infrastructure-class beads out of the work store and into the binding [storage.classes] assigns them to, then clear the work store’s copies. Every bead is copied with its id and its within-class dependency topology preserved, proven field-equal against a closed and reopened destination, and then recorded in a proven-copy manifest and a convergence marker. Nothing in the work store changes before the marker, so a rollback before cutover is a config edit with no data recovery step. Past the marker the binding is the only authoritative copy, so the work store’s now-stale copies are cleared: each is written to a backup beside the manifest (infra.retained-source.jsonl), the backup is re-read and proven equal to the rows it records, and only then are the rows removed. A work bead whose blocking dependency the binding has already satisfied is released; every other cross-store edge is kept. Run it again on a converged city to repair one that still holds its copies — a city migrated by an earlier build, or a clear that was interrupted. Boot refuses such a city and names this command. —from-backup re-copies a binding whose database is gone from that backup instead of from the work store, which no longer holds the slice. —from-rigs moves each rig’s graph and infrastructure beads (closed history, wisps and steps included) out of the rig’s own store and into the city binding, keeping their ids and stamping each with gc.root_store_ref=rig:<name>; a rig store then holds only work. It runs per rig (—rig narrows it), is resumable at every step, and refuses, by bead and with the fix, the edge shapes it cannot carry without a cross-store edge. It needs a converged city binding. Last, on the converged binding, each open deliver-now unit the copy carried in is re-lowered under the binding’s id prefix: its derived interrupt is re-created at the id a lowering there gives it, with its state, and the old row is closed as a pointer to it, one all-or-nothing write per unit. A unit in flight or that may have run, one with more than one open derived interrupt, and one whose id there another row already holds are left as they are and named; their lanes run each one as a unit by identity. A message not yet lowered, or whose unit is over, is not a unit to move, and is not named. A city whose binding holds no lowered deliver-now message skips the step and prints nothing for it. A step that did not finish exits non-zero, and running this command again finishes it. The move refuses while a writer can reach the source. This binary can prove the absence of a controller and cannot prove the absence of anything else, so that half is an explicit operator attestation.gc storage preflight
Run every check gc storage migrate —from-work runs and report what it finds — without copying anything, creating anything, taking the migration guard, or publishing any event. This is for deciding whether the window you are about to take will be spent migrating or spent reading a refusal. It runs against a LIVE city: a controller serving this city is reported by PID rather than refused, because stopping it is the next thing you were going to do anyway. It resolves its destination from [storage.classes], so it has nothing to check until that section names a binding. On a city with no infrastructure split it reports exactly that and exits non-zero — author the split first. It exits non-zero when the migration would refuse for a reason you have to go and fix first. That is a different question from gc storage status, which exits non-zero whenever the city is not yet serving from its binding — the ordinary state of every city with a cutover still ahead of it. One condition is never checked here, because no process can check it: —fleet-stopped attests that every writer that can reach this city’s work store is stopped — not just its controller, which this command proves on its own.gc storage recover-stranded
Copy the infrastructure beads a converged city’s proven copy never carried out of the retained work store and into the binding that is already serving. This is the recovery the stranded-write refusal names. Unless you name a row with —replace-binding-row or —drop-work-row (below), it is additive: it moves only ids the binding does not hold and the proven-copy manifest does not record, it deletes nothing from either store, and it extends the manifest only after every moved bead has been proven equal against a closed and reopened destination. A bead whose class it cannot state is named and left where it is. It refuses on a city that has NOT converged — the whole copy is still owed there, andgc storage migrate --from-work is what owes it. It is not that
command run twice: the migration is one-shot on purpose, and forcing it to
re-copy would re-import a serving binding from a source that no longer holds
what the binding does.
The recovered beads stay in the work store until the migration is run again,
which clears them exactly as it clears the cutover’s own copies.
A manifest written by an older build may list a work-store row by id alone,
with nothing that says whether it is the bead the copy carried: no time
bounds the entry, the row carries no created_at, or the row is younger than
the manifest, which an older recover-stranded extended with the id of every
row it carried. When the binding no longer holds such a row, a closed one is
moved. One that is not closed is refused and shown (status, type,
timestamps, title): nothing here can tell whether the binding collected the
bead the copy carried or never received it. Decide per id with —move <id>
(copy it in as it is) or —record-carried <id> (record it as carried; the
clear then deletes its work-store row, and the clear’s backup keeps it).
Both also accept closed rows. —dry-run and —dump show these rows without
writing, and naming an already-resolved id again is a no-op.
A work-store row can also reuse an id the binding still holds for a
different bead: the work store minted the id again after the copy carried
the original. No copy can carry it under that id, so it is named and left
unrecorded until you decide per id: —replace-binding-row <id> (the
work-store row replaces the binding’s) or —drop-work-row <id> (the
work-store row is removed and the binding’s stays). These are the only
choices that remove a row, and each first backs up the row it removes, with
every edge touching it, to infra.recover-choices.jsonl at the binding root.
—dry-run shows both rows of each such id.
gc storage repair-sequence
Inspect or raise the persisted id-sequence floor of a SQLite bead store. Without —floor this is read-only: it reports the persisted floor and the highest auto-minted id the store still holds, and whether minting is refused because a negative “<prefix>—<n>” id ranks above the floor. A negative id above the floor usually means an older build wrapped the sequence past 9223372036854775807. It can also come from a copy or import that pinned “<prefix>—<n>” ids into a store that never wrapped. If those rows are stray duplicates, do not raise the floor: delete every “<prefix>—<n>” row above the floor, not only the one the report names, and reopen the store (restart the processes serving it), and minting resumes in the positive range. Deleting destroys those beads, so if any of them is a real bead, raise the floor instead. With —floor=N it persists N as the floor, so the next auto id is N+1. Pick N at or above the highest id EVER issued under the prefix — deleted beads are no longer in the store, so derive it from the event log and dispatcher traces. The command refuses to lower the persisted floor and refuses N below the highest auto id present. Ids are ordered 1 < … < 9223372036854775807 < -9223372036854775808 < … < -1. On a store an older build wrapped, the positive range is spent: pass a NEGATIVE floor above every “<prefix>—<n>” id ever issued, and allocation continues upward toward -1 without re-entering the positive range. That cannot be undone. Builds without this fix refuse to open a store whose floor is negative. Before repairing a wrapped store, stop every process serving it that runs a build without this fix, so none keeps minting wrapped ids past the floor you pick. After a floor raise, processes on this build need no restart: one that refuses to mint resumes at its next mint once the floor covers the store. The store defaults to this city’s SQLite infrastructure binding; —dir names any other store directory (the directory holding beads.sqlite).gc storage status
Report which binding serves each storage class, whether this city has converged onto it, and what the retained source and the binding each hold. This path is read-only against a LIVE city: it creates no directory, database, write-ahead log, shared-memory index, schema, marker or manifest. It does not open the binding’s engine unless that database already exists, because opening it would create the very database the report is being asked about. It exits non-zero when the city is configured for a binding it has not converged on, so a deployment script can gate on it. That is the ordinary state of every city with a cutover still ahead of it, and it is NOT a fault report: a non-zero status here says the migration has not run, not that it would fail. To find out whether it would fail, rungc storage preflight, which rehearses
every check the migration makes without migrating.