The Inner Loop
Seven subsystems, reflexion, trajectories, auto-skills, gate synthesis, postmortems, federation, and the opt-in reviewer, that turn every slice into a research step.
- Reflexion, when a slice fails, the model gets to re-read its own previous attempt before retrying. (Like reviewing your own essay before rewriting it.)
- Trajectories, short notes the model leaves for itself about what worked and what didn't. Saved per slice.
- Auto-skills, if a pattern keeps showing up across slices, Plan Forge auto-generates a reusable skill so the next slice starts from a higher baseline.
- Gate synthesis, advisory suggestions for stricter validation gates based on what's been failing.
- Postmortems, a one-paragraph summary written after every run: what retried, what cost more, what drifted.
- Federation, optionally publish those postmortems to a shared store so sibling projects benefit from each other's lessons.
- Opt-in reviewer, a second AI checks the slice before it commits. You decide whether to enable it.
For the canonical system-wide overview covering Phase-25 and Phase-26 together, see The Self-Deterministic Agent Loop.
The Inner Loop — State Flow
The deterministic slice executor (Phase-1 through Phase-24) is the spine. The Phase-25 subsystems bolt on reflective behavior at specific transitions, they never replace the spine, they only enrich it.
The Seven Subsystems
Each subsystem has a single job, a single config key (if any), and a single storage artifact. Add them up and you get a closed research loop where every run teaches the next.
1. Reflexion (L7) — the retry gets context
When a slice's validation gate fails, the orchestrator builds a compact Markdown block with the gate command, model, duration, and the stderr tail (≤2KB). That block is injected into the next attempt's prompt so the worker reasons about its prior failure instead of blindly trying the same thing.
- Module:
pforge-mcp/memory.mjs → buildReflexionBlock() - Config: none, always on
- Storage: in-memory per attempt
2. Trajectories (L8) — what actually happened
On slice pass, Plan Forge extracts the sentinel-wrapped note the worker produced (<!-- PFORGE_TRAJECTORY:BEGIN -->…<!-- PFORGE_TRAJECTORY:END -->), word-caps it at 500, and writes it to disk. Postmortems and federation consumers read these for compact run narratives.
- Module:
pforge-mcp/memory.mjs → writeTrajectory() - Config: none, always on
- Storage:
.forge/trajectories/<slice>/<iso>.md
3. Auto-skills (L2) — patterns that earn promotion
A slice that passes gets captured as a candidate auto-skill with its domain keywords, gate commands, and a SHA prefix. Before the next slice, the orchestrator retrieves matching skills (ranked by reuse count) and injects them into the prompt. A skill promotes to "stable" once its reuse count hits the threshold (default 3).
- Module:
pforge-mcp/memory.mjs → retrieveAutoSkills() / writeAutoSkill() - Config: none — defaults are Dashboard-editable in Phase-26
- Storage:
.forge/auto-skills/*.md
4. Adaptive gate synthesis (L6) — Tempering advises your plans
During plan pre-flight the orchestrator scans every slice. If a slice's title or file list matches a Tempering domain profile (domain / integration / controller) but declares no validation gate, it prints a suggested command using the project's Tempering coverage minimum and runtime budget. Default mode is suggest; set mode: "off" to silence it.
- Module:
pforge-mcp/orchestrator.mjs → synthesizeGateSuggestions() - Config:
runtime.gateSynthesis: { mode, domains } - Storage: stdout only (never mutates your plan)
5. Plan postmortems (L5) — the hardener learns from you
After every run, pass or fail, Plan Forge writes a JSON postmortem with retriesPerSlice, gateFlaps, topFailureReason, costDelta, and driftDelta (deltas vs the prior run). Retention is 10 per plan. The Step-2 hardener now reads the newest 3 postmortems and folds their signals into the Scope Contract, closing the loop from execution back into planning.
- Module:
pforge-mcp/orchestrator.mjs → buildPlanPostmortem() / writePlanPostmortem() - Config: retention count via
maxRunHistory-style defaults - Storage:
.forge/plans/<plan-basename>/postmortem-*.json
6. Cross-project federation (L4-lite) — one project's memory helps another
Opt-in. When a cross.* brain recall misses L3 (OpenBrain), the facade fans out to the repos listed in brain.federation.repos[] and reads their .forge/brain/<entity>/<id>.json, read-only, absolute local paths only. URLs and relative paths are rejected by contract.
- Module:
pforge-mcp/brain.mjs → federationRead() - Config:
brain.federation: { enabled, repos: [] }, defaults off - Security: absolute-local-paths-only (D9);
..rejected; defense-in-depth path containment check
7. Reviewer-agent in-loop (L4) — cheap second pair of eyes
Opt-in. When enabled, the brain.gate-check responder invokes a speed-quorum reviewer on each slice's diff summary and attaches a verdict to the response (score, critical, summary, durationMs). Advisory-only by default: critical verdicts do not block the next slice unless operators explicitly set blockOnCritical: true. Blocking mode enters Phase-26 after calibration data exists.
- Module:
pforge-mcp/brain.mjs → invokeReviewer() - Config:
runtime.reviewer: { enabled, quorumPreset, blockOnCritical, timeoutMs } - Defaults:
enabled=false,quorumPreset="speed"(D5),blockOnCritical=false(D6),timeoutMs=30000
Configuration Summary
Everything the Inner Loop exposes lives under two keys in .forge.json, and every key has a toggle in the Dashboard → Config tab.
{
"runtime": {
"gateSynthesis": { "mode": "suggest", "domains": ["domain", "integration", "controller"] },
"reviewer": { "enabled": false, "quorumPreset": "speed", "blockOnCritical": false, "timeoutMs": 30000 }
},
"brain": {
"federation": { "enabled": false, "repos": [] }
}
}
Phase-26 additions (v2.58.0)
Three more subsystems close the loop further, the slice executor can now race strategies, draft its own patches when a gate fails, and flag token-cost drift without halting a run.
- Competitive execution (L9), Opt-in worktree race. Two or more strategies run the same slice under isolated git worktrees; the winner is elected by gate result, reviewer verdict, and token-cost tie-breaker. Off by default. Config:
innerLoop.competitive. See The Competitive Loop for the full flow. - Auto-fix patch proposals (L6), When a gate-fail trajectory suggests a small local correction, the orchestrator drafts a
.patchfile under.forge/proposed-fixes/. Advisory, nothing auto-applies unlessapplyWithoutReview: true. - Cost-anomaly detection (L5), Slices whose token cost drifts above the per-model median by more than
ratio(default 2.0) are recorded in.forge/cost-anomalies.jsonl. Detection only; never halts a run.
Additional config block (added by the v2.58 best-defaults preset for new installs; existing projects opt in):
{
"innerLoop": {
"competitive": { "enabled": false, "maxParallel": 2, "timeoutSec": 1800 },
"autoFix": { "enabled": true, "applyWithoutReview": false },
"costAnomaly": { "enabled": true, "ratio": 2.0, "medianWindow": 20 }
}
}
All three are surfaced in the Dashboard's new Inner Loop tab alongside the Phase-25 subsystems.