CONTEXT FOUNDRY

Technical Reference Manual -- foundry v0.6.1 -- Generated 2026-03-19

System Overview

Context Foundry is an autonomous build loop that runs AI coding agents through a structured pipeline (Scout, Plan, Implement, Doubt) to complete software engineering tasks. Written in Rust (foundry v0.6.1), it provides a ratatui-based TUI dashboard, pattern learning, extension system, dual-model execution arena, and full git integration with PR workflows. The system reads tasks from TASKS.md, processes each through the SPID pipeline, and commits results -- optionally creating per-task pull requests for human review.

CLI Layer main.rs: 7 subcommands Run Status Tasks Plan App Layer app/: Event-driven mpsc AppEvent channel Agent Layer agent.rs: PTY spawn claude / codex CLI TUI Layer tui/: ratatui pipeline+stats+output Build Pipeline app/build.rs SPID: Scout Plan Impl Doubt Ship Git Integration git.rs commit_and_push, PR flow Dual-Model Arena .buildloop/arena/ parallel worktrees Pattern Store ~/.foundry/patterns/ JSON keyword+semantic Extension System extensions.rs discover + load CLAUDE.md MCP Server Model Context Protocol 5 tools for agents dispatch spawn events AppEvent process_task() run_agent() commit/PR dual inject at plan wrap_with_extensions() read/write patterns

SPID Pipeline

The build loop executes a 5-stage pipeline per task: Scout, Plan, Implement, Doubt, Ship. Two ancillary stages -- Discovery and Pattern Extraction -- run outside the per-task pipeline (Discovery triggers when all tasks complete; Pattern Extraction runs after each successful task).

scout-report exists? yes: skip no FAST MODE SCOUT AgentRole::Scout In: TASKS, SPEC, src Out: scout-report.md Skip: fast + report exists Prompt: scout() PLAN AgentRole::Planner In: scout-report, patterns, extensions Out: current-plan.md Skip: simple task + skip_planner_for_simple Lookahead: task N+1 IMPLEMENT AgentRole::Builder In: current-plan.md Out: build-claims.md Dual: parallel worktrees Prompt: builder() batch && !last? yes: skip DOUBT Reviewer + Fixer In: build-claims.md Out: review-report.md Gate: claims > 10 bytes On FAIL: Fixer (2 pass) Skip: backpressure_only Prompt: reviewer() no PASS: feat() FAIL: WIP() SHIP No agent -- git only Auto: commit_and_push() Review: commit_task_pr() Branch: foundry/{task_id} Push: --force-with-lease WIP: skip PR creation DISCOVERY AgentRole::Discovery Runs when all tasks done Appends to TASKS.md PATTERNS Pattern Extraction Runs after each feat() Writes patterns-extracted Dashed = ancillary (outside per-task pipeline) BACKPRESSURE MODE Skips DOUBT entirely. Relies on build/test/lint verification.

Pipeline Variants

Variant Trigger Behavior
Full pipeline_mode: "full" (default) All 5 stages run for every task
Fast pipeline_mode: "fast" Scout skipped when scout-report.md exists. Doubt can be batched to end of session.
Backpressure pipeline_mode: "backpressure" or backpressure_only: true Skip LLM review entirely. Rely on build/test/lint commands for verification.
Batched Doubt batch_doubt: true Doubt runs only on the last pending task. All prior tasks skip Doubt. The final Doubt audits all accumulated changes.

Execution Modes

Mode run_mode Task Source Review Gate WIP Commits PR Poller Ctrl+M
Auto (Loop) "auto" TASKS.md, then Discovery appends more None -- auto-commits after Doubt On Doubt FAIL: WIP commit preserves progress Not used Cycles to "sprint"
Sprint "sprint" TASKS.md only -- no Discovery None -- auto-commits after Doubt On Doubt FAIL: WIP commit preserves progress Not used Cycles to "review"
Review "review" TASKS.md, one task at a time Human gate: waits for Enter or PR approval On Doubt FAIL: WIP commit on feature branch Polls every pr_poll_interval_secs (default 30s) for PR approval/close Cycles to "auto"

Ctrl+D: Dual-Selection States

Ctrl+D cycles through the DualSelection enum (state.rs:216-251). When builder_models has 2+ entries, this controls which model(s) execute:

State Behavior Next (Ctrl+D)
Off (default) Single-model execution using builder_model/builder_provider First
First Uses first entry from builder_models array Second
Second Uses second entry from builder_models array Both
Both run_dual_pipelines() -- both models in parallel git worktrees First

Note: After "Both", cycling returns to "First" (not "Off"). Confirmed from DualSelection::next() at state.rs:243-249.

Ctrl+M cycles run_mode through: auto -> sprint -> review -> auto.

Dual-Model Arena

When builder_models has 2+ entries and dual_selection is "both", run_dual_pipelines() forks execution into two independent git worktrees. Each model runs the full Plan-Implement-Doubt pipeline independently in its own copy of the project.

Worktree Layout

.buildloop/arena/
├── pipeline-0-{provider}/    (git worktree for model[0])
│   ├── .buildloop/
│   │   ├── scout-report.md   (copied from main)
│   │   ├── current-plan.md   (generated by model[0]'s planner)
│   │   ├── build-claims.md   (generated by model[0]'s builder)
│   │   └── review-report.md  (generated by model[0]'s reviewer)
│   └── ... (full project copy)
└── pipeline-1-{provider}/    (git worktree for model[1])
    ├── .buildloop/
    │   ├── scout-report.md
    │   ├── current-plan.md
    │   ├── build-claims.md
    │   └── review-report.md
    └── ... (full project copy)

Event Tagging

Each pipeline wraps its events with AppEvent::DualPipelineEvent(usize, Box<AppEvent>) where the usize is the pipeline index (0 or 1). The TUI dispatches these to the correct stream in DualBuildState.streams[idx].

TUI Tab Bar

The agent output pane shows a tab bar when dual build is active. DualBuildState.tab (0 or 1) controls which stream is displayed. The tab bar shows model labels from DualBuildState.models[0] and DualBuildState.models[1].

Winner Selection

No automated winner selection runs. The human evaluates both worktrees and decides which to keep.

Per-Pipeline State

Tracked in DualBuildState (state.rs:254-264):

FieldTypePurpose
streams[Vec<String>; 2]Agent output lines per pipeline
event_counts[usize; 2]Event count per pipeline
models[String; 2]Model display labels
context_pcts[Option<u8>; 2]Context window usage per pipeline
finished[bool; 2]Completion flag per pipeline
stages[Option<AgentRole>; 2]Current SPID stage per pipeline
stage_models[String; 2]Model label for current stage per pipeline

Git Integration

commit_task_pr Flow (Review Mode)

Foundry Git / GitHub Remember base branch git checkout -B foundry/{task_id} git add -A && git reset -- .buildloop/logs/ git diff --cached --quiet alt [nothing staged]: checkout base, delete branch, return (false, None) git commit -m "feat({task_id}): {desc}" (or "WIP" prefix if is_wip) git push --force-with-lease -u {remote} foundry/{task_id} alt [push OK && !is_wip]: gh pr create --base {base} --title "feat({task_id}): ..." if create fails: gh pr list --head foundry/{task_id} (find existing PR) annotate_tasks_with_pr() Stage TASKS.md, commit annotation, push --force-with-lease git checkout {base_branch} git show foundry/{task_id}:TASKS.md (copy to base) Stage TASKS.md, commit "mark {task_id} done", push to auto_push_remote return (true, pr_number)

commit_and_push (Auto/Sprint Mode)

The simpler flow for auto and sprint modes:

  1. git add -A
  2. git reset -- .buildloop/logs/
  3. git diff --cached --quiet (bail if nothing staged)
  4. git commit -m "feat({task_id}): {desc}" (or WIP prefix)
  5. maybe_push_commit() -- push to auto_push_remote if set

Key Details

AspectDetail
Branch namingfoundry/{task_id} (task_id lowercased, e.g. foundry/t1.1)
Push strategy--force-with-lease (safe force push, fails if upstream diverged)
auto_push_remoteDefaults to None (local commits only). When set, pushes to that remote.
WIP commitsWhen is_wip is true, branch + commit still happen, but PR creation is skipped.
create_issue_on_wipWhen enabled and task is WIP, create_wip_issue() creates a GitHub issue with review findings.

TUI Layout

The running screen layout is defined in tui/mod.rs:122-165. Five vertical zones, with the middle zone split 60/40 horizontally.

┌────────────────────────────────────────────────────────────────────────┐
│ HEADER (5 lines)                                                       │
│  Project name │ Phase badge (Startup/Planning/Running)                  │
│  Mode badge (auto/sprint/review) │ Task: T1.1 -- description           │
│  Agent: IMPLEMENT (claude:opus) ⠋ 2m34s                                │
│  [dual tab bar when active: model[0] │ model[1]]                       │
├────────────────────────────────────────────────────────────────────────┤
│ PIPELINE DIAGRAM (7 lines)                                             │
│  ┌──────────┐   ┌──────────┐   ┌──────────┐   ┌──────────┐   ┌──────────┐ │
│  │  SCOUT   │──>│   PLAN   │──>│IMPLEMENT │──>│  DOUBT   │──>│  SHIP    │ │
│  │ sonnet   │   │  opus    │   │  opus    │   │ sonnet   │   │ GitHub   │ │
│  │scout-rpt │   │curr-plan │   │bld-claim │   │fresh ctx │   │ git+pr   │ │
│  └──────────┘   └──────────┘   └──────────┘   └──────────┘   └──────────┘ │
│  ┌──────────┐   ┌──────────┐  (disconnected)                            │
│  │ DISCOVER │   │ PATTERNS │                                             │
│  └──────────┘   └──────────┘                                             │
├──────────────────────────────────┬─────────────────────────────────────┤
│ AGENT OUTPUT (60% width)         │ TASK QUEUE (40% width, min 6 lines) │
│  [scrollable log of agent text,  │  H1.1: Create overview...           │
│   tool calls, tool results]      │  D32.1: Fix pipeline bug...         │
│                                  │  (H=yellow, D=blue, T=white)        │
│  Events: AppEvent::AgentOutput   │                                     │
│                                  ├─────────────────────────────────────┤
│                                  │ PATTERNS LEARNED (6 lines)          │
│                                  │  [pattern activity feed]            │
│                                  ├─────────────────────────────────────┤
│                                  │ EXTENSIONS USED (6 lines)           │
│                                  │  [extension injection feed]         │
├──────────────────────────────────┴─────────────────────────────────────┤
│ STATS PANEL (6 lines)                                                  │
│  Progress: [████████░░░░] 3/7 │ Git: main (3 dirty)                   │
│  Context%: S:45% P:72% I:89% D:-- │ Patterns: 3 injected, 1 used     │
│  Session: 12m │ Cost: $0.47 │ Commits: 2 feat, 0 WIP                  │
│  Agent: IMPLEMENT (claude:opus) running... ⠋                           │
├────────────────────────────────────────────────────────────────────────┤
│ STATUS BAR (1 line)                                                    │
│  q stop  Ctrl+C quit  ↑↓ scroll  i inject  PgUp/PgDn queue  p patt   │
│  ^T theme  Tab explore  [Enter continue]  [f findings]                 │
└────────────────────────────────────────────────────────────────────────┘

Pane-to-Event Mapping

Pane Widget Driven by AppEvent
Header render_header LoopEvent::TaskStarted, LoopEvent::AgentStarted, DualBuildStarted
Pipeline Diagram render_pipeline_map LoopEvent::AgentStarted (highlights active stage)
Agent Output render_agent_output AppEvent::AgentOutput(AgentOutputEvent::*), DualPipelineEvent
Task Queue render_task_queue LoopEvent::QueueUpdated, LoopEvent::TaskCompleted
Patterns Learned render_patterns LoopEvent::PatternsUsed
Extensions Used render_extensions_used LoopEvent::ExtensionInjected
Stats Panel render_dashboard_stats AppEvent::AgentOutput(Usage{...}), LoopEvent::CountsUpdated
Status Bar render_status_bar AppPhase changes, awaiting_review, awaiting_pr

Keybinds

From tui/running.rs:695-814:

KeyAction
qStop after current task
Ctrl+CForce quit
↑↓Scroll agent output
iInject text into running agent
PgUp/PgDnScroll task queue
pToggle pattern overlay
^TCycle TUI theme (dark -> catppuccin -> solarized -> dark)
TabToggle explore/dashboard view
EnterContinue (when awaiting review) or skip wait (when awaiting PR)
fToggle findings (when orchestrator outcome exists)

Configuration Reference

Configuration Reference (.foundry.json) -- 55 fields
Field Type Default Description
scout_model String "sonnet" Model name for Scout agent
planner_model String "opus" Model name for Planner agent
builder_model String "opus" Model name for Builder agent
builder_models Vec<String> [] Dual-model execution specs, format "provider:model". When len >= 2, overrides builder_model/builder_provider.
dual_selection String "" (off) Dual-build selection: "first", "second", "both", or "" (off). Ctrl+D cycles through states.
reviewer_model String "sonnet" Model name for Reviewer agent
fixer_model String "sonnet" Model name for Fixer agent
discovery_model String "opus" Model name for Discovery agent
scout_provider String "claude" Provider for Scout: "claude" or "codex"
planner_provider String "claude" Provider for Planner
builder_provider String "claude" Provider for Builder
reviewer_provider String "claude" Provider for Reviewer
fixer_provider String "claude" Provider for Fixer
discovery_provider String "claude" Provider for Discovery
studio_claude_model String "opus" Claude model for Studio mode
studio_codex_model String "" Codex model for Studio mode
studio_theme String "foundry" Studio UI theme name
studio_custom_themes BTreeMap<String, StudioThemeConfig> {} Custom Studio theme definitions
pause_between_tasks_secs u64 10 Seconds to wait between tasks
pause_between_agents_secs u64 3 Seconds to wait between agent spawns
pause_between_cycles_secs u64 30 Seconds to wait between discovery cycles
agent_timeout_secs u64 600 Max seconds before killing an agent (10 min)
patterns_dir String "~/.foundry/patterns" Directory for global pattern store
backpressure_only bool false Skip LLM review, rely on build/test/lint only
simple_planner_model String "sonnet" Override planner model for Simple tasks
simple_builder_model String "sonnet" Override builder model for Simple tasks
simple_reviewer_model String "" Override reviewer for Simple tasks ("" = skip review)
max_pattern_injection usize 10 Max patterns injected into agent prompts
planning_iterations u64 0 Max iterations for foundry plan mode (0 = unlimited)
adaptive_pauses bool true Skip full sleep when agent was not rate-limited (500ms min)
auto_push_remote Option<String> null Git remote to auto-push after commits (null = local only)
semantic_match_enabled bool true Enable semantic pattern matching via Ollama embeddings
embedding_model String "nomic-embed-text" Ollama embedding model name
ollama_url String "http://127.0.0.1:11435" Ollama API base URL for embeddings
embedding_timeout_ms u64 2000 Timeout for Ollama embedding requests in milliseconds
orchestrator_proposer_provider String "claude" Design mode: proposer model provider
orchestrator_proposer_model String "opus" Design mode: proposer model name
orchestrator_reviewer_provider String "claude" Design mode: reviewer model provider
orchestrator_reviewer_model String "opus" Design mode: reviewer model name
orchestrator_max_iterations usize 3 Design mode: max proposal/review iterations
orchestrator_accept_policy String "no-high-medium" Design mode: acceptance policy ("no-high", "no-high-medium", "no-findings")
review_mode String "diff-only" Reviewer input: "diff-only" or "file-list"
skip_planner_for_simple bool true Skip planner for Simple-complexity tasks
discovery_cooldown_minutes u64 5 Minutes before running discovery after last H-task
planner_lookahead bool true Pre-plan task N+1 while building task N
pattern_extraction_model String "sonnet" Model for pattern extraction (lightweight)
run_mode String "auto" Execution mode: "auto", "sprint", or "review"
pipeline_mode String "full" Pipeline mode: "full", "fast", or "backpressure"
batch_doubt bool false Defer doubt to last task only
extensions Vec<String> [] Selected extension names (e.g., ["roblox", "extend"])
create_issue_on_wip bool false Create GitHub issue on WIP (failed) commits
preview_wrap bool true Preview pane word-wrap preference
pr_poll_interval_secs u64 30 Seconds between PR review status checks
theme String "dark" TUI color theme: "dark", "catppuccin", or "solarized"

Extensions

Extensions provide domain-specific knowledge to agents. They are discovered from ~/.foundry/extensions/ (global), ancestor directories' extensions/ folders, and <project>/extensions/ (local). Each extension directory must contain a CLAUDE.md file. Project-local extensions override global ones with the same name. Extension context is built by load_extension_context() and prepended to agent prompts via wrap_with_extensions().

8.0 Extension Taxonomy

An extension (or domain pack) is a directory containing any combination of the following component types:

Component Location Purpose Required?
Instructions CLAUDE.md Authored domain rules, critical constraints, session-start checklists. Always injected into agent prompts when the extension is selected. Yes
Patterns patterns/*.json Learned recurring pitfalls in canonical pattern schema (pattern_id, title, issue, solution). Keyword-matched at plan time. No
Docs docs/ Reference guides, specs, API documentation, governance lists, asset inventories, analyzer output. No
Templates templates/ Starter blueprints and proven command templates for common operations. No
Examples examples/ Working reference implementations, sample projects, demo flows. No

The patterns/ directory is ONLY for canonical-schema pattern JSON. Every file in patterns/ must be parseable by the pattern loader (src/patterns.rs) as either a Vec<Pattern>, a PatternWrapper, or a single Pattern. Reference docs, asset catalogs, expertise metadata, and governance lists belong in docs/.

extensions/<name>/
├── CLAUDE.md                          # Instructions (required)
├── patterns/
│   └── <name>-common-issues.json      # Canonical pattern JSON only
├── docs/                              # Reference guides, specs, asset catalogs
├── templates/                         # Starter blueprints, command templates
├── examples/                          # Working reference projects
├── scripts/                           # Utility scripts
└── config/                            # Configuration files

8.1 Roblox

extensions/roblox/

8.2 Workday Extend

extensions/extend/

8.3 Recon

extensions/recon/

8.4 Flowise

extensions/flowise/

8.5 Mindcraft

extensions/mindcraft/

MCP Tools

Context Foundry exposes five MCP (Model Context Protocol) tools that allow AI agents to interact with the pattern store and delegate work. The MCP server source is not in this repo (only __pycache__ remnants in tools/); documentation is derived from CLAUDE.md and the patterns module API.

Tool Signature Reads/Writes Usage Note
read_global_patterns read_global_patterns(category: str) Reads ~/.foundry/patterns/*.json Load patterns before starting work; category is typically "common-issues"
save_global_patterns save_global_patterns(patterns: list, category: str) Writes to ~/.foundry/patterns/{category}.json Save newly discovered patterns after solving issues
merge_project_patterns merge_project_patterns(path: str, category: str) Reads project patterns, writes to global store Promotes project-local patterns to ~/.foundry/patterns/; deduplicates by pattern_id
delegate_to_claude_code delegate_to_claude_code(task: str, ...) Spawns a fresh Claude Code instance Delegate subtasks to a fresh agent with independent context
search_skills search_skills(query: str) Reads pattern store and skills index Find reusable code patterns and skills by keyword search

Pattern Store

Location: ~/.foundry/patterns/ (configurable via patterns_dir in .foundry.json). Tilde is expanded via $HOME (or $LOCALAPPDATA/$USERPROFILE on Windows). Fallback: /tmp/.foundry/patterns/ if HOME is unset.

JSON Schema

From src/patterns.rs:17-41:

{
  "pattern_id": "string (unique identifier)",
  "title": "string",
  "first_seen": "string (ISO date)",
  "last_seen": "string (ISO date)",
  "frequency": 0,
  "severity": "HIGH | MEDIUM | LOW | null",
  "keywords": ["string"],
  "tech_stack": ["string"],
  "issue": "string | null",
  "solution": {
    "planner": "string (advice for planner agent)",
    "reviewer": "string (advice for reviewer agent, alias: validator)"
  },
  "auto_apply": false,
  "learned_from": "string | null (project/task that produced this pattern)"
}

Supported JSON Formats

Three formats are accepted:

Pattern Matching at Plan Time

Pattern Lifecycle

  1. After each task: pattern_extraction agent writes .buildloop/patterns-extracted.json
  2. Extraction model: pattern_extraction_model (default "sonnet")
  3. merge_patterns() deduplicates by pattern_id, increments frequency on duplicates, updates last_seen
  4. Auto-apply graduation: patterns reaching frequency >= 3 gain auto_apply: true

Samsara / Discovery

When all tasks in TASKS.md are complete AND run_mode is "auto" (not sprint or review), the Discovery stage triggers. The name "Samsara" refers to the cycle of rebirth -- after Discovery, the build loop restarts with new tasks, forming an infinite improvement cycle.

Discovery Agent

The Discovery agent (AgentRole::Discovery) scans:

Output

Appends new tasks under a ## Discovery Round N header in TASKS.md.

Task ID Convention

Format: D{round}.{sub} -- e.g., D33.1, D33.2. The highest_discovery_round() function (task.rs:188-214) parses both section headers (## Discovery Round N) and task ID regex (D(\d+)\.) to find the max round number.

Cooldown

discovery_cooldown_minutes (default 5). When Discovery finds 0 new tasks, the cooldown doubles (up to 30 minutes maximum). This prevents tight loops of empty discovery scans.

Prompts

prompts::discovery() for scanning, prompts::append_tasks() for writing new tasks to TASKS.md.

Samsara Loop

┌─────────────┐
│  TASKS.md   │<──────────────────────────────┐
│  (pending)  │                               │
└──────┬──────┘                               │
       │                                      │
       v                                      │
┌─────────────┐    ┌───────────┐    ┌─────────┴───────┐
│ SPID Pipeline│──>│   SHIP    │──>│    DISCOVERY     │
│ per task     │    │ commit/PR │    │ scan codebase   │
└─────────────┘    └───────────┘    │ append new tasks │
                                    └─────────────────┘
                                    (auto mode only)