Guild logo Guild
Reference / Configuration Reference
Reference

Configuration Reference

Complete settings.json reference — agent_mode, model tiers, SQLite index, security/secrets policy, O-3 calibration, and cross-host dispatch for Guild v2.

Configuration Reference

Guild works without any configuration. .guild/settings.json exists only when you want to override a default — absent keys fall back to the built-in defaults, and parse errors never block a run (they print a warning and fall back).

Generate a fully-documented scaffold: /guild:config init
Inspect the resolved config: /guild:config show
Validate against the closed-key set: npx tsx scripts/read-guild-config.ts --validate


Precedence ladder

From highest priority (first wins) to lowest:

1. CLI flag  (--rigor=deep, --agent-mode=team, --model-tier=cheap …)
2. --rigor profile expansion  (fills only keys NOT set explicitly)
3. .guild/settings.json
4. Built-in defaults

Model-tier only: --model-tier=cheap|mid|powerful → per-lane plan model_tier: override → models.tiers + models.thresholds → built-in map.


Top-level keys

KeyTypeDefaultDescription
rigor"quick" | "standard" | "deep""standard"Expands into loops, loop_cap, and review via the rigor profile. Explicit values for those keys override the profile. See Rigor profiles below.
auto_approvestring[][]Opt-in autonomy — which lifecycle gates skip the user-approval pause. Values: "spec", "plan", "build", "all". Destructive, network, and spend actions still ask regardless.
review"local" | "cross" | "off""local"Review broker mode. cross engages the Claude↔Codex adversarial broker. rigor=deep auto-implies cross; override to local/off to suppress.
host"claude" | "codex" | "auto""auto"Co-equal host adapter selection.
initiative_defaultstring | nullnullAttach all runs to a named initiative by default.
index"auto" | "off""auto"Top-level SQLite read-through cache gate. auto = lazy-build when measured slowness thresholds are exceeded. off = always direct-parse; no index.sqlite written. Fine-grained thresholds: defaults.index.*.
agent_mode"team" | "agent" | "subagent" | "auto""auto"Execution backend. See Agent-mode dispatch ladder. Supersedes the deprecated defaults.agent_team.
workspace{ mode: "auto"|"on"|"off" }{ mode: "auto" }Workspace federation mode (guild.workspace.v1). auto detects by immediate-child rule (presence of .git/.guild). Depth is hard-fixed at 1 — no max_depth knob.
loopsstring | nullnullAdversarial-loop scope override. Values: "none", "spec", "plan", "implementation", "all", or a comma-separated subset. null = derive from rigor.
loop_capinteger 1–25616Maximum rounds per adversarial loop.
codex_capinteger 1–105Maximum rounds per Codex adversarial review gate. CLI: --codex-cap=N.

Rigor profiles

rigor fills loops, loop_cap, and review only for keys you did not set explicitly (in settings.json or as a CLI flag). Explicit values always win.

rigorloopsloop_capreview
quick"none"— (no cap)"off"
standard"spec,plan"16"local"
deep"all"16"cross" (falls back to "local" if Codex unavailable, env GUILD_CROSS_HOST_AVAILABLE=0)

The resolved expansion is visible as _rigor_expanded in --validate output and in the JSON returned by read-guild-config.ts.


Agent-mode dispatch ladder

agent_mode: "auto" resolves at runtime in this order — team and independent agents are primary; subagent is the last resort:

PriorityConditionBackend
1$TMUX setteam in-session: new tmux window, one pane per specialist, select-windowed immediately. Never clobbers the active pane.
2tmux installed, not currently inside oneteam in a fresh detached session, then attaches your terminal.
3No tmux; host (claude/codex) supports independent agentsagentInProcessTeamBackend: orchestrator consumes a dispatchPlan; each specialist dispatched as an independent Agent-tool call. No tmux required.
4Elsesubagent fallback: guild:execute-plan dispatches via the Agent tool. No tmux required (CI, fresh installs).

Pinning agent_mode: "team" on a tmux-less host is rejected with a warning.

defaults.agent_team is a deprecated alias (warn-once). Migration: auto→auto, on→team, off→subagent. Removed at v2.1.0.

Example:

{ "agent_mode": "subagent" }

models.* — Cost tiering

Three-tier model routing: cheap (haiku) for I/O, mid (sonnet) for drafting, powerful (opus) for architecture and security

Canonical ADR: cost-aware-tiering-and-lean-context (§1 tiers · §2 auto-score · §3 advisor · §4 recall · §5 handoff · §6 lifecycle · §8 learn · §10 config)

Closed key set — unknown models.* keys are rejected by --validate.

KeyTypeDefaultDescription
models.enabledbooleantrueMaster toggle for cost tiering. false = all lanes run at mid.
models.tiers{ cheap, mid, powerful }see belowHost-agnostic tier→model map. Each tier is { claude, codex, gemini }. A null host slot means no model for that tier on that host. Partial overrides deep-merge over built-in defaults.
models.scoreWeightsRecord<string, number>see belowAuto-score rubric weights. Signals: workType, blastRadius, dependsOn, security, priorEscalation. Tunable per-repo.
models.thresholds{ mid: int, powerful: int }{ mid: 1, powerful: 3 }Score-band cutoffs. score < mid → cheap; mid ≤ score < powerful → mid; score ≥ powerful → powerful.
models.advisorRoundsinteger ≥ 12Max advisor consults per lane before recording inconclusive.
models.escalationMarkersstring[]see belowUncertainty phrases that trigger advisor escalation.
models.recallBeforeReadbooleantrueEnforce recall-before-read: query the wiki before opening a file.
models.recallScoreThresholdfloat 0–10.4Min BM25 recall score to skip a full file read.
models.structuredOutputRequiredbooleantrueReject non-guild.handoff.v2 agent returns.
models.cacheTTL.coordinator"1h" | "5m" | "off""1h"Coordinator prompt-cache TTL hint.
models.cacheTTL.leaf"1h" | "5m" | "off""5m"Leaf-agent prompt-cache TTL hint.
models.importanceGateinteger 1–53Min wiki importance level for routine recall. Pages below this level are skipped in the recall pass.
models.ingestSimilarityGatefloat 0–10.80BM25 top-1 similarity threshold for the wiki ingest anomaly gate. When a candidate page scores ≥ this against existing pages, guild:wiki-ingest pauses for user decision (supersede / skip / proceed) — never silently overwrites.
models.shortOutputThresholdRecord<task_type, Record<tier, number>>{}O-3 short-output advisor trigger buckets. Each entry maps task_typetier → output-token floor. Empty map (default) = O-3 trigger is silent for all buckets. See O-3 calibration below.

Default tier map

{
  "models": {
    "tiers": {
      "cheap":    { "claude": "haiku",  "codex": null, "gemini": null },
      "mid":      { "claude": "sonnet", "codex": null, "gemini": null },
      "powerful": { "claude": "opus",   "codex": null, "gemini": null }
    }
  }
}

codex and gemini slots are null pending those adapters; they slot in as config + adapter when available.

Default score weights

{
  "models": {
    "scoreWeights": {
      "workType":        0,
      "blastRadius":     1,
      "dependsOn":       1,
      "security":        1,
      "priorEscalation": 1
    }
  }
}

workType is a base offset: read/summarize = +0, draft/extract = +1, architect/review/schema = +2. The other weights are additive per signal.

Default escalation markers

{
  "models": {
    "escalationMarkers": [
      "I'm not sure",
      "unclear",
      "cannot determine",
      "I don't know",
      "ambiguous",
      "uncertain",
      "not enough information"
    ]
  }
}

Example — tune thresholds, reduce advisor rounds:

{
  "models": {
    "thresholds": { "mid": 2, "powerful": 4 },
    "advisorRounds": 1
  }
}

O-3 calibration buckets

ADR: v2-observability-and-replay §D-OBS-3

The O-3 “anomalously short output” advisor trigger fires when a lane’s output token count falls below the p10 baseline for that (task_type, tier) bucket. Thresholds are not built-in — derive them from ≥ 30 run samples and land them here manually.

Workflow:

  1. Run npx tsx benchmark/src/calibrate-o3-cli.ts (after sufficient samples).
  2. The CLI prints a models.shortOutputThreshold JSON fragment with proposed floors.
  3. Review and merge the proposal into .guild/settings.json.
  4. Nothing auto-writes this key. All writes are explicit.

Until a (task_type, tier) pair appears in this map, the O-3 trigger is silent for that bucket.

Example (after calibration on a mature repo):

{
  "models": {
    "shortOutputThreshold": {
      "build":  { "cheap": 80,  "mid": 150, "powerful": 200 },
      "review": { "cheap": 120, "mid": 200, "powerful": 300 },
      "plan":   { "mid": 180,   "powerful": 250 }
    }
  }
}

Malformed entries (non-object task-type values, non-number tier values) are silently dropped — a partial calibration proposal never hard-blocks config load.


security.* — bypassPermissions governance

ADR: v2-security-and-untrusted-content (D-BYPASS)

Closed key set — only bypass_permissions_policy is valid.

KeyTypeDefaultDescription
security.bypass_permissions_policy"deny" | "audit" | "allow""audit"bypassPermissions governance during Guild-managed runs. deny: hard-block + security event (forced under auto_approve / autonomous-after-plan). audit: surfaces always-ask channel + security event (default for interactive mode). allow: opt-in for interactive mode only. Guild cannot govern bypass outside its own run lifecycle.

Example:

{ "security": { "bypass_permissions_policy": "deny" } }

secrets_policy.* — Secrets redaction

ADR: v2-security-and-untrusted-content (D-SECRETS)

Closed key set.

KeyTypeDefaultDescription
secrets_policy.env_allowliststring[][]Env var names explicitly permitted in agent-context injection. All others are redacted before context assembly.
secrets_policy.redaction_patternsstring[][]Regex patterns applied as the first stage of the 3-stage secrets scrubber (prefix regexes → Shannon-entropy → file-path context). Run over all .guild/ artifact writes.
secrets_policy.fail_mode_durable"closed" | "open""closed"On scrub failure for durable shared-git artifacts (handoff, provenance, wiki, review): closed = block the write + surface always-ask; open = warn + proceed.
secrets_policy.fail_mode_telemetry"open" | "closed""open"On scrub failure for local gitignored telemetry writes (runs/<id>/logs/*.jsonl): open = warn + security event + proceed; closed = block.

Example:

{
  "secrets_policy": {
    "env_allowlist": ["GITHUB_TOKEN"],
    "redaction_patterns": ["sk-[A-Za-z0-9]{32,}"],
    "fail_mode_durable": "closed",
    "fail_mode_telemetry": "open"
  }
}

mcp.* — MCP description pinning

ADR: v2-security-and-untrusted-content (D-MCP, PI-6)

Closed key set — only tool_description_hashes is valid.

KeyTypeDefaultDescription
mcp.tool_description_hashesRecord<string, string>{}Map of MCP tool-name → SHA-256 hash of (description + inputSchema), pinned at /guild:config init time. PreToolUse compares the live hash per call. Drift triggers a warn+gate-on-approval. Re-pin via /guild:config update-mcp-hashes.

defaults.* — Per-run behavioral defaults

The defaults block configures default posture for each Guild run. All keys deep-merge: absent sub-keys inherit the built-in defaults.

KeyTypeDefaultDescription
defaults.agent_team"auto" | "on" | "off""auto"DEPRECATED — use top-level agent_mode instead. Warn-once alias: auto→auto, on→team, off→subagent. Removed at v2.1.0. Run /guild:config init to migrate.
defaults.auto_learnbooleanfalseWhen true, /guild:init runs the full learn-* pipeline at bootstrap. Precedence: --learn CLI flag > this setting > built-in false.
defaults.adversarial"on" | "off""on"Adversarial review posture. "off" is rejected for Guild self-build (--self-build --validate).
defaults.team.sizeinteger | nullnullTeam size cap. null = apply the 3–4 rule. Values capped at 6 unless explicitly overridden.
defaults.team.always_includestring[][]Specialists always included in the team regardless of composition. Subset of the 14 specialist names.
defaults.review_workflow"standard" | "cross" | "minimal""standard"Default review depth for lane reviews.
defaults.skill_policy"standard" | "conservative""standard"Default skill-usage posture.
defaults.gates.auto_approvestring[][]Default approval-gate posture. Values: "spec", "plan", "build", "all". Never auto-approves qa or ops gates.
defaults.wiki.share_mode"team" | "private""team"Wiki share mode.
defaults.wiki.autopromotebooleanfalseAlways false. true is rejected always — agents emit candidates only; humans promote.
defaults.quality.budget.per_class_minutesinteger > 010Per-check-class wall-clock cap for the QA phase.
defaults.quality.budget.total_minutesinteger > 030Whole-QA-phase wall-clock cap.
defaults.reporting"standard" | "quiet" | "verbose""standard"Default task/progress reporting verbosity.

defaults.index.* — SQLite lazy-cache thresholds

ADR: v2-persistence-and-sqlite-index (D-PS-1)

Closed key set. These thresholds determine when the lazy index.sqlite cache is populated. Below each threshold, the existing BM25 grep path is used unchanged.

KeyTypeDefaultDescription
defaults.index.enabledbooleantrueMaster switch for index.sqlite. false = always direct-parse, no index.sqlite ever written. Equivalent to --no-index made persistent.
defaults.index.kg_node_thresholdpositive integer2000Populate kg_nodes/kg_edges tables when knowledge-graph.json has more than N nodes.
defaults.index.kg_size_threshold_mbpositive number1Populate kg_nodes/kg_edges tables when knowledge-graph.json exceeds N MB.
defaults.index.links_edge_thresholdpositive integer2000Populate kl_edges table when knowledge-links.json has more than N edges.
defaults.index.runs_thresholdpositive integer20Populate run_provenance table when runs/*/provenance.json count exceeds N.
defaults.index.wiki_file_thresholdpositive integer500Populate wiki_fts table when wiki file count exceeds N. Below threshold, guild-memory BM25 grep path is used unchanged.

Example — disable index for a small repo:

{
  "defaults": {
    "index": { "enabled": false }
  }
}

defaults.cross_host.* — Cross-host SSH routing

ADR: v2-cross-host-orchestration (CR-1 / CH-1)

Security: address/port/user only — no secrets, no passwords, no key paths. SSH authentication must use keys or the ssh-agent socket (~/.ssh/config or SSH_AUTH_SOCK). The validator hard-rejects any key other than address, port, and user on each host entry.

KeyTypeDefaultDescription
defaults.cross_host.enabledbooleanfalseMaster toggle for mixed-host routing and teams. false = single-host behavior. Env override: GUILD_CROSS_HOST_ENABLED=1 enables cross-host even when this key is false; the env var wins when set.
defaults.cross_host.hostsRecord<string, HostEntry>{}SSH endpoint config keyed by guild.host_capability.v1 host ID. Each entry: { address: string, port?: integer 1–65535, user?: string }. Non-standard ports prefer ~/.ssh/config Host entries over the port field.

Example:

{
  "defaults": {
    "cross_host": {
      "enabled": true,
      "hosts": {
        "codex-worker-1": {
          "address": "192.168.1.50",
          "port": 2222,
          "user": "guild"
        }
      }
    }
  }
}

Never add password, private_key, key_path, or any credential to a host entry. The validator rejects unknown host-entry keys.


Complete minimal example

{
  "agent_mode": "auto",
  "rigor": "standard",
  "review": "local",
  "codex_cap": 5,
  "loop_cap": 16,
  "models": {
    "enabled": true,
    "thresholds": { "mid": 1, "powerful": 3 },
    "advisorRounds": 2,
    "recallScoreThreshold": 0.4,
    "importanceGate": 3
  },
  "security": {
    "bypass_permissions_policy": "audit"
  },
  "defaults": {
    "auto_learn": false,
    "adversarial": "on",
    "wiki": { "share_mode": "team", "autopromote": false },
    "index": { "enabled": true },
    "cross_host": { "enabled": false, "hosts": {} }
  }
}

Validation and tooling

CommandWhat it does
/guild:config initScaffold settings.json with all keys + self-documenting _help block.
/guild:config showPrint the resolved config (merged defaults + file + CLI flags).
/guild:config update-mcp-hashesRe-pin MCP tool description hashes in mcp.tool_description_hashes.
npx tsx scripts/read-guild-config.ts --validateValidate settings.json against the closed-key set; exit non-zero on violation.
npx tsx scripts/read-guild-config.ts --scaffoldPrint the canonical settings.json scaffold to stdout.

Migration from v1 config.yml

.guild/config.yml is read via a one-time back-compat shim when settings.json is absent. Once settings.json exists it is authoritative and config.yml is ignored. Run /guild:config init to migrate. See the v1 → v2 migration guide §3.

v1 config.yml keyv2 settings.json key
loopsloops
loop_caploop_cap
codex_capcodex_cap
codex_review: truereview: "cross"
auto_approve: spec-and-planauto_approve: ["spec", "plan"]
auto_approve: allauto_approve: ["all"]
auto_approve: implementationauto_approve: ["build"]