.forge.json Reference
Every settable key in the per-project Plan Forge configuration file, type, default, example, and what changes when the value is touched. The canonical source of truth for this reference is CONFIG_SCHEMA in pforge-mcp/capabilities.mjs; this appendix mirrors that schema in human-readable form.
forge_config MCP tool (or the dashboard Config tab) for schema-validated writes, both perform atomic updates (write to temp, then rename) so partial writes never leave a half-valid file. Hand-editing is fine for small changes; just validate the JSON before saving.
Orientation
The file lives at the repo root as .forge.json. It is read at startup by the orchestrator, the dashboard, and most MCP tools. The schema is intentionally shallow at the top and grouped by subsystem, each top-level key controls one slice of Plan Forge behavior:
| Top-level key | Subsystem it controls | Where it is used |
|---|---|---|
projectName, preset, templateVersion, pipelineVersion | Project identity | OpenBrain memory scoping, preset gating, version checks |
updateSource | Update source mode | pforge update source selection (auto / github-tags / local-sibling) |
meta | Meta-defect routing | forge_meta_bug_file target repository |
agents | Multi-agent adapters | Generates per-agent setup files (Claude / Cursor / Codex) |
modelRouting | Default model selection | Orchestrator slice dispatch, dashboard Cost tab |
forgeMaster | Forge-Master reasoning loop | forge_master_ask, dashboard Forge-Master tab |
maxParallelism, maxRetries, maxRunHistory | Execution limits | Orchestrator DAG scheduling and retention |
quorum | Multi-model consensus | --quorum=... flag, forge_estimate_quorum |
extensions | Installed extensions | pforge ext, Extensions tab |
hooks | LiveGuard lifecycle hooks | PreDeploy, PostSlice, PreAgentHandoff, PostRun |
openclaw | OpenClaw analytics bridge | PreAgentHandoff snapshot push (optional) |
runtime | Inner-loop subsystems | Phase-25 gate synthesis and quorum reviewer |
brain | Memory and federation | OpenBrain federation across local repos |
testbed | Testbed path | forge_testbed_* tools |
The next sections describe each group in detail. Every field row uses the same five columns, Key, Type, Default, Example, Change impact, so the table reads the same way no matter which subsystem you land on.
Project identity
Four fields tell Plan Forge what kind of project it is looking at. projectName is the most important one, it scopes memory in OpenBrain (so two projects with the same plan name do not collide) and is the default project tag for traces and replay.
| Key | Type | Default | Example | Change impact |
|---|---|---|---|---|
projectName | string | (none) | "plan-forge" | OpenBrain memory namespace; default project tag for replay; affects all memory-related queries. Changing it splits memory between old and new names. |
preset | enum | (none) | "dotnet" | One of dotnet, typescript, python, java, go, swift, azure-iac, custom. Determines which instruction files, agents, and skills are installed by setup. Read by validators and the dashboard. |
templateVersion | string | (none) | "2.56.0" | Records the Plan Forge release that last ran setup here. Compared against the running CLI version so pforge update can detect drift. |
pipelineVersion | string | "2.0" | "2.0" | Pipeline schema version. Rarely changed by users; bumped when the 7-step pipeline contract changes shape. |
updateSource — how pforge update finds the framework
Controls where the pforge update command pulls framework files from. Defaults to auto, which picks the newer of a local sibling clone (if present) and the latest GitHub tag. See Appendix G — Update Source Modes for the full mode-selection story; this entry is the bare schema reference.
| Key | Type | Default | Example | Change impact |
|---|---|---|---|---|
updateSource | enum | "auto" | "github-tags" | One of auto (pick newer of local-sibling and github-tags), github-tags (always GitHub), or local-sibling (always sibling clone). Validated server-side by POST /api/config; invalid values are rejected with HTTP 400. |
meta — meta-defect routing
Where Plan Forge files bugs against itself. When forge_meta_bug_file runs without an explicit target, it reads meta.selfRepairRepo. If the key is missing, it falls back to srnichols/plan-forge.
| Key | Type | Default | Example | Change impact |
|---|---|---|---|---|
meta.selfRepairRepo | string | (fallback: srnichols/plan-forge) | "acme/plan-forge-fork" | Target repository for self-repair issues. Set this if your team maintains a fork or a private mirror. owner/repo form. See self-repair-reporting. |
agents — multi-agent adapters
Which AI agents have native config files generated alongside the GitHub Copilot defaults. See Chapter 13 — Multi-Agent Setup for what each adapter writes.
| Key | Type | Default | Example | Change impact |
|---|---|---|---|---|
agents | array<enum> | [] | ["claude", "cursor"] | Each entry is one of claude, cursor, codex. Adding an entry causes setup (or setup --agent <name>) to generate that adapter's native file (e.g. CLAUDE.md, .cursorrules). Removing an entry does not delete files, clean those up manually. |
modelRouting — default model selection
Where slices go by default when no plan-level Model: directive is present. default is the catch-all; execute and review override it for those phases. See Advanced Execution — Model Routing for the routing precedence (plan front-matter > flag > execute/review > default).
| Key | Type | Default | Example | Change impact |
|---|---|---|---|---|
modelRouting.default | enum | "auto" | "claude-opus-4.7" | One of auto, claude-opus-4.7, claude-opus-4.6, claude-sonnet-4.6, claude-haiku-4.5, gpt-5.4, gpt-5.2-codex, gpt-5-mini, gemini-3-pro-preview. auto lets the host pick based on availability. |
modelRouting.execute | string | (uses default) | "gpt-5.3-codex" | Model for slice execution. Free-form string so newer models work without a CLI upgrade. |
modelRouting.review | string | (uses default) | "claude-opus-4.7" | Model for the Step 5 review gate. Free-form string. |
forgeMaster — Forge-Master reasoning loop
Configuration for the Forge-Master intent-routing layer. The routerModel is the small, cheap model that classifies intent; reasoningModel is the heavier model that synthesises the answer.
| Key | Type | Default | Example | Change impact |
|---|---|---|---|---|
forgeMaster.reasoningModel | string | (falls back to modelRouting.default) | "gpt-4o-mini" | Model used for multi-step reasoning in forge_master_ask. Affects answer quality and per-call cost. |
forgeMaster.reasoningProvider | string | (auto-detected) | "githubCopilot" | Which provider serves the reasoning model. One of githubCopilot, anthropic, openai, xai. If unset, Plan Forge picks based on available API keys. |
forgeMaster.routerModel | string | "grok-3-mini" | "gpt-4o-mini" | Small classifier model that decides which tools to call. Should be cheap and fast; quality matters less than latency. |
forgeMaster.defaultProvider | string | (auto-detected) | "githubCopilot" | Default provider for both router and reasoning if the per-model provider is not set. |
forgeMaster.observer
v3.8+ — Background hub subscriber that batches live Plan Forge events and narrates notable patterns. Mute-by-default: enabled must be explicitly set to true. Control via forge_master_observe MCP tool or pforge master observe CLI. Observer is strictly read-only; it cannot invoke write tools or create PRs.
| Key | Type | Default | Example | Change impact |
|---|---|---|---|---|
forgeMaster.observer.enabled | boolean | false | true | Master switch. Must be true for any observation to occur. forge_master_observe returns an "observer disabled" error when this is false. Set env var PFORGE_FORGE_MASTER_OBSERVE_DISABLE=1 to override to false at process level regardless of this setting. |
forgeMaster.observer.maxUsdPerDay | number | 0.10 | 0.25 | Daily USD budget cap. Once the day's narration spend reaches this cap the observer skips LLM calls and logs a budget-block event. Cap is finite; null or Infinity means no cap (not recommended). |
forgeMaster.observer.maxNarrationsPerHour | number | 6 | 12 | Max narration LLM calls per clock hour. Rate-limits the observer during burst activity. |
forgeMaster.observer.batchWindowMs | number | 60000 | 30000 | Event batch flush interval in milliseconds. Lower = more responsive narrations; higher = fewer LLM calls. |
forgeMaster.observer.modelTier | string | null | null | "fast" | Model capability tier for narrations: flagship (quality), mid (balance), fast (cheap, high-volume), or null to inherit ask-mode model. Tier resolves against the existing model registry; no vendor IDs are hardcoded. Valid values are the MODEL_TIERS array in pforge-mcp/enums.mjs. |
forgeMaster.auditor
v3.8+ — Configuration for the A4 plan-health-auditor auto-invocation. The auditor is triggered via hooks.postRun.invokeAuditor. Tokens are attributed to a separate forge-master cost entry; the parent run's budget is never charged.
| Key | Type | Default | Example | Change impact |
|---|---|---|---|---|
forgeMaster.auditor.modelTier | string | null | null | "flagship" | Model tier for auditor reasoning: flagship, mid, fast, or null to inherit ask-mode model. Use flagship for highest-quality health analysis; use fast for high-frequency auto-invocation. Valid values are the MODEL_TIERS array in pforge-mcp/enums.mjs. |
forgeMaster.auditor.outputPath | string | ".forge/health/latest.md" | ".forge/health/weekly.md" | Path where the auditor writes its health report, relative to project root. |
Execution limits
Three numeric caps the orchestrator enforces during pforge run-plan.
| Key | Type | Default | Example | Change impact |
|---|---|---|---|---|
maxParallelism | number (1–10) | 3 | 5 | Max concurrent [P]-tagged slices. Higher = faster but more contention on shared resources (the file system, the model provider's rate limit, your wallet). |
maxRetries | number (0–5) | 1 | 2 | How many times a slice will retry after a gate failure before being marked failed. 0 means fail-fast; 5 is the cap to prevent runaway loops. |
maxRunHistory | number (≥1) | 50 | 100 | How many .forge/runs/<timestamp>/ directories are retained on disk. The orchestrator auto-prunes the oldest beyond this cap on every run. |
quorum — multi-model consensus
Configuration for quorum mode. Master switch is enabled; with auto: true the orchestrator only quorums slices whose complexity score crosses threshold. See Advanced Execution — Quorum Mode for the scoring rubric and worked examples, and Complexity Scoring Rubric for the seven signals that drive the score. The CLI --quorum= flag accepts values from the QUORUM_MODES array in pforge-mcp/enums.mjs.
| Key | Type | Default | Example | Change impact |
|---|---|---|---|---|
quorum.enabled | boolean | false | true | Master switch. When false, quorum is off regardless of the other keys. |
quorum.auto | boolean | true | true | When enabled, gate quorum on slice complexity score. When false, every slice fans out. |
quorum.threshold | number (1–10) | 6 | 5 | Complexity score above which auto-mode fires quorum. Lower = more slices use quorum, higher cost. |
quorum.models | array<string> | ["claude-opus-4.7", "gpt-5.3-codex", "gemini-3.1-pro"] | ["claude-opus-4.7", "gpt-5.2-codex"] | Models that participate in the dry-run fan-out. 2–5 entries is typical; minimum is 1 (degrades to advisory). |
quorum.reviewerModel | string | "claude-opus-4.7" | "gpt-5.4" | Model that synthesises the dry-run responses into a single execution plan. |
quorum.dryRunTimeout | number (ms) | 300000 | 600000 | Per-worker timeout in milliseconds. Increase for very large slices; the default is 5 minutes. |
quorum.strictAvailability | boolean | false | true | When true, fail-fast (exit code 2) if any configured model is unavailable. When false (default), drop unavailable models and continue if at least one remains. |
extensions — installed extensions
Names of extensions installed via pforge ext add <name>. Managed by the CLI; rarely edited by hand. See Chapter 12 — Extensions.
| Key | Type | Default | Example | Change impact |
|---|---|---|---|---|
extensions | array<string> | (none) | ["notify-slack", "notify-teams"] | Extension names from the catalog. pforge ext add appends; pforge ext remove deletes. Affects which tools and skills are registered at startup. |
hooks — LiveGuard lifecycle hooks
Five hook configurations live under this object: preDeploy (before deploy slices), postSlice (after every slice), preAgentHandoff (multi-agent turn), preCommit (ordered commit-time guard chain), and postRun (after a run completes — auditor auto-invoke). Each section is independent; omit any subsection to accept its defaults.
For the full eight-hook picture, including the Copilot session hooks (SessionStart, PreToolUse, PostToolUse, Stop) configured separately in .github/hooks/plan-forge.json and the PreCommit chain runner, see Customization — Lifecycle Hooks Reference.
hooks.preDeploy
| Key | Type | Default | Example | Change impact |
|---|---|---|---|---|
hooks.preDeploy.enabled | boolean | true | false | Master switch for the PreDeploy hook. Disable only if you have an equivalent external gate. |
hooks.preDeploy.blockOnSecrets | boolean | true | true | When true, block deploy if forge_secret_scan finds anything at severity ≥ high. Set false to demote to a warning. |
hooks.preDeploy.warnOnEnvGaps | boolean | true | true | Warn (do not block) when forge_env_diff finds keys missing from the target environment. |
hooks.preDeploy.scanSince | string (git range) | "HEAD~1" | "HEAD~10" | Git range scanned for secrets. Widen for repos with bursty commit cadence. |
hooks.postSlice
| Key | Type | Default | Example | Change impact |
|---|---|---|---|---|
hooks.postSlice.silentDeltaThreshold | number | 5 | 3 | Drift score delta below this is silent (no log line). |
hooks.postSlice.warnDeltaThreshold | number | 10 | 15 | Drift score delta at or above this prints a warning. Between silent and warn = info. |
hooks.postSlice.scoreFloor | number | 70 | 80 | Absolute drift score floor, below this triggers a red warning regardless of delta. |
hooks.preAgentHandoff
| Key | Type | Default | Example | Change impact |
|---|---|---|---|---|
hooks.preAgentHandoff.injectContext | boolean | true | true | Inject LiveGuard context (drift score, MTTR, open incidents) into the next agent's prompt at handoff. |
hooks.preAgentHandoff.runRegressionGuard | boolean | true | true | Run forge_regression_guard at handoff time. Disable if your CI already does this. |
hooks.preAgentHandoff.cacheMaxAgeMinutes | number | 30 | 60 | Max cache age before LiveGuard tools are re-run. Higher = faster handoffs, staler data. |
hooks.preAgentHandoff.minAlertSeverity | string | "medium" | "high" | Minimum severity for an alert to be injected. One of low, medium, high, critical. |
hooks.preCommit.chain[]
Ordered commit-time validation chain executed by .github/hooks/PreCommit.mjs during pforge run-plan. The built-in entries are master-branch-reject first and diff-classify second; the first non-zero exit stops the commit.
| Key | Type | Default | Example | Change impact |
|---|---|---|---|---|
hooks.preCommit.chain | array | [{ name: "master-branch-reject", ... }, { name: "diff-classify", ... }] | [{ "name": "custom-check", "command": "node scripts/check.js" }] | Defines the ordered PreCommit chain. Entries run sequentially; first non-zero exit aborts the commit. |
hooks.preCommit.chain[].name | string | "master-branch-reject" / "diff-classify" | "license-scan" | Stable display name for logs and diagnostics. The first built-in entry is master-branch-reject; the second is diff-classify. |
hooks.preCommit.chain[].command | string | node .github/hooks/PreCommit.mjs <name> | node scripts/license-scan.mjs | Command executed for that chain entry. Use a deterministic command that exits non-zero on block. |
hooks.postRun.invokeAuditor
v3.8+ — Automatically invoke the A4 plan-health-auditor after a run completes. Two trigger modes: fire on every failure (onFailure), or fire periodically after N runs (everyNRuns). Both are off by default. When both conditions fire on the same run, the auditor is invoked exactly once.
| Key | Type | Default | Example | Change impact |
|---|---|---|---|---|
hooks.postRun.invokeAuditor.onFailure | boolean | false | true | When true, automatically invokes the A4 auditor whenever a plan run ends with at least one failed slice. The auditor's tokens are attributed to a separate forge-master cost entry, never to the parent run's budget. |
hooks.postRun.invokeAuditor.everyNRuns | number | null | null | 5 | Invoke the auditor after every N completed runs (pass or fail). Counter persists in .forge/auditor-state.json. When the state file is absent the first run always triggers. Set to null to disable. Reasonable values: 5–25. |
The auditor is spawned as its own Forge-Master process so its token costs land in forge_cost_report under the forge-master source. Use forge_testbed_findings to query any defects the auditor surfaces. For the full auditor configuration (model tier, output path), see forgeMaster.auditor.
openclaw — OpenClaw analytics bridge (optional)
Optional outbound POST on every PreAgentHandoff. Configures the analytics ingest endpoint. Leave unset to disable.
| Key | Type | Default | Example | Change impact |
|---|---|---|---|---|
openclaw.endpoint | string (URL) | (unset = disabled) | "https://openclaw.example/api/ingest" | Ingest endpoint URL. When set, every PreAgentHandoff posts a context snapshot. |
openclaw.apiKey | string | (fallback: .forge/secrets.json#OPENCLAW_API_KEY) | "sk_live_..." | API key. Prefer storing in .forge/secrets.json (gitignored) rather than in .forge.json (typically committed). |
runtime — inner-loop subsystems
Opt-in subsystems added by Phase-25. Both default to off or advisory; existing users see no behavior change without explicit configuration.
runtime.gateSynthesis
L6, adaptive gate synthesis from Tempering minima. Suggest-only by default; the orchestrator never mutates plans.
| Key | Type | Default | Example | Change impact |
|---|---|---|---|---|
runtime.gateSynthesis.mode | enum | "suggest" | "off" | One of off (silent), suggest (print advisory), enforce (track in .forge/gate-suggestions.jsonl, Phase-26+). Plans are still never mutated. |
runtime.gateSynthesis.domains | array<enum> | ["domain", "integration", "controller"] | ["domain"] | Which Tempering profiles to emit suggestions for. Trim to reduce noise. |
runtime.reviewer
L4, opt-in speed-quorum reviewer that scores slice diffs inside brain.gate-check. Advisory-only by default.
| Key | Type | Default | Example | Change impact |
|---|---|---|---|---|
runtime.reviewer.enabled | boolean | false | true | Master switch. Off by default; turn on to get reviewer verdicts in the dashboard Audit-Loop tile. |
runtime.reviewer.quorumPreset | enum | "speed" | "power" | One of speed (cheaper, faster) or power (flagship models, slower). |
runtime.reviewer.blockOnCritical | boolean | false | false | When true, critical verdicts block the next slice. Advisory-only (false) by design. |
runtime.reviewer.timeoutMs | number (ms) | 30000 | 60000 | Max time to wait for a reviewer response. Increase for power-preset reviewers on large diffs. |
brain — memory and federation
OpenBrain federation configuration. Off by default; opt-in via brain.federation.enabled.
| Key | Type | Default | Example | Change impact |
|---|---|---|---|---|
brain.federation.enabled | boolean | false | true | Master switch for cross-project read-only memory federation (L4-lite, Phase-25). |
brain.federation.repos | array<string> | [] | ["E:/GitHub/Rummag"] | Absolute local repo paths only. Relative paths and URL schemes (http, https, ssh, git) are rejected at load time. Each entry is searched read-only by brain_recall. |
testbed — testbed path
Where the reference testbed repo lives. Required for the forge_testbed_* tools and the --testbedPath override.
| Key | Type | Default | Example | Change impact |
|---|---|---|---|---|
testbed.path | string (path) | (unset = testbed tools error) | "E:/GitHub/plan-forge-testbed" | Absolute or workspace-relative path to the testbed repo. When unset, forge_testbed_run returns ERR_TESTBED_NOT_FOUND with a recovery hint. |
Full annotated example
A realistic .forge.json for a TypeScript project that has opted into Claude as a secondary agent, runs quorum on high-complexity slices, and uses OpenBrain federation to read from a sibling repo:
.forge.json, representative{
"projectName": "myapp",
"preset": "typescript",
"templateVersion": "2.56.0",
"updateSource": "auto",
"agents": ["claude"],
"modelRouting": {
"default": "auto",
"execute": "gpt-5.3-codex",
"review": "claude-opus-4.7"
},
"forgeMaster": {
"reasoningModel": "gpt-4o-mini",
"reasoningProvider": "githubCopilot",
"routerModel": "gpt-4o-mini",
"defaultProvider": "githubCopilot",
"observer": {
"enabled": false,
"maxUsdPerDay": 0.10,
"maxNarrationsPerHour": 6,
"batchWindowMs": 60000,
"modelTier": null
},
"auditor": {
"modelTier": null,
"outputPath": ".forge/health/latest.md"
}
},
"maxParallelism": 3,
"maxRetries": 1,
"maxRunHistory": 50,
"quorum": {
"enabled": true,
"auto": true,
"threshold": 6,
"models": ["claude-opus-4.7", "gpt-5.3-codex", "gemini-3.1-pro"],
"reviewerModel": "claude-opus-4.7",
"dryRunTimeout": 300000,
"strictAvailability": false
},
"extensions": ["notify-slack"],
"hooks": {
"preDeploy": { "enabled": true, "blockOnSecrets": true, "warnOnEnvGaps": true, "scanSince": "HEAD~1" },
"postSlice": { "silentDeltaThreshold": 5, "warnDeltaThreshold": 10, "scoreFloor": 70 },
"preAgentHandoff": { "injectContext": true, "runRegressionGuard": true, "cacheMaxAgeMinutes": 30, "minAlertSeverity": "medium" },
"postRun": { "invokeAuditor": { "onFailure": true, "everyNRuns": null } }
},
"brain": {
"federation": {
"enabled": true,
"repos": ["E:/GitHub/shared-platform-memory"]
}
},
"meta": { "selfRepairRepo": "srnichols/plan-forge" }
}
See also
- Customization — Configuration Hierarchy, how
.forge.jsoninteracts withcopilot-instructions.mdand instruction files when settings conflict. - Appendix U — Environment Variables Reference, the companion reference for everything that lives outside
.forge.json: provider API keys, server ports, orchestrator timing, telemetry. Includes the full resolution precedence when flags, env vars, secrets, and.forge.jsonoverlap. - Appendix G — Update Source Modes, the full story behind
updateSource: auto | github-tags | local-sibling. - Chapter 14 — Quorum Mode, what each
quorum.*key does in practice; the complexity scoring rubric that drivesauto. - Chapter 13 — Multi-Agent Setup, what each entry in
agentsgenerates. - Chapter 22 — How the Shop Remembers, how
brain.federationshapes cross-project memory recall. - pforge-mcp/capabilities.mjs — CONFIG_SCHEMA, the machine-readable JSON Schema this appendix mirrors. If they disagree, the schema wins; please file an issue.