Runs and operations

Guild Stack writes everything it does into one folder, .guild/, at the top of your project. Nothing is hidden. Start by reading a run; the Power layer adds status, the dashboard, ops runbooks, initiatives, and workspaces; the Architect layer is the full observability record.

Try it. The first line reports where your project stands. The second lists every run Guild Stack has recorded:

/guild:status
ls .guild/runs/

Reading what Guild Stack wrote

Guild Stack writes everything it does into one folder, .guild/, at the top of your project. Nothing is hidden. This page shows where to look.

Settings

  • .guild/settings.json: this project's Guild Stack settings. It is plain JSON.

Project notes (the wiki)

  • .guild/wiki/index.md: the start page.
  • .guild/wiki/concepts/architecture-map.md: how your code fits together.
  • .guild/wiki/sources/: notes made from documents you added.
  • .guild/wiki/decisions/: decisions you asked Guild Stack to record, with the options you turned down.

These are Markdown files. Open them in any editor.

Maps of your code

  • .guild/indexes/codebase-map.json: every file Guild Stack found, and which file imports which.

What init did

  • .guild/init/<project>.md: a short report of the setup.

Plans

  • .guild/plan/*.md: the plan for a task. Each piece of work (a lane) is listed here, and so is any lane it waits for.

Runs: one folder per task

Each Guild Stack task gets its own folder in .guild/runs/:

  • .guild/runs/<run-id>/run.yaml: which command ran.
  • .guild/runs/<run-id>/handoffs/: one receipt per lane. Each receipt has a ## changed_files section that lists the files that lane touched.
  • .guild/runs/<run-id>/review.md: the review of the work.
  • .guild/runs/<run-id>/verify.md: the final check, with a pass or fail result.

Tip: to see what happened in a task, read verify.md first, then the receipts.

Knowledge waiting for approval

  • .guild/knowledge/sources/: copies of documents you added to the notes.
  • .guild/knowledge/candidates/: new knowledge, such as a decision, waiting for your approval before it goes into the wiki.

Status, stats, and the dashboard

/guild:status is the one place to read where a project stands. The bare form writes no .guild/ data.

Bare status

/guild:status shows the current run state, the furthest phase, the next gate, blockers, the layout version, and the active team for each phase. It resolves state by a filesystem scan, or by an optional SQLite read-through cache that lives on platform state, off the repo. --no-index skips the cache.

A legacy single-file team.yaml is reported once as legacy; status never acts on it.

Sub-verbs

Sub-verbWhat it doesWrites?
resumeContinues the active run from its next pending gate. It hands off to that phase's own command. --restart clears run state after it asks you.yes, via the phase it resumes
statsUsage and telemetry over .guild/runs/**. --rebuild-index rebuilds the optional cache.no
dashboardServes the benchmark web UI over this project's runs and knowledge. --stop shuts it down.on stable 3.0.0, only under .guild/cache/; the upcoming beta analysis view additionally triggers plugin commands that write analysis and recommendation artifacts (see below)

The dashboard

/guild:status dashboard launches the local benchmark UI: a runs table, a Knowledge view, and a Wiki browser. It imports the project's run logs and prints the URL.

  • Port: default 3055. If that port is taken, it moves to the next free one. --port N picks another.
  • Checkout: it looks for the benchmark repo as a workspace sibling, then in-repo, then as a cached clone under .guild/cache/benchmark.
  • No network by default. A clone or an install happens only after you confirm it.
  • Managed, not a daemon. The server logs to .guild/cache/dashboard.log and records its PID in .guild/cache/dashboard.json, which --stop reads.

Use stats when you want text in the terminal. Use dashboard when you want to browse runs and the knowledge graph in a browser.

Run analysis in the dashboard (upcoming beta)

The upcoming beta (next) releases add a behavioral-analysis view to the dashboard. You can start an analysis of one run, a comparison of several, or an analysis of an initiative or an independent-run group, and watch the job's progress. The analysis itself always runs in the plugin; the dashboard only displays its artifacts and triggers the plugin's own commands.

Three rules keep what you see honest:

  • Evidence states are explicit. A report renders as current, stale, missing, malformed, or failed — each distinctly. A stale report (its inputs changed since it was computed) is never actionable; refresh the analysis first.
  • Partial evidence stays partial. Not every event class has a producer wired yet, so some conclusions report unobservable instead of a verdict. Absence of evidence never proves success.
  • A recommendation decision is scoped and explicit. Before you decide, the panel shows exactly where the decision lands: accepting a plugin recommendation writes a local draft under .guild/recommendations/drafts/ (nothing is filed anywhere external); accepting a project recommendation moves it to the queue in .guild/recommendations/queue.jsonl. Neither accept implements anything — implementation is always separate, later work, and the plugin re-checks freshness at decision time and refuses a stale decide.

The status line

Guild Stack ships a small script that prints one line of run state: the phase, the review round, the loop cap, the active loops, and the restart count. It is off by default.

Turn it on

statusline is a settings-schema key with default false. It is not a policy key, so /guild:config set statusline … is refused in v3.0.0. Use one of these:

  • Pass --statusline through Guild Stack's runner.
  • Export GUILD_STATUSLINE=1 yourself before you start the host.

The script prints nothing unless GUILD_STATUSLINE is exactly 1.

When the key is true, the agent-team launcher exports GUILD_STATUSLINE=1 and passes it to every specialist pane. If you already exported it, the launcher keeps your value. If settings cannot be read, it leaves the variable unset.

What it shows

With a run id and a counters file, the line is:

phase: build | round: 2 | cap: 16 | loops: all | restarts: 0
FieldSource
phaseGUILD_PHASE. unknown when unset.
roundFrom counters.json in the run directory. With GUILD_LANE_ID set, the highest of that lane's L3, L4, and security rounds. Otherwise the higher of the global L1 and L2 rounds.
capGUILD_LOOP_CAP. 16 when unset.
loopsGUILD_LOOPS (none, spec, plan, implementation, all, or a comma list). none when unset.
restartsThe lane's restart_count, or 0 without a lane.

The run directory is GUILD_RUN_DIR if set, else <cwd>/.guild/runs/<GUILD_RUN_ID>.

Fallback lines

StateOutput
GUILD_STATUSLINE is not 1Nothing.
GUILD_RUN_ID unsetphase: unknown
Run id set, no counters.json yetphase: <run-id> (initialising)

The script always exits 0 and prints no errors. It reads the host's stdin JSON so the host does not block, but it does not use its fields.

What the source does not cover

The plugin ships the script and the opt-in key. The v3.0.0 source does not register the script as a host's status-line command, and hooks/hooks.json does not reference it. The HELP text for the key describes a tmux status pane. This page does not claim which hosts render the line. Treat it as a script you point your host at yourself.

See Config reference for the statusline key and Status, stats, and dashboard for the status command.

Ops runbooks

/guild:ops is the operations phase. It runs a runbook: a written, reviewed procedure for a release, an alert, an outage or a revert. Every runbook runs behind a mandatory pre-flight dry-run. For the phase overview see Lifecycle in depth.

Try it

/guild:ops              # Guild suggests a runbook and asks you to confirm
/guild:ops <runbook>    # name the runbook yourself

Either way the class is confirmed with you before anything runs.

The five classes

ClassPostureProducer specialist
releaseinteractive by defaultdevops-ci-cd-pipeline (plus technical-writer-release-notes as advisor)
monitoringinteractive by defaultdevops-observability-setup
incidentinteractive always, never autonomousdevops-incident-runbook
rollbackinteractive always, never autonomousdevops-incident-runbook
maintenanceinteractive by defaultdevops-infrastructure-as-code

The five runbooks are chapters of one assembler skill, not separate skills. Approving a runbook lowers only the soft gate. It never lowers the hard set.

Where runbooks live

A runbook's trust root is .guild/wiki/standards/runbooks/<name>.md. It is promoted through the decisions flow. See Knowledge.

Four safety rails

The router enforces these for every class, before dispatch. Rail 4 has two legs, so four rails produce five checkable booleans in guild.ops.v1. All five must be true.

#RailBoolean
1An unproven runbook is not autonomous. The first run is interactive.unproven_runbook_was_interactive
2Incident and rollback are never autonomous.incident_rollback_not_autonomous
3The always-ask hard set is unconditional, even under --auto-approve=all.hard_set_prompted_inline
4aThe pre-flight dry-run is mandatory.preflight_dry_run_ran
4bThe autonomy allowlist holds no hard-set class.no_hard_set_in_allowlist

The hard set is release, security, ops and destructive. The gates that can never run autonomously are ops and destructive.

An op_class_allowlist may never contain a destructive, network or spend class. Plan validation rejects it with exit code 2.

The pre-flight dry-run

The dry-run is rail 4. It is mandatory and the router checks it before the runbook is dispatched. The result is recorded as preflight_dry_run_ran. Every hard-set step is also recorded as autonomy: prompted_inline.

Risky or destructive steps prompt you every time.

Refusing on a quality BLOCK

Ops reads the quality report from QA. If its recommendation is block and no human force_pass is recorded:

  • release and rollback refuse, and route you back to QA.
  • monitoring, maintenance and incident may proceed.

Review and evidence

The ops team is composed and approved before any dispatch. Its advisory challengers are security (always) and architect (only on the multi_component signal). A cross-host reviewer is optional and policy-gated, as in QA. Neither changes the safety rails.

Records go under .guild/runs/<run-id>/ops/, with per-step evidence in ops/evidence/. Every run writes guild.ops.v1. Incident and rollback also write guild.incident.v1. Release also writes guild.release.v1.

Ops only supplies evidence for closing an initiative. The release record carries outcome.status, doc_sync_status and release_evidence_refs. Closing stays with the initiative close gate. See Initiatives.

Initiatives

An initiative is work that spans more than one run. It is opt-in. A one-off /guild:guild run never creates one. Attachment is always explicit, in one of three ways:

  1. You run /guild:initiative … directly.
  2. You pass --initiative=<id|new> to a phase command.
  3. Your brief names a durable goal. Then /guild:guild asks you: attach to a new initiative, an existing one, or keep it one-off. It never attaches on its own.

Initiatives live under .guild/initiatives/active/<id>/ and .guild/initiatives/archived/<id>/.

Sub-verbs

Sub-verbWhat it does
newWrites initiative.yaml and its definition ledger, behind the definition-ready gate.
statusRead-only view of one initiative.
listRead-only list. --archived includes archived ones.
resumeRe-enters the next open work item.
updateAmends the ledger, for example --add-goal "…".
archiveMoves it from active to archived.
restoreMoves it from archived back to active.
closeRuns the close gate and refuses to close on a failure.

The close gate

close runs a deterministic gate script (the D8 gate) and refuses on a non-zero exit. It also refuses when any cited evidence path does not exist: a close_gate.evidence entry or a work-item evidence_refs entry. The skill never re-decides the outcome in prose.

An unknown sub-verb prints usage and runs nothing.

Workspaces

A workspace is a folder whose immediate children are separate projects. Each child has its own .git/ or .guild/. Guild Stack has exactly two state levels: the workspace root (the umbrella) and its immediate children (the sub-guilds). Each level has its own .guild/. There is no third nested level. The umbrella reads child state in place. It never replicates a child's agents, skills, wiki pages, initiatives, or runs.

How Guild Stack detects one

/guild:init and /guild:learn map run a detection script before they scan anything. It looks at immediate children only. Depth is fixed at 1. A child counts if it holds a nested .git/ or .guild/. Plain folders such as docs/ match neither and are ignored. Guild Stack shows you the verdict ("detected N sub-guilds: …, by rule …"). It is never silent, and you can override it.

On a regular repo, none of this runs and nothing changes.

The workspace.mode setting

Set workspace.mode in .guild/settings.json to override detection.

ValueMeaning
autoDetect from the children, as above.
onTreat the folder as a workspace.
offTreat the folder as a regular repo.

The default is auto.

What init writes on a workspace

  • .guild/workspace.json (schema guild.workspace.v1), the federation manifest. It lists each detected sub-guild. A script writes it, and re-running init refreshes it without clobbering other state.
  • A root wiki, only when the manifest says root_wiki: true. That is the case when the root itself has scannable top-level code. A pure federation root (for example, just docs/ and the child repos) gets no root wiki.
  • For each child that has no .guild/ yet, Guild Stack offers to run /guild:init on it. It registers the child either way. It never auto-inits and never forces.

All writes land under the workspace's own .guild/. Detection and registration are read-only on every child's .guild/.

Federation: query, not copy

When the root has a .guild/workspace.json, a wiki query does not stop at the root's own (often empty) wiki. It fans out across every registered sub-guild that has a wiki, then merges the results into one ranked list. Each hit is tagged with the sub-guild it came from. The root wiki joins as one more source when root_wiki is true.

  • A query that names one sub-guild searches only that sub-guild.
  • A query that names none searches all of them.
  • The same fan-out feeds a lane's context bundle. No child knowledge is copied into the bundle, and the bundle size cap is unchanged.

The same rule holds for the knowledge graph. Each child keeps its own codebase-map.json and knowledge-graph.json under its own .guild/. The root graph never merges them. Cross-repo references are counted and left unresolved, not turned into root-graph nodes.

When pages conflict

The plugin at v3.0.0 has no rule that ranks the umbrella wiki above a child wiki. A federated query uses the normal contradiction policy instead. When two returned pages contradict on the same claim, the newer page wins, unless the older page has confidence: high and the newer one does not. Guild Stack never picks silently. It shows both pages with their paths, updated_at, confidence, and a resolution: line, and suggests guild:wiki-lint so a person decides.

If your team wants the umbrella wiki to win cross-project conflicts, keep that as a workspace convention (for example in the umbrella AGENTS.md). Guild Stack does not enforce it.

Learning across children

/guild:learn map on a workspace registers the children. It does not auto-run a deep scan on each. The no-argument /guild:learn does fan out. Its behavior follows the workspace knowledge setting learn_fanout:

  • auto (default): fans out to the children after showing a cost estimate.
  • plan-only: writes the fan-out plan to .guild/runs/<run-id>/learn/workspace-plan.md and stops.

--dry-run always behaves as plan-only.

Once children have their own harvest candidates, a script can stage the cross-cutting ones for the umbrella. It writes only a reference manifest at <root>/.guild/runs/<run-id>/upstream-candidates.json. It writes nothing under .guild/wiki/. A candidate lands in the umbrella wiki only through the separate, human-gated wiki-ingest step.

Observability

Every tracked run writes to its own directory, .guild/runs/<run-id>/. Nothing leaves your machine (see Security and trust). You read the record with plain files, scripts/trace-summarize.ts, or the optional guild-telemetry MCP server.

Run events to cost rollup.
Open full size

Try it

With the guild-telemetry server loaded, call trace_list_runs to find run ids, then trace_summary with one of them. The server is optional. Guild Stack works without it.

Files in a run directory

Path under .guild/runs/<run-id>/Written byContent
logs/v1.4-events.jsonlpost-tool-use, capture-telemetry, run-trace-*Canonical event log. One JSON object per line.
events.ndjsoncapture-telemetryLegacy mirror. Same lines for every event type, including PostToolUse. Best-effort.
logs/payloads/<span_id>.jsoncapture-telemetryguild.trace_payload.v1 sidecar: a redacted structured body. Raw provider prompts are never stored.
logs/security-events.jsonlPreToolUse and the scrub pathSecurity events.
logs/tier-dispatch.jsonl, logs/backend-degradation.jsonlPreToolUseTier-dispatch and backend-degradation records.
run.yaml, provenance.jsonrun lifecycleRun status, and the provenance pointer written at close.
resolved-settings.jsonrun-start preflightThe resolved settings snapshot, referenced from run.yaml's settings_ref. Best-effort.

Event schema

The v1.4 log is a closed union of 16 event types: phase_start, phase_end, specialist_dispatch, specialist_receipt, loop_round_start, loop_round_end, tool_call, hook_event, gate_decision, assumption_logged, escalation, codex_review_round, harvest_event, redirect_event, cas_event, curator_event. Validators reject other values.

Common fields are ts, event, run_id, and an optional lane_id. Run ids match ^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$. A tool_call event adds:

FieldMeaning
toolOne of 17 closed values (Read, Write, Edit, Grep, Glob, Bash, Agent, Skill, AskUserQuestion, TaskCreate, TaskUpdate, TaskList, WebFetch, WebSearch, NotebookEdit, BashOutput, KillShell)
command_redacted, result_excerpt_redactedRedacted text
statusok, err or n/a
latency_msFrom Pre/Post pairing
tokens_in, tokens_outOptional

phase_start and phase_end use the phases brainstorm, team-compose, plan, context, execute, review, verify, reflect. A hook_event names one of 12 hook events.

Trace event v2 fields

Lines written by capture-telemetry also carry ts, event, tool, specialist, payload_digest, ok, ms, and for loop events loop_layer, loop_round, loop_gate, loop_terminated. Additive guild.trace_event.v2 fields are optional:

  • span_id: sha256(run_id|event|ts|actor_id)[0:16].
  • parent_span_id: from GUILD_PARENT_SPAN_ID when threaded.
  • tier: from GUILD_TIER (cheap, mid, powerful).
  • model: from GUILD_MODEL, else the payload.
  • tokens: {input, output, cached, cost_usd}, on LLM-call events only.
  • payload_ref: path of the payload sidecar.

Run lifecycle markers, run_started and run_closed, are guild.trace_event.v1 lines appended to the same log.

The hooks

HookEventWhat it does
capture-telemetryUserPromptSubmit, PostToolUse, SubagentStopAppends event lines. It skips the canonical write for PostToolUse, because post-tool-use already writes the validated tool_call line. Otherwise every tool call counted twice. The legacy mirror still receives it.
run-trace-startUserPromptSubmitEmits run_started once per run. Later prompts are no-ops. With no resolvable run id it does nothing.
run-trace-closeStopCloses the run: writes provenance.json, flips run.yaml status, appends run_closed. It acts only for a run that was started.

Stop fires after every assistant turn, not only at session end. If a run was closed and then saw more tool activity, run-trace-close closes it again so provenance reflects the latest state. A run that stayed quiet is left alone.

All three hooks exit 0 and never block the session. The run id comes from GUILD_RUN_ID and is verified against the run's minted binding. Commands and skills start runs through hooks/run-trace.js start --command=.... A full run stays open for the Stop hook. A --run-class=lightweight run, such as status, starts and closes at once.

Telemetry text goes through secrets scrubbing first. The UserPromptSubmit prompt honors secrets_policy.fail_mode_telemetry.

guild-telemetry MCP

The server is read-only. It reads logs/v1.4-events.jsonl first, then falls back to legacy events.ndjson. v1.4 fields are normalized (status to ok, latency_ms to ms, hook_name to tool), so every tool works on both shapes. Bad lines are skipped. Output is sorted by run_id then ts.

ToolArgumentsReturns
trace_list_runssince?, limit?, cwd?Runs with event_count, started_at, ended_at
trace_summaryrun_id, cwd?The stored summary.md (source: "file"), else one synthesized in memory (source: "synthesized")
trace_queryrun_id?, event?, specialist?, since?, limit?, cwd?Filtered events, each annotated with run_id
trace_cost_rolluprun_id?, since?, cwd?Token totals plus by_tier, by_model, by_specialist

Cost rollup

trace_cost_rollup adds up guild.trace_event.v2 token usage. It merges two sources: the v2 tokens object (input, output, cached) and the v1.4 tool_call tokens_in / tokens_out. Each breakdown row is {key, input, output, cached, total}, sorted by total descending, then key. Events without token fields are skipped, and llm_event_count says how many counted. Omit run_id to roll up all runs. For tiering policy, read Cost and tiering.

Which project it reads

The root resolves in this order: the per-call cwd argument; the GUILD_TELEMETRY_CWD environment variable; the server process cwd. The Codex manifest launches the server with --no-cwd-fallback. In that mode the process-cwd step is removed, cwd must be absolute, and a call with no usable root fails with isError: true. Otherwise it would read the plugin's own .guild/.

Behavioral run analysis (upcoming beta)

In the upcoming beta (next) releases the plugin also analyzes what it recorded. The command surface is deterministic and filesystem-canonical: analyze one run, compare several, or analyze an initiative or an independent-run group. A read-only analyze inspect form shows a report's identity, inputs and freshness without writing anything.

  • Analysis artifacts land under .guild/analysis/runs/** and .guild/analysis/comparisons/**; recommendations under .guild/recommendations/**. The benchmark dashboard reads these files; it never computes conclusions of its own.
  • Each report binds the exact inputs it was computed from. If a trace or sidecar changes afterwards, the report shows as stale and a decision on it is refused until it is recomputed.
  • Conclusions are honest about coverage: an event class with no wired producer makes the dependent conclusion unobservable rather than guessed, and missing identity, snapshots, or required event classes lower completeness. Wiring more producers is ongoing work in the beta cycle.
  • Recommendation writes are serialized and audited: decisions append to an activity log, and an interrupted multi-file write is rolled back before the next writer proceeds.

Limits

  • The MCP server is optional: scripts/trace-summarize.ts and plain filesystem reads work without it.
  • Payload sidecars are size-capped and share the legacy log's retention story. This page does not state a cap or a retention period.