A single ornate enchanted brass key resting on a stone tablet at the workbench inside the Plan Forge shop, the key's bow shaped like a rune cog and its blade glowing softly amber, the stone tablet beside it inscribed with arcane configuration runes that glow faintly
Appendix T

.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.

How to edit safely. Prefer the 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 keySubsystem it controlsWhere it is used
projectName, preset, templateVersion, pipelineVersionProject identityOpenBrain memory scoping, preset gating, version checks
updateSourceUpdate source modepforge update source selection (auto / github-tags / local-sibling)
metaMeta-defect routingforge_meta_bug_file target repository
agentsMulti-agent adaptersGenerates per-agent setup files (Claude / Cursor / Codex)
modelRoutingDefault model selectionOrchestrator slice dispatch, dashboard Cost tab
forgeMasterForge-Master reasoning loopforge_master_ask, dashboard Forge-Master tab
maxParallelism, maxRetries, maxRunHistoryExecution limitsOrchestrator DAG scheduling and retention
quorumMulti-model consensus--quorum=... flag, forge_estimate_quorum
extensionsInstalled extensionspforge ext, Extensions tab
hooksLiveGuard lifecycle hooksPreDeploy, PostSlice, PreAgentHandoff, PostRun
openclawOpenClaw analytics bridgePreAgentHandoff snapshot push (optional)
runtimeInner-loop subsystemsPhase-25 gate synthesis and quorum reviewer
brainMemory and federationOpenBrain federation across local repos
testbedTestbed pathforge_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.

KeyTypeDefaultExampleChange impact
projectNamestring(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.
presetenum(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.
templateVersionstring(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.
pipelineVersionstring"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.

KeyTypeDefaultExampleChange impact
updateSourceenum"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.

KeyTypeDefaultExampleChange impact
meta.selfRepairRepostring(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.

KeyTypeDefaultExampleChange impact
agentsarray<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).

KeyTypeDefaultExampleChange impact
modelRouting.defaultenum"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.executestring(uses default)"gpt-5.3-codex"Model for slice execution. Free-form string so newer models work without a CLI upgrade.
modelRouting.reviewstring(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.

KeyTypeDefaultExampleChange impact
forgeMaster.reasoningModelstring(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.reasoningProviderstring(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.routerModelstring"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.defaultProviderstring(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.

KeyTypeDefaultExampleChange impact
forgeMaster.observer.enabledbooleanfalsetrueMaster 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.maxUsdPerDaynumber0.100.25Daily 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.maxNarrationsPerHournumber612Max narration LLM calls per clock hour. Rate-limits the observer during burst activity.
forgeMaster.observer.batchWindowMsnumber6000030000Event batch flush interval in milliseconds. Lower = more responsive narrations; higher = fewer LLM calls.
forgeMaster.observer.modelTierstring | nullnull"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.

KeyTypeDefaultExampleChange impact
forgeMaster.auditor.modelTierstring | nullnull"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.outputPathstring".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.

KeyTypeDefaultExampleChange impact
maxParallelismnumber (1–10)35Max concurrent [P]-tagged slices. Higher = faster but more contention on shared resources (the file system, the model provider's rate limit, your wallet).
maxRetriesnumber (0–5)12How 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.
maxRunHistorynumber (≥1)50100How 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.

KeyTypeDefaultExampleChange impact
quorum.enabledbooleanfalsetrueMaster switch. When false, quorum is off regardless of the other keys.
quorum.autobooleantruetrueWhen enabled, gate quorum on slice complexity score. When false, every slice fans out.
quorum.thresholdnumber (1–10)65Complexity score above which auto-mode fires quorum. Lower = more slices use quorum, higher cost.
quorum.modelsarray<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.reviewerModelstring"claude-opus-4.7""gpt-5.4"Model that synthesises the dry-run responses into a single execution plan.
quorum.dryRunTimeoutnumber (ms)300000600000Per-worker timeout in milliseconds. Increase for very large slices; the default is 5 minutes.
quorum.strictAvailabilitybooleanfalsetrueWhen 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.

KeyTypeDefaultExampleChange impact
extensionsarray<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

KeyTypeDefaultExampleChange impact
hooks.preDeploy.enabledbooleantruefalseMaster switch for the PreDeploy hook. Disable only if you have an equivalent external gate.
hooks.preDeploy.blockOnSecretsbooleantruetrueWhen true, block deploy if forge_secret_scan finds anything at severity ≥ high. Set false to demote to a warning.
hooks.preDeploy.warnOnEnvGapsbooleantruetrueWarn (do not block) when forge_env_diff finds keys missing from the target environment.
hooks.preDeploy.scanSincestring (git range)"HEAD~1""HEAD~10"Git range scanned for secrets. Widen for repos with bursty commit cadence.

hooks.postSlice

KeyTypeDefaultExampleChange impact
hooks.postSlice.silentDeltaThresholdnumber53Drift score delta below this is silent (no log line).
hooks.postSlice.warnDeltaThresholdnumber1015Drift score delta at or above this prints a warning. Between silent and warn = info.
hooks.postSlice.scoreFloornumber7080Absolute drift score floor, below this triggers a red warning regardless of delta.

hooks.preAgentHandoff

KeyTypeDefaultExampleChange impact
hooks.preAgentHandoff.injectContextbooleantruetrueInject LiveGuard context (drift score, MTTR, open incidents) into the next agent's prompt at handoff.
hooks.preAgentHandoff.runRegressionGuardbooleantruetrueRun forge_regression_guard at handoff time. Disable if your CI already does this.
hooks.preAgentHandoff.cacheMaxAgeMinutesnumber3060Max cache age before LiveGuard tools are re-run. Higher = faster handoffs, staler data.
hooks.preAgentHandoff.minAlertSeveritystring"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.

KeyTypeDefaultExampleChange impact
hooks.preCommit.chainarray[{ 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[].namestring"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[].commandstringnode .github/hooks/PreCommit.mjs <name>node scripts/license-scan.mjsCommand 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.

KeyTypeDefaultExampleChange impact
hooks.postRun.invokeAuditor.onFailurebooleanfalsetrueWhen 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.everyNRunsnumber | nullnull5Invoke 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.

KeyTypeDefaultExampleChange impact
openclaw.endpointstring (URL)(unset = disabled)"https://openclaw.example/api/ingest"Ingest endpoint URL. When set, every PreAgentHandoff posts a context snapshot.
openclaw.apiKeystring(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.

KeyTypeDefaultExampleChange impact
runtime.gateSynthesis.modeenum"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.domainsarray<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.

KeyTypeDefaultExampleChange impact
runtime.reviewer.enabledbooleanfalsetrueMaster switch. Off by default; turn on to get reviewer verdicts in the dashboard Audit-Loop tile.
runtime.reviewer.quorumPresetenum"speed""power"One of speed (cheaper, faster) or power (flagship models, slower).
runtime.reviewer.blockOnCriticalbooleanfalsefalseWhen true, critical verdicts block the next slice. Advisory-only (false) by design.
runtime.reviewer.timeoutMsnumber (ms)3000060000Max 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.

KeyTypeDefaultExampleChange impact
brain.federation.enabledbooleanfalsetrueMaster switch for cross-project read-only memory federation (L4-lite, Phase-25).
brain.federation.reposarray<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.

KeyTypeDefaultExampleChange impact
testbed.pathstring (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