# TeamBuild v0.1 — System Design Document

**Date:** 2026-02-10
**Status:** Final (v0.1)
**Inputs:** requirements.md, interview-agent-synthesis.md, all research materials (see HANDOFF.md)

---

## 1. System Overview

TeamBuild is an **AI-powered engineering workflow framework**. It owns the lifecycle before and after code is written — planning, validation, review, metrics — while the actual code execution is a pluggable slot that can be filled by any coding agent (Claude Code, Cursor, Aider, a human, or TeamBuild's own optional managed executor).

**Core identity:** TeamBuild is the workflow layer. Agent runtimes are the execution layer. TeamBuild doesn't care who writes the code — it cares that the right thing gets built, validated, and tracked.

### High-Level Architecture

```mermaid
graph TD
    subgraph "TeamBuild CLI"
        TB_INT["teambuild interview"]
        TB_PLAN["teambuild plan"]
        TB_CHECK["teambuild check"]
        TB_REVIEW["teambuild review"]
        TB_METRICS["teambuild metrics"]
        TB_CODE["teambuild code<br/>(optional managed executor)"]
    end

    subgraph "Workflow Modules (TeamBuild owns these)"
        IA[Interview Agent]
        PM[PM Integration]
        CR[Critique/Review Layer]
        VAL[Validation Runner]
        MET[Cost/Performance Metrics]
    end

    subgraph "Foundation"
        PA[Provider Abstraction]
        CWM[Context Window Manager]
        IDX["Index Manager<br/>(.index.md files)"]
    end

    subgraph "Execution Layer (pluggable — not owned by TeamBuild)"
        AGENT_ANY["Any Coding Agent<br/>Claude Code / Cursor / Aider / Human"]
    end

    subgraph "External Services"
        PLANE[Plane API]
        LINEAR[Linear API]
        AI_PROVIDERS["AI Providers<br/>Anthropic / OpenAI / Bedrock / Ollama"]
        GIT[Git / GitHub]
    end

    TB_INT --> IA
    TB_PLAN --> PM
    TB_CHECK --> VAL
    TB_REVIEW --> CR
    TB_METRICS --> MET
    TB_CODE -.->|optional wrapper| AGENT_ANY

    IA --> PM
    IA --> MET
    PM -->|spec + acceptance criteria| AGENT_ANY
    AGENT_ANY -->|code changes| VAL
    VAL --> CR
    CR -->|fix prompts| AGENT_ANY
    CR --> PM

    IA --> PA
    CR --> PA

    PA --> AI_PROVIDERS
    PM --> PLANE
    PM --> LINEAR
    AGENT_ANY --> GIT

    MET -.->|collects from| IA
    MET -.->|collects from| CR
    MET -.->|collects from| VAL
    MET -.->|collects from| PA
    MET --> PM

    CWM -.->|budgets for| IA
    CWM -.->|budgets for| CR
    IDX -.->|context for| AGENT_ANY
    IDX -.->|context for| CR

    style AGENT_ANY fill:#f0f0f0,stroke-dasharray: 5 5
```

**Key distinction:** The dashed box is not TeamBuild. It's whatever the developer already uses to write code. TeamBuild bookends the process — planning on one side, validation and review on the other — and the indexes help whatever's in the middle work efficiently.

### Module Dependency Graph

```mermaid
graph BT
    PA[Provider Abstraction] --> IA[Interview Agent]
    PA --> CR[Critique/Review Layer]

    PM[PM Integration] --> CR

    IA --> PM

    MET["Metrics (lightweight lib)"] -.->|no hard dependency| PA
    MET -.-> PM

    VAL[Validation Runner] -.->|utility| CR

    IDX[Index Manager] -.->|utility| CR

    EX["Managed Executor<br/>(optional)"] --> VAL
    EX --> PM

    style PA fill:#e1f5fe
    style MET fill:#fff3e0
    style VAL fill:#fff3e0
    style IDX fill:#fff3e0
    style EX fill:#f0f0f0,stroke-dasharray: 5 5
```

**Build order implications:**
1. **Provider Abstraction** (foundation) — must be stable first
2. **Metrics Collection** (foundation) — lightweight lib, all modules import it
3. **Interview Agent** — first real proof of value, depends only on Provider + Metrics
4. **PM Integration** — depends on Provider + Metrics
5. **Validation Runner** (`teambuild check`) — standalone CLI, no agent dependency
6. **Critique/Review Layer** — depends on Provider + PM + Validation
7. **Cost/Performance Metrics** (full module) — storage, reporting, dashboards. Built BY items 1-6 as dogfooding
8. **Managed Executor** (optional) — wraps coding agents with rules, monitoring, validation. Built last, uses everything above

---

## 2. Agent Workflow Contract

**This is the most important section in the design doc.** Everything else is module design. This section defines the rules that every agent must follow every time, enforced mechanically — not by documentation, not by best practices, not by hoping the agent remembers.

The core problem: agents need to update index files, report metrics, hand off state, and update tickets. Programmers are terrible at remembering to do housekeeping. AI agents are no different — if it's not enforced, it will be skipped, and the whole context management system collapses.

### 2.1 The Lifecycle — Every Task, Every Time

```mermaid
flowchart TD
    PICKUP["1. PICKUP<br/>Claim ticket from PM<br/>Update status: in_progress"] --> LOAD["2. LOAD<br/>Read root index → route to relevant modules<br/>Load only what ticket scope markers specify"]
    LOAD --> BUDGET["3. BUDGET CHECK<br/>Reserve 15% of context for housekeeping<br/>Work budget = 85% of remaining context"]
    BUDGET --> WORK["4. WORK<br/>TDD cycle: tests → implement → validate<br/>Stay within work budget"]
    WORK --> MONITOR{"5. BUDGET MONITOR<br/>Still within work budget?"}
    MONITOR -->|yes| WORK
    MONITOR -->|approaching limit| HOUSEKEEP
    WORK -->|task complete| VALIDATE["6. VALIDATE<br/>Self-validation gates<br/>(language-agnostic)"]
    VALIDATE -->|pass| HOUSEKEEP["7. HOUSEKEEPING<br/>(mandatory — cannot skip)"]
    VALIDATE -->|fail, retries left| WORK
    VALIDATE -->|fail, no retries| ESCALATE["ESCALATE<br/>Circuit breaker → human"]
    ESCALATE --> HOUSEKEEP

    subgraph "7. HOUSEKEEPING — Mandatory Steps"
        direction TB
        H1["a. Update index files<br/>for every file touched"] --> H2["b. Report metrics<br/>tokens, cost, duration, outcome"]
        H2 --> H3["c. Update PM ticket<br/>status, metrics, comments"]
        H3 --> H4["d. Commit state<br/>if checkpointing for fresh context"]
        H4 --> H5["e. Hand off<br/>next agent can pick up<br/>without re-reading anything"]
    end

    HOUSEKEEP --> DONE["8. DONE<br/>Context released"]

    style HOUSEKEEP fill:#ffcdd2
    style BUDGET fill:#fff3e0
    style MONITOR fill:#fff3e0
```

### 2.2 Enforcement Mechanisms

Housekeeping can't be optional. Here's how each step is enforced:

| Step | Enforcement | What Happens If Skipped |
|------|-------------|------------------------|
| **Update indexes** | Post-edit hook detects file changes, blocks commit if touched files have stale indexes | Commit blocked. Agent sees: "You modified auth/session.py but auth/.index.md is stale. Update it before committing." |
| **Report metrics** | Metrics collector wraps every `AgentProvider.invoke()` call automatically | Can't skip — it's in the provider abstraction itself, not the agent's responsibility |
| **Update PM ticket** | Pre-handoff hook checks ticket status matches work state | Handoff blocked. Agent sees: "Ticket TEAM-042 is still 'in_progress' but your work is complete. Update the ticket." |
| **Commit state** | Pre-compaction hook requires plan + report before context can be released (from hooks research) | Compaction blocked. Agent sees: "Write a handoff summary before compacting. What was done, what's left, what did you learn." |
| **Hand off cleanly** | Handoff validation checks that the next agent has everything it needs without re-reading files | Handoff blocked until state file is complete |

### 2.3 The Context Budget — Smart Window, Not Full Window

The raw context window (e.g., 200K tokens) is **not the usable budget**. Model quality degrades well before the window is full — the "smart window" where output quality is high is significantly smaller than the raw limit. The budget must respect this reality.

```
Raw context window:    200,000 tokens (model limit)
├── Smart window:      120,000 tokens — quality output zone
│   └── Work budget:   120,000 tokens — agent's actual task
├── Housekeeping:       30,000 tokens — index updates, metrics, handoff
│   ├── Index updates:    10,000 tokens
│   ├── PM ticket update:  5,000 tokens
│   ├── Metrics report:    5,000 tokens
│   └── Handoff state:    10,000 tokens
└── Hard ceiling:       ~150,000 tokens — absolute max before forced handoff
    └── Beyond this: quality is degraded, don't work here
```

**Key principle:** When the work budget is exhausted, the agent does housekeeping and then **hands off to a fresh agent** — not a compaction. Compaction loses context. A true handoff writes structured state to the PM ticket and shared knowledge layer so the next agent picks up cleanly with a full smart window.

All thresholds are **configurable per model** because this will change as models improve:

```python
class AgentBudget(BaseModel):
    """Context budget configuration. All values configurable per model/provider."""

    # The raw context window size (from provider abstraction)
    raw_context_limit: int = 200_000

    # The smart window — where output quality is high
    # Current reality: ~120K for most models. Will increase over time.
    smart_window: int = 120_000

    # Housekeeping reserve — always available after work budget is spent
    housekeeping_budget: int = 30_000

    # Hard ceiling — absolute max before forced handoff
    # Should rarely be reached. Work + housekeeping should fit below this.
    hard_ceiling: int = 150_000

    @property
    def work_budget(self) -> int:
        """How many tokens the agent can use for actual work."""
        return self.smart_window

    def status(self, used_tokens: int) -> Literal["working", "housekeeping", "handoff"]:
        if used_tokens < self.smart_window:
            return "working"
        if used_tokens < self.smart_window + self.housekeeping_budget:
            return "housekeeping"
        return "handoff"  # Forced handoff — do not continue working

    def should_start_housekeeping(self, used_tokens: int) -> bool:
        return used_tokens >= self.smart_window

    def must_handoff(self, used_tokens: int) -> bool:
        return used_tokens >= self.hard_ceiling
```

**What happens at each threshold:**
- **< 120K (working):** Agent does its task normally.
- **120K reached (housekeeping):** Agent stops working. Updates indexes, reports metrics, updates PM ticket, writes handoff state. Has 30K tokens to do this cleanly.
- **150K reached (forced handoff):** Agent must stop immediately. Writes whatever state it has and hands off. This is the emergency brake — it should never be needed if the 120K trigger works correctly.
- **Never compact.** Always hand off to a fresh agent with a full smart window. The handoff state + shared knowledge layer gives the new agent everything it needs without re-reading files.

### 2.4 Mandatory Handoff State

When an agent finishes (or hits its budget limit), it must produce a handoff state that lets the next agent pick up without re-reading anything:

```python
class HandoffState(BaseModel):
    ticket_id: str
    status: Literal["completed", "checkpointed", "escalated"]

    # What was done
    files_modified: list[str]
    files_created: list[str]
    indexes_updated: list[str]
    tests_added: list[str]

    # What's left (if checkpointed)
    remaining_work: str | None = None
    next_steps: list[str] = []
    blockers: list[str] = []

    # What was learned (survives context boundaries)
    key_decisions: list[str] = []
    gotchas: list[str] = []        # "Don't do X because Y"
    context_needed: list[str] = []  # Files the next agent should load

    # Metrics
    tokens_used: int
    cost_usd: float
    duration_seconds: float
    attempts: int
```

This state is written to the shared knowledge layer and attached to the PM ticket. The next agent's first action is reading this state — not re-priming from scratch.

### 2.5 Index Update Rules

Index updates are the highest-risk housekeeping item. Rules:

1. **If you modify a file, you update its module's `.index.md`** — no exceptions. The post-edit hook enforces this.
2. **If you create a new file, you add it to the module's `.index.md`** — with purpose, line count, and exports.
3. **If you delete a file, you remove it from the module's `.index.md`**.
4. **If you change a module's exports or purpose, you update the root `.index.md`** — so routing stays accurate.
5. **Index updates happen in the housekeeping phase** — not during work. The agent tracks what changed and does all index updates in one batch at the end. This is more efficient and ensures nothing is missed.
6. **The post-edit hook tracks which files were touched** — at commit time, it cross-references against the indexes and blocks if anything is stale.

### 2.6 No Silent Exits

An agent must never silently run out of context. The budget monitor catches this before it happens, but as a safety net:

- **Pre-compaction hook** (from hooks research): Before any context compaction, the agent must write a handoff state and update all indexes. If it tries to compact without this, the hook blocks it.
- **Session end hook**: If the agent's session ends for any reason, it writes whatever state it has. Partial state is better than no state.
- **Crash recovery**: The PM ticket always reflects the last known state. If an agent crashes mid-task, the ticket status and any partial handoff state tell the next agent (or human) exactly where things stand.

### 2.7 The Contract, Summarized

Every agent, every task, no exceptions:

```
1. PICKUP    — Claim ticket, update PM status
2. LOAD      — Root index → relevant module indexes → files (only what's needed)
3. BUDGET    — Reserve 15% for housekeeping. Work within the remaining 85%.
4. WORK      — TDD cycle. Stay within work budget.
5. MONITOR   — If approaching work budget limit → start housekeeping.
6. VALIDATE  — Self-validation gates. Circuit breaker if stuck.
7. HOUSEKEEP — Update indexes, report metrics, update PM, write handoff state.
8. DONE      — Context released. Next agent can pick up cleanly.
```

Steps 1-3 and 7-8 are **framework-level** — the agent doesn't choose to do them, the system does them automatically. Steps 4-6 are where the agent does its actual work.

---

## 3. Integration Model

**Core principle:** TeamBuild is a CLI tool and workflow framework. It does not depend on any specific agent runtime. It integrates into projects through standard, universal mechanisms — files in the repo and a CLI.

### 3.1 What TeamBuild Is NOT

- **NOT a Claude Code plugin.** It doesn't manage `.claude/` or generate skills/hooks for any specific tool.
- **NOT an agent runtime.** It doesn't compete with Claude Code, Cursor, or Aider. Those are execution tools. TeamBuild is the workflow layer around them.
- **NOT another config directory.** No `.teambuild/` folder. No proprietary config format that clutters the repo.

### 3.2 How TeamBuild Plugs Into a Project

TeamBuild integrates through three universal mechanisms:

**1. Git-native indexes (`.index.md` files)** — committed to the repo, version-controlled, reviewable in PRs. Any agent, any tool, any human can read them. They're just markdown files. This is the primary integration surface.

**2. Project config in `pyproject.toml`** — TeamBuild settings live under `[tool.teambuild]`, following the standard Python convention (like ruff, mypy, pytest). No separate config file. For non-Python projects, a `teambuild.toml` at project root.

```toml
[tool.teambuild]
# Validation
test_cmd = "pytest"
lint_cmd = "ruff check ."
type_cmd = "mypy ."
format_cmd = "ruff format ."

# Context
index_root = ".index.md"
smart_window = 120000

# PM
pm_adapter = "plane"
pm_project_id = "TEAM"

# Metrics
metrics_store = "jsonl"
metrics_path = ".teambuild-metrics/"  # gitignored
```

**3. A standalone CLI** — `teambuild` commands work independently. No agent runtime required. A developer can use `teambuild check` without ever touching an AI coding agent.

### 3.3 The CLI Surface

```
teambuild init              Analyze project (L1+L2), generate root .index.md
teambuild index [module]    Regenerate index for a specific module (or all)

teambuild interview         Run the Interview Agent (interactive)
teambuild plan <spec>       Generate tickets + acceptance criteria from a spec

teambuild check             Run all validation gates (test, lint, type, format, security)
teambuild check --gate=test Run a single validation gate
teambuild review [files]    Run AI-powered code review

teambuild metrics           Show cost/quality dashboard
teambuild metrics export    Export metrics to PM tool

teambuild code <ticket>     (Optional) Managed execution — wraps a coding agent
                            with rules, monitoring, and automatic validation
```

Every command is independently useful. You can use `teambuild check` without `teambuild interview`. You can use `teambuild index` without `teambuild code`. No command assumes a specific agent runtime.

### 3.4 Agent Runtime Independence

The indexes, validation, and review work regardless of what writes the code:

| Workflow Step | TeamBuild's Role | Agent Runtime's Role |
|---------------|-----------------|---------------------|
| **Planning** | `teambuild interview` + `teambuild plan` produce spec + tickets | None — this is TeamBuild's job |
| **Context** | `.index.md` files in the repo | Agent reads them like any other file |
| **Coding** | Not involved (unless using managed executor) | Agent writes code however it works |
| **Validation** | `teambuild check` runs tests/lint/types | None — validation is standalone |
| **Review** | `teambuild review` produces fix prompts | Agent picks up fix prompts |
| **Metrics** | `teambuild metrics` tracks everything | Agent's own usage tracked via provider abstraction |

**The handoff document is the contract.** TeamBuild produces a spec with acceptance criteria and scope markers. Any agent can read it. TeamBuild validates the output. It doesn't matter what happened in between.

### 3.5 Optional: Thin Convenience Layer for Specific Runtimes

For teams that want `teambuild init` to also set up their agent runtime (write a CLAUDE.md, generate a .cursorrules, etc.), this is a thin optional script — not an abstraction layer, not an adapter pattern. A one-shot generator that writes a file pointing at the indexes and listing the `teambuild` CLI commands. If the runtime's config format changes, you regenerate. There's nothing to sync or keep in drift.

```
teambuild setup claude      Write a CLAUDE.md pointing at indexes + teambuild commands
teambuild setup cursor      Write a .cursorrules with the same content
teambuild setup generic     Write a AGENTS.md (plain markdown, any tool can read it)
```

This is explicitly **not** an adapter pattern. There's no `AgentRuntimeAdapter` ABC. Each generator is 50-100 lines of string formatting. If a new tool appears, someone writes a new generator in an afternoon. If an old tool dies, its generator is deleted with zero impact.

---

## 4. Three-Layer Project Understanding

**Key insight:** 80% of project understanding costs zero AI tokens.

When TeamBuild needs to understand a project (for `teambuild init`, for index generation, for scoping tickets), it uses a three-layer approach that maximizes free analysis and uses AI only when necessary.

### 4.1 Layer 1 — Static Analysis (Free)

Zero tokens. Runs in seconds. Provides the structural skeleton.

| Signal | Source | What It Tells You |
|--------|--------|-------------------|
| File list + directory tree | `git ls-files` | Project shape, module boundaries |
| File sizes | filesystem | Where the complexity lives |
| Package manifests | `pyproject.toml`, `package.json`, `Cargo.toml` | Dependencies, entry points, tool configs |
| Git change frequency | `git log --stat` | What's actively being worked on |
| Co-change patterns | `git log` correlation | Which files change together (implicit coupling) |
| Entry points | manifest detection | Where execution starts |

### 4.2 Layer 2 — AST Parsing (Free)

Zero tokens. Runs in seconds. Provides the dependency graph and public API surface.

**Tool:** tree-sitter (language-agnostic AST parser)

| Signal | What It Tells You |
|--------|-------------------|
| Exports per file | Public API surface — what each module offers |
| Imports per file | Dependency graph — who depends on whom |
| Function/class signatures | Interface contracts without reading implementation |
| Import graph | Module relationships, circular dependencies, layering violations |

Tree-sitter supports Python, TypeScript, Rust, Go, Java, and 50+ other languages from the same API. This keeps TeamBuild language-agnostic at the analysis layer.

### 4.3 Layer 3 — AI Summarization (Expensive, Lazy)

Costs tokens. Done **once per module**, on first access. Cached in the module's `.index.md`.

This is the only layer that requires AI. It answers the question Layer 1 and Layer 2 can't: **"What does this module do in business terms?"**

- Input: Module's exports, imports, file list, and (optionally) 2-3 key files
- Output: A 3-5 sentence business-level description written into the module's `.index.md`
- When: Lazily, the first time an agent or `teambuild index <module>` targets that module
- Cost: One cheap AI call per module (haiku-tier model, ~500 tokens output)

### 4.4 Bootstrap Flow

```mermaid
flowchart TD
    INIT["teambuild init"] --> L1["Layer 1: Static Analysis<br/>git ls-files, file sizes, manifests,<br/>change frequency, entry points"]
    L1 --> L2["Layer 2: AST Parsing<br/>tree-sitter: exports, imports,<br/>signatures, dependency graph"]
    L2 --> ROOT["Generate root .index.md<br/>(one cheap AI call — summarize<br/>project structure from L1+L2 data)"]
    ROOT --> DONE["Project ready<br/>Module indexes generated lazily<br/>on first access"]

    style L1 fill:#e8f5e9
    style L2 fill:#e8f5e9
    style ROOT fill:#fff3e0
    style DONE fill:#e1f5fe
```

**Cost of `teambuild init`:** Near zero. L1 and L2 are free. The root `.index.md` generation is one AI call (~1K tokens total). Module-level indexes are generated lazily — only when an agent first works in that module or when explicitly requested via `teambuild index <module>`.

### 4.5 Agent File-Finding Flow

When an agent needs to find relevant code (whether using TeamBuild's managed executor or working independently), the navigation path is:

```
1. Read root .index.md              → identifies 2-3 relevant modules
2. Read module .index.md(s)         → identifies specific files + exports
3. Check import graph (from L2)     → finds related files via dependencies
4. Check git history (from L1)      → finds recently-changed files in scope
5. Read 2-3 targeted files          → only what's needed for the task
```

On a 500-file project, the agent reads the root index, 2-3 module indexes, and 2-3 actual files. Not 500 files. Not 25 indexes. The index system turns O(n) exploration into O(1) routing.

---

## 5. Foundation Layer


### 5.1 Provider Abstraction

**Validated by:** Pydantic AI POC (`research/early-research/examples/pydantic-ai-poc/`)

The POC confirmed that Pydantic AI's generic typing pattern works across Anthropic, OpenAI, Bedrock, and Ollama with zero code changes in the application layer.

#### Interface

```python
from abc import ABC, abstractmethod
from typing import Generic, TypeVar
from pydantic import BaseModel

OutputT = TypeVar("OutputT", bound=BaseModel)
DepsT = TypeVar("DepsT")

class TokenUsage(BaseModel):
    input_tokens: int
    output_tokens: int
    total_tokens: int
    cost_usd: float | None = None

class AgentResult(BaseModel, Generic[OutputT]):
    output: OutputT
    usage: TokenUsage
    model: str
    provider: str
    duration_ms: int

class AgentProvider(ABC, Generic[OutputT, DepsT]):
    @abstractmethod
    async def invoke(
        self,
        prompt: str,
        dependencies: DepsT | None = None,
        system_prompt: str | None = None,
        **kwargs,
    ) -> AgentResult[OutputT]:
        ...
```

#### Configuration

```python
from pydantic_settings import BaseSettings

class ProviderConfig(BaseSettings):
    provider: Literal["anthropic", "openai", "bedrock", "ollama"] = "anthropic"
    model: str = "claude-sonnet-4-5-20250929"
    fallback_provider: str | None = None
    fallback_model: str | None = None
    max_tokens: int = 4096
    timeout_seconds: int = 120
    max_retries: int = 3

class ModelRoster(BaseSettings):
    """Per-role model assignment — swap models without changing agent code."""
    interview: ProviderConfig = ProviderConfig(model="claude-sonnet-4-5-20250929")
    coding: ProviderConfig = ProviderConfig(model="claude-sonnet-4-5-20250929")
    review: ProviderConfig = ProviderConfig(model="claude-opus-4-6")
    planning: ProviderConfig = ProviderConfig(model="claude-opus-4-6")
    search: ProviderConfig = ProviderConfig(model="claude-haiku-4-5-20251001")
```

#### Key Design Decisions
- **Pydantic AI as the orchestration framework** — validated by POC
- **Generic typing** for type-safe outputs across all providers
- **Configuration-based model selection** per agent role
- **Feature flags** for safe provider migration and A/B testing
- **Mock providers** for testing without API keys

---

### 5.2 Context Window Manager

**Source:** requirements.md Context Window Management, research/hooks/precompact.md, PIV-Swarm workflow

#### Architecture

```mermaid
flowchart TD
    AGENT[Agent Request] --> BUDGET[Context Budget Check]
    BUDGET -->|within budget| INDEX[Read Atomic Index]
    BUDGET -->|over budget| WARN[Degradation Warning]
    WARN --> COMPACT[Checkpoint & Compact]
    COMPACT --> INDEX

    INDEX --> DECIDE{Need more detail?}
    DECIDE -->|yes| DRILL["Progressive Disclosure<br/>index → signatures → implementation"]
    DECIDE -->|no| WORK[Execute Task]
    DRILL --> BUDGET

    WORK --> UPDATE[Update Index if stale]
    UPDATE --> METRICS[Report Context Usage]

    subgraph "Shared Knowledge Layer"
        IDX[("Module Indexes<br/>.index.md per directory")]
        CACHE[("Summary Cache<br/>function signatures, types")]
    end

    INDEX --> IDX
    UPDATE --> IDX
    DRILL --> CACHE
```

#### Hierarchical Index Navigation

The index system is **hierarchical, not flat**. A project with 25+ directories can't load all indexes — the agent needs a routing table to find the right 2-3 modules without scanning everything.

```mermaid
flowchart TD
    ROOT[".index.md (root)<br/>Module routing table"] --> AUTH["auth/.index.md"]
    ROOT --> DB["database/.index.md"]
    ROOT --> API["api/.index.md"]
    ROOT --> BILLING["billing/.index.md"]
    ROOT --> N["...20 more modules"]

    AUTH --> AP["auth/provider.py"]
    AUTH --> AS["auth/session.py"]
    AUTH --> AM["auth/middleware.py"]

    style ROOT fill:#e1f5fe
    style AUTH fill:#fff3e0
    style DB fill:#f5f5f5
    style API fill:#f5f5f5
    style BILLING fill:#f5f5f5
    style N fill:#f5f5f5
```

**Root index** — loaded first, always. Maps modules to responsibilities with cross-references:

```markdown
# Project Index

## Modules
| Module | Purpose | Touches |
|--------|---------|---------|
| auth/ | OAuth2, token refresh, session management | database/, config/ |
| database/ | User storage, migrations, repository pattern | — |
| api/ | FastAPI routes, request handling | auth/, database/, billing/ |
| billing/ | Stripe integration, subscription management | database/, auth/ |
| ...

## Common Patterns
- Authentication: start at auth/.index.md
- Data access: start at database/.index.md
- Adding a new endpoint: start at api/.index.md, then the relevant domain module
```

**Module index** — loaded only when the agent routes into that module:

```markdown
# auth/ — Authentication Module

## Purpose
Handles user authentication via OAuth2 with automatic token refresh.

## Exports
- `authenticate(credentials) -> Session`
- `refresh_token(session) -> Session`
- `validate_session(token) -> User | None`

## Files (5)
- `provider.py` — OAuth2 provider abstraction (142 lines)
- `session.py` — Session management and token refresh (98 lines)
- `middleware.py` — FastAPI auth middleware (67 lines)
- `models.py` — User, Session, Token models (54 lines)
- `config.py` — Auth configuration (23 lines)

## Related Modules
- **database/** — user storage (see database/.index.md § UserRepository)
- **config/** — auth configuration keys
- **api/routes/auth.py** — HTTP endpoints that use this module

## Last Updated
2026-02-09 by coding-agent-1 (ticket AUTH-003)
```

**Navigation flow:**
1. Agent reads root `.index.md` (always cached — small, high value)
2. Uses ticket scope markers to route into 2-3 relevant module indexes
3. Module indexes have cross-references ("Related Modules") to find adjacent code without scanning the whole project
4. Only drills into actual files when the index + signatures aren't enough
5. Agents update indexes when they modify files (keeps navigation fresh)

This means an agent working on a login bug reads: root index → auth/.index.md → auth/session.py. Not 25 index files and certainly not the full codebase.

#### Context Budget Tracking

> **Research needed before implementation:** Claude Code's `/context` command already tracks token spending per session. Pydantic AI also exposes usage data on every call. Before building custom tracking, research what's already available and wrap it rather than reinventing it. The goal is the best possible dev metrics, not duplicated effort.

Context budget tracking uses the `AgentBudget` model defined in section 2.3 (Agent Workflow Contract). The key insight: budget against the **smart window** (~120K tokens), not the raw context limit (~200K). Reserve 30K for housekeeping. Never compact — always hand off to a fresh agent.

See section 2.3 for the full `AgentBudget` model and threshold behavior.

#### Fresh Context Per Task

From PIV-Swarm research: each task runs in a fresh context (`context: fork`). No accumulated cruft from previous tasks.

```mermaid
flowchart LR
    T1["Task 1<br/>Fresh Context"] --> R1[Result 1]
    T2["Task 2<br/>Fresh Context"] --> R2[Result 2]
    T3["Task 3<br/>Fresh Context"] --> R3[Result 3]

    R1 --> LEAD[Lead Agent<br/>Synthesizes Results]
    R2 --> LEAD
    R3 --> LEAD

    KL[("Shared Knowledge Layer")] -.->|provides context| T1
    KL -.-> T2
    KL -.-> T3
    R1 -.->|updates indexes| KL
    R2 -.-> KL
    R3 -.-> KL
```

---

### 5.3 Metrics Collection (Lightweight Library)

Built early as a thin library that all modules import. The full metrics module (storage, reporting, dashboards) is built later as the dogfooding test.

```python
from contextlib import asynccontextmanager

class MetricsCollector:
    """Lightweight collector — imported by all modules."""

    async def track_invocation(
        self,
        agent_name: str,
        result: AgentResult,
        ticket_id: str | None = None,
    ) -> None:
        """Record a single agent invocation."""
        ...

    @asynccontextmanager
    async def track_operation(self, operation: str, ticket_id: str | None = None):
        """Context manager for timing operations."""
        start = time.monotonic()
        yield
        duration = time.monotonic() - start
        await self._record(operation, duration, ticket_id)
```

#### Collection Points

```mermaid
graph TD
    subgraph "Metrics Collection Points"
        M1["1. Agent invocation<br/>tokens, cost, duration, model"]
        M2["2. Context budget<br/>used vs remaining, health status"]
        M3["3. Circuit breaker<br/>attempt count, escalations"]
        M4["4. Ticket lifecycle<br/>time per status, total cost"]
        M5["5. Review outcomes<br/>issues found, severity, false positive rate"]
        M6["6. Provider comparison<br/>same task, different models"]
    end

    PA[Provider Abstraction] -->|every call| M1
    CWM[Context Manager] -->|every budget check| M2
    CR[Critique/Review] -->|every review cycle| M3
    PM[PM Integration] -->|every status change| M4
    CR -->|every review| M5
    PA -->|when A/B testing| M6
```

---

## 6. Interview Agent

**Build order:** #4 (after Provider Abstraction + Metrics foundation)
**Depends on:** Provider Abstraction, Metrics Collection (lightweight)
**Full spec:** requirements.md section 1, interview-agent-synthesis.md

### Internal Architecture

```mermaid
flowchart TD
    INPUT["User Input<br/>brain dump / topic / existing spec"] --> MODE{Detect Mode}

    MODE -->|stakeholder available| DIRECT[Mode 1: Direct Interview]
    MODE -->|existing spec provided| GAP[Mode 2: Gap Analysis]

    subgraph "Direct Interview"
        DIRECT --> INFER[Infer Role & Goal]
        INFER --> CONFIRM[Confirm with User]
        CONFIRM --> LOOP[Interview Loop]
        LOOP --> NOTES["Internal Note-Taking<br/>+ completeness tracking"]
        NOTES --> QGEN["Dynamic Question Generation<br/>3-5 candidates, pick best"]
        QGEN -->|completeness < 9| LOOP
        QGEN -->|completeness >= 9| OUTPUT
    end

    subgraph "Gap Analysis"
        GAP --> ANALYZE[Analyze Spec vs Domain Patterns]
        ANALYZE --> GAPS[Identify Gaps]
        GAPS --> STORY_Q["Generate Story-Based Questions<br/>per gap"]
        STORY_Q --> DECIDE{Stakeholder available?}
        DECIDE -->|yes| LOOP2[Interview to Fill Gaps]
        DECIDE -->|no| QLIST[Produce Question List]
        LOOP2 --> OUTPUT
        QLIST --> OUTPUT
    end

    OUTPUT["Structured Output<br/>requirements.md / gap report"]
    OUTPUT --> DOMAIN[Update Domain Libraries<br/>with new patterns]
    OUTPUT --> METRICS[Report Metrics<br/>questions asked, duration, tokens]
```

### Key Components

| Component | Purpose |
|-----------|---------|
| `InterviewOrchestrator` | Manages session lifecycle, mode detection, state |
| `QuestionGenerator` | Generates 3-5 candidate questions, selects best based on completeness gaps |
| `CompletenessTracker` | Tracks 1-10 score with sub-dimensions (inputs, outputs, scope, constraints, edge cases, success criteria) |
| `NoteKeeper` | Internal notes, profile building, insight tracking — not shown to user |
| `OutputFormatter` | Produces structured deliverables per domain type |
| `DomainLibrary` | Reusable question patterns per domain — grows after each interview |

### Interface

```python
class InterviewAgent:
    """Main entry point for the Interview Agent module."""

    async def start_interview(
        self,
        initial_input: str,
        mode: Literal["direct", "gap_analysis", "auto"] = "auto",
        domain: str = "software-requirements",
    ) -> InterviewSession:
        """Start a new interview session."""
        ...

    async def process_response(
        self,
        session: InterviewSession,
        user_response: str,
    ) -> InterviewTurn:
        """Process a user response and generate the next question."""
        ...

    async def conclude(
        self,
        session: InterviewSession,
    ) -> InterviewOutput:
        """Conclude the interview and produce structured output."""
        ...

class InterviewTurn(BaseModel):
    question: str
    internal_notes: InternalNotes  # Not shown to user
    completeness: float            # 1-10
    turn_number: int

class InternalNotes(BaseModel):
    current_understanding: str
    key_insights: list[str]
    technical_constraints: list[str]
    user_profile: StakeholderProfile
    unanswered_questions: list[str]
    candidate_questions: list[CandidateQuestion]
    selected_rationale: str

class InterviewOutput(BaseModel):
    deliverable: str               # Markdown document
    domain: str
    completeness_score: float
    questions_asked: int
    key_insights: list[str]
    profile: StakeholderProfile
    metrics: InterviewMetrics
```

### Core Mechanics

These are non-negotiable for both modes (from interview-agent-synthesis.md):

1. **ONE question at a time** — never multi-part questions
2. **Story-based questioning** — "Tell me about the last time..." not "What do you usually..."
3. **Dynamic question generation** — 3-5 candidates per turn, pick best
4. **Internal completeness tracking** — 1-10 score drives when to stop
5. **Explorer mindset** — follow valuable tangents
6. **Profile building** — adapt to user's working style, values, pain points
7. **Domain libraries that grow** — update patterns after each interview
8. **Structured output always** — concrete deliverable, not just notes

### Context Management

Low risk — conversations are naturally scoped. **Key requirement:** output documents must use progressive disclosure (high-level overview → detailed specs per component) so downstream agents can read only what they need.

---

## 7. PM Integration

**Build order:** #5
**Depends on:** Provider Abstraction, Metrics Collection

### Data Flow

```mermaid
sequenceDiagram
    participant IA as Interview Agent
    participant PM as PM Integration
    participant PLANE as Plane API
    participant CA as Coding Agent
    participant CR as Critique/Review
    participant MET as Metrics

    IA->>PM: Submit requirements doc
    PM->>PM: Parse into project + features + tickets
    PM->>PLANE: Create project
    PM->>PLANE: Create tickets with scope markers

    CA->>PM: Request next ticket
    PM->>PLANE: Query unassigned tickets
    PM-->>CA: Return ticket with scope markers
    CA->>PM: Update status: in_progress
    PM->>PLANE: Update ticket status

    CA->>CR: Submit for review
    CR->>PM: Update status: in_review
    CR-->>CA: Review result

    alt Review Passes
        CA->>PM: Update status: done
        CA->>PM: Attach metrics
        PM->>PLANE: Update ticket + metrics
    else Review Fails, attempt < max
        CR->>CA: Return issues + agentPrompts
        CA->>PM: Update status: in_progress (retry)
    else Circuit Breaker Triggered
        CR->>PM: Update status: blocked
        CR->>PM: Attach escalation report
        PM->>PLANE: Update ticket + notify human
    end

    MET->>PM: Aggregate metrics per ticket/project
```

### Adapter Pattern

```python
class PMAdapter(ABC):
    """Abstract interface for PM tool integration."""

    @abstractmethod
    async def create_project(self, project: ProjectSpec) -> ProjectRef: ...

    @abstractmethod
    async def create_ticket(self, ticket: TicketSpec) -> TicketRef: ...

    @abstractmethod
    async def get_next_ticket(self, filters: TicketFilter) -> Ticket | None: ...

    @abstractmethod
    async def update_status(self, ticket_id: str, status: TicketStatus) -> None: ...

    @abstractmethod
    async def attach_metrics(self, ticket_id: str, metrics: TicketMetrics) -> None: ...

    @abstractmethod
    async def add_comment(self, ticket_id: str, comment: str) -> None: ...

class PlaneAdapter(PMAdapter):
    """Plane API implementation (v1 target — self-hosted, personal)."""
    ...

class LinearAdapter(PMAdapter):
    """Linear API implementation (work environment)."""
    ...
```

### Ticket Schema with Scope Markers

Scope markers are the primary mechanism that drives context loading for coding agents:

```python
class TicketSpec(BaseModel):
    title: str
    description: str
    acceptance_criteria: list[str]

    # Scope markers — drives context loading for coding agents
    relevant_modules: list[str]       # e.g., ["auth/", "database/"]
    relevant_files: list[str]         # e.g., ["auth/provider.py"]
    dependencies: list[str]           # Other ticket IDs

    # Estimation
    estimated_tokens: int
    complexity: Literal["S", "M", "L", "XL"]  # S <5K, M <20K, L <50K, XL split it

    # Assignment
    assigned_role: str | None = None  # e.g., "backend-dev"
    assigned_agent: str | None = None

    # Stale comment resolution (from code-review research)
    previous_review_issues: list[str] | None = None
```

### Stale Issue Resolution

From the code reviewer research: when a coding agent fixes issues and resubmits, previous review comments that no longer apply should be auto-resolved in the PM tool. This keeps ticket threads clean.

---

## 8. Validation Runner (`teambuild check`)

**Build order:** #5 (after Interview Agent and PM Integration)
**Depends on:** Metrics Collection (for tracking pass/fail rates)

The Validation Runner is a **standalone CLI tool** — it works regardless of what wrote the code. Human, Claude Code, Cursor, Aider — doesn't matter. It runs the same gates on the output.

### Validation Categories

The categories are **language-agnostic** — the specific tools are resolved per-language at runtime:

| Category | Python | TypeScript | Rust | Generic |
|----------|--------|-----------|------|---------|
| **Tests** | pytest | jest/vitest | cargo test | Language test runner |
| **Linting** | ruff check | eslint | clippy | Language linter |
| **Type checking** | mypy | tsc --noEmit | cargo check | Language type checker |
| **Formatting** | ruff format | prettier | rustfmt | Language formatter |
| **Security** | bandit | npm audit | cargo audit | Language security scanner |
| **App starts** | python -m app | npm start | cargo run | Language entry point |

The runner detects the project language from config files (`pyproject.toml`, `package.json`, `Cargo.toml`) and resolves the appropriate tool chain. Custom commands can be configured in `[tool.teambuild]`.

### CLI Usage

```
teambuild check              Run all gates
teambuild check --gate=test  Run only tests
teambuild check --gate=lint  Run only linting
teambuild check --diff=HEAD  Only check changed files (faster)
teambuild check --spec=TICKET-42  Validate against ticket acceptance criteria
```

### Integration Points

`teambuild check` can be wired into any workflow:
- **Git hooks** — `pre-commit` or `pre-push` (works regardless of agent runtime)
- **CI/CD** — runs in any pipeline as a standard CLI command
- **Managed executor** — called automatically after code is written
- **Manual** — developer runs it whenever they want

---

## 9. Managed Executor (`teambuild code`) — Optional

**Build order:** #8 (last — requires everything else to exist first)
**Depends on:** PM Integration, Validation Runner, Critique/Review, Metrics, Index Manager

**This module is explicitly optional.** The core TeamBuild workflow works without it. It exists for teams (like MetrIQ) that want consistent, monitored coding across all developers — everyone uses the same rules, the same validation, the same metrics collection.

### What It Is

A thin wrapper around an external coding agent. It doesn't reimplement the agent — it:
1. **Injects rules** — TDD, context budget, quality gates
2. **Feeds context** — relevant indexes, ticket spec, acceptance criteria
3. **Monitors** — token usage, time, cost in real-time
4. **Validates automatically** — runs `teambuild check` when the agent says it's done
5. **Reports** — cost, pass/fail, metrics back to PM

### Executor Interface

```python
class CodingExecutor(ABC):
    """Wraps an external coding agent with TeamBuild's workflow."""

    @abstractmethod
    async def setup_environment(self, ticket: Ticket) -> ExecutionContext:
        """Prepare workspace — worktree, indexes, rules injection."""
        ...

    @abstractmethod
    async def execute(self, context: ExecutionContext) -> ExecutionResult:
        """Hand off to the underlying agent and monitor."""
        ...

    @abstractmethod
    async def teardown(self, context: ExecutionContext) -> None:
        """Clean up workspace."""
        ...

class ClaudeCodeExecutor(CodingExecutor):
    """Wraps Claude Code with TeamBuild rules + monitoring."""
    ...

class ManualExecutor(CodingExecutor):
    """'Go do it yourself' — sets up the workspace and waits for teambuild check."""
    ...
```

### Managed Execution Flow

```mermaid
sequenceDiagram
    participant DEV as Developer
    participant TB as teambuild code
    participant PM as PM Integration
    participant ENV as Environment Setup
    participant AGENT as Coding Agent (e.g. Claude Code)
    participant VAL as teambuild check
    participant CR as teambuild review
    participant MET as Metrics

    DEV->>TB: teambuild code TICKET-42
    TB->>PM: Fetch ticket spec + acceptance criteria
    PM-->>TB: Ticket with scope markers

    TB->>ENV: Set up workspace
    Note over ENV: Create worktree (if multi-agent)<br/>Load relevant .index.md files<br/>Inject rules (TDD, quality gates)
    ENV-->>TB: ExecutionContext ready

    TB->>AGENT: Launch with context + rules
    Note over AGENT: Agent writes code<br/>TeamBuild monitors token usage

    AGENT-->>TB: Agent signals completion
    TB->>VAL: teambuild check --spec=TICKET-42
    VAL-->>TB: Validation result

    alt Validation passes
        TB->>CR: teambuild review (changed files)
        CR-->>TB: Review result
        alt Review passes
            TB->>PM: Update ticket: done + metrics
            TB->>MET: Record full session metrics
            TB-->>DEV: Done — PR ready
        else Review fails, retries left
            TB->>AGENT: Feed fix prompts back
            Note over AGENT: Agent fixes issues
        end
    else Validation fails, retries left
        TB->>AGENT: Feed failure output back
        Note over AGENT: Agent fixes issues
    else Circuit breaker triggered
        TB->>PM: Update ticket: blocked + escalation report
        TB-->>DEV: Escalated — needs human attention
    end
```

### Coordination Model (Multi-Agent)

When the managed executor runs multiple agents in parallel (for large tickets or multiple tickets):

3-tier delegation model (from Opus research):

| Tier | When | Cost | Coordination |
|------|------|------|-------------|
| **Solo** | Small scope, single file, sequential work | 1x | Executor runs one agent |
| **Subagent** | Independent, parallelizable, fire-and-forget | ~2x | Executor spawns parallel agents |
| **Team** | Inter-agent communication needed, 3+ workstreams | ~5x | Shared task list, direct messaging |

#### File Conflict Isolation

When running multiple agents, **git worktrees** provide isolated working directories:

```
repo/                          # Main worktree (lead agent)
repo-worktrees/
├── agent-1/                   # git worktree for agent 1
├── agent-2/                   # git worktree for agent 2
└── agent-3/                   # git worktree for agent 3
```

Each worktree is a separate checkout — agents can edit any file without conflicting. Changes merge through PRs, the same as human developers.

> **Research needed before implementation:** Deep dive into how Claude's agent teams currently handle multi-agent file coordination. Git worktrees are one approach; there may be better patterns emerging. We should understand the state of the art before committing to an isolation strategy.

### Why This Is Built Last

The managed executor is a convenience layer on top of the core workflow. Building it last means:
1. **Validation is proven** — `teambuild check` works reliably before wrapping it in automation
2. **Review is proven** — `teambuild review` produces useful fix prompts before feeding them back automatically
3. **Metrics are proven** — cost/quality tracking is accurate before monitoring automated sessions
4. **Dogfooding** — building modules 1-7 manually (using Claude Code directly, running `teambuild check` by hand) reveals exactly where the handoff document is too vague, where validation misses things, where metrics are incomplete. That feedback is worth more than any upfront design
5. **The wrapper is thin** — by the time you build it, it's mostly glue code connecting existing modules

---

## 10. Critique/Review Layer

**Build order:** #7
**Depends on:** Provider Abstraction, PM Integration, Validation Runner
**Informed by:** `research/code-review/ai-reviewer.mjs`, `research/hooks/`, `current_ai/` code-review skill

### Two-Pass Review Architecture

```mermaid
flowchart TD
    INPUT[Code Submission] --> PASS1["Pass 1: Automated Checks<br/>(hooks — fast, synchronous)"]

    subgraph "Pass 1: Hooks Layer"
        PASS1 --> LINT[ruff check]
        PASS1 --> TYPE[mypy]
        PASS1 --> TEST[pytest]
        PASS1 --> SEC[bandit]

        LINT --> GATE1{All pass?}
        TYPE --> GATE1
        TEST --> GATE1
        SEC --> GATE1
    end

    GATE1 -->|fail| AUTOFIX["Auto-fix Loop<br/>post-failure hooks inject<br/>targeted fix instructions"]
    AUTOFIX -->|retry| INPUT

    GATE1 -->|pass| PASS2["Pass 2: AI Deep Review<br/>(agent — thorough, context-aware)"]

    subgraph "Pass 2: AI Review"
        PASS2 --> BUG["Bug Detection<br/>CONFIRMED bugs only<br/>mandatory 5-point self-check"]
        PASS2 --> SPEC["Spec Compliance<br/>output vs acceptance criteria"]
        PASS2 --> PERF["Performance<br/>N+1 queries, unnecessary work"]
        PASS2 --> QUAL["Code Quality<br/>DRY, complexity, standards"]

        BUG --> GATE2{Issues found?}
        SPEC --> GATE2
        PERF --> GATE2
        QUAL --> GATE2
    end

    GATE2 -->|clean| APPROVE["Approve"]
    GATE2 -->|issues| ISSUES[Generate Issue Reports]

    ISSUES --> AGENT_PROMPT["Generate agentPrompt per issue<br/>AI-to-AI handoff prompt"]
    AGENT_PROMPT --> CB{Circuit Breaker<br/>attempt <= max?}

    CB -->|yes| RETURN["Return to Coding Agent<br/>with fix prompts"]
    CB -->|no| ESCALATE["Escalate to Human<br/>notification + PM ticket"]
```

### Key Concept: agentPrompt (from code-review research)

Every review issue includes an `agentPrompt` — a detailed prompt a coding agent can pick up directly to verify and fix the issue. This turns review into a pipeline, not a handoff.

```python
class ReviewIssue(BaseModel):
    path: str                                      # Exact file path
    line: int                                      # Line number
    severity: Literal["HIGH", "MEDIUM", "LOW"]
    bug: str                                       # Human-readable, quotes problematic code
    suggested_fix: str                             # Concrete fix description
    agent_prompt: str                              # AI-to-AI handoff — detailed enough for
                                                   # a coding agent to locate, verify, and fix
                                                   # independently
```

### False Positive Prevention

From the code reviewer's prompt engineering — mandatory self-check before reporting any issue:

1. Can I name a **SPECIFIC input** that triggers a runtime failure? (If no → SKIP)
2. Does the code **already handle** this? Look for try/catch, null checks, validation. (If yes → SKIP)
3. Have I read the **FULL function body**, not just the signature? (If no → read it first)
4. Is this a **style preference** or design opinion? (If yes → SKIP)
5. Am I using **speculative language** ("may", "might", "could")? (If yes → SKIP)

**Zero issues = ideal outcome.** The review agent must never invent issues to appear thorough.

### Circuit Breaker

```python
class CircuitBreaker:
    """Prevents infinite retry loops. Configurable per project (3-5 attempts)."""

    def __init__(self, max_attempts: int = 3):
        self.max_attempts = max_attempts
        self.attempts: dict[str, list[AttemptRecord]] = {}

    async def record_attempt(self, ticket_id: str, record: AttemptRecord) -> None:
        self.attempts.setdefault(ticket_id, []).append(record)

    async def should_escalate(self, ticket_id: str) -> bool:
        return len(self.attempts.get(ticket_id, [])) >= self.max_attempts

    async def generate_escalation(self, ticket_id: str) -> EscalationReport:
        history = self.attempts[ticket_id]
        return EscalationReport(
            ticket_id=ticket_id,
            attempts=len(history),
            what_was_tried=[a.approach for a in history],
            what_failed=[a.failure_reason for a in history],
            where_stuck=history[-1].current_state,
            suggested_next_steps=self._suggest(history),
        )
```

### Review Types

| Type | When | Scope | Priority Source |
|------|------|-------|--------|
| Plan Critique | Before building starts | Spec/plan docs | Opus critique skill |
| Code Review | After implementation | Changed files + direct deps | code-review research + current_ai |
| Bug Detection | During code review | Diff-focused, confirmed only | ai-reviewer.mjs |
| Security Review | During code review | OWASP top 10, dependencies | current_ai security-checklist |
| Test Validation | After tests written | Coverage, quality, edge cases | current_ai validate skill |
| Spec Compliance | After implementation | Output vs acceptance criteria | requirements.md |

### Hooks as the Lightweight Critique Layer

From hooks research: build the first critique pass as hooks, not separate agents. Hooks are fast (milliseconds), synchronous, and zero-cost in tokens:

| Hook | Event | Action |
|------|-------|--------|
| pre-commit-lint | PreToolUse (git commit) | Block if ruff fails |
| post-edit-format | PostToolUse (Edit/Write .py) | Auto-format with ruff |
| post-failure-autofix | PostToolUseFailure (Bash) | Inject targeted fix instructions for pytest/ruff/mypy |
| phase-gate | PreToolUse (phase transition) | Block if validation incomplete |

Escalate to full AI review agent only for Pass 2 (deep review).

---

## 11. Cost/Performance Metrics (Full Module)

**Build order:** #8 (built BY items 1-7 as the dogfooding test)
**Depends on:** All other modules as collection targets

### What Gets Tracked

```mermaid
mindmap
  root((Metrics))
    Agent Performance
      Tokens per invocation
      Cost per invocation
      Duration per invocation
      Model used
      Provider used
    Ticket Lifecycle
      Time per status
      Total cost per ticket
      Estimated vs actual tokens
      Retry count
      Circuit breaker triggers
    Context Health
      Tokens used vs budget
      Smart vs dumb window ratio
      Priming cost vs working cost
      Context compaction events
    Quality
      Review pass rate per agent
      Issues found per review
      False positive rate
      Test coverage
      Lint and type check pass rate
    System
      Provider uptime
      Throttling events
      Fallback activations
      Model comparison data
```

### Storage

For v0.1: **local structured storage** with PM export for visibility.

```python
class MetricsStore(ABC):
    @abstractmethod
    async def record(self, metric: Metric) -> None: ...

    @abstractmethod
    async def query(self, filters: MetricFilter) -> list[Metric]: ...

    @abstractmethod
    async def aggregate(self, group_by: list[str]) -> list[AggregatedMetric]: ...

class LocalJSONLStore(MetricsStore):
    """JSONL file storage — simple, human-readable, git-friendly."""
    ...

class SQLiteStore(MetricsStore):
    """SQLite — row-oriented, good for transactional queries."""
    ...

class DuckDBStore(MetricsStore):
    """DuckDB — columnar, designed for analytics/aggregation queries."""
    ...
```

**Decision:** Start with JSONL for simplicity. All stores implement the same ABC so switching is seamless. For the analytics-heavy metrics workload (aggregations, comparisons, time-series queries), DuckDB may be a better fit than SQLite.

> **Research needed before implementation:** Compare DuckDB vs SQLite for our specific metrics workload — DuckDB is columnar and optimized for analytical queries (aggregations, GROUP BY, time-series), while SQLite is row-oriented and better for transactional access. Since metrics are write-once-read-many with heavy aggregation, DuckDB may be the right default. Research before committing.

---

## 12. Resolved Design Decisions

These open questions from HANDOFF.md are now resolved:

| Question | Decision | Rationale |
|----------|----------|-----------|
| **TeamBuild identity** | **Workflow framework, not agent runtime** | TeamBuild owns planning, validation, review, metrics. Code execution is a pluggable slot filled by any agent. Survives agent runtime churn. |
| **Integration model** | **CLI + git-native files, no agent runtime dependency** | `.index.md` files are universal markdown. `teambuild` CLI commands work standalone. No `.claude/` management, no `.teambuild/` directory. Optional thin generators for agent-specific config. |
| **Project config** | **`[tool.teambuild]` in `pyproject.toml`** | Standard Python convention. No separate config file. `teambuild.toml` for non-Python projects. |
| **Project understanding** | **Three-layer: static analysis + AST + lazy AI** | 80% of understanding is free (L1+L2). AI summarization (L3) is lazy, one call per module, cached in `.index.md`. |
| PM abstraction pattern | **Adapter pattern** | PlaneAdapter and LinearAdapter implement PMAdapter ABC. |
| Agent coordination | **PM-driven + git worktrees** | PM tool is single source of truth. Git worktrees for file isolation between agents (in managed executor). |
| Metrics storage | **JSONL → DuckDB/SQLite, with PM export** | JSONL for simplicity. DuckDB for analytics-heavy aggregation. Same ABC for all. |
| Module interfaces | **Python packages + Pydantic models** | Each module is a Python package with a clear public API. All inputs/outputs are Pydantic models. |
| Atomic index implementation | **Hierarchical `.index.md`** | Root index routes to module indexes. Cross-references between related modules. |
| Context budgeting | **Token counting + percentage thresholds** | Smart window ~120K, housekeeping 30K, hard ceiling 150K. Research existing tracking before building custom. |
| Package structure | **Monorepo + import-linter** | Single pyproject.toml. Layered architecture enforced by import-linter in CI. |
| Self-validation | **Language-agnostic categories** | Test/lint/type/format/security resolved per-language at runtime. Standalone CLI (`teambuild check`). |
| Managed executor | **Optional wrapper, built last** | `teambuild code` wraps any coding agent with rules + monitoring + automatic validation. Not core — built after everything else is proven. |

---

## 12.1 Research Backlog

Items that need investigation before or during implementation:

| Topic | Needed For | Priority |
|-------|-----------|----------|
| **Pydantic AI built-in usage tracking** | Metrics collection — don't reinvent what's already there | High (before Provider Abstraction) |
| **tree-sitter Python bindings** | Three-layer project understanding — L2 AST parsing | High (before `teambuild init`) |
| **Plane API** | PM Integration — PlaneAdapter implementation | High (before PM module) |
| **DuckDB vs SQLite** | Metrics storage — columnar vs row-oriented for analytics workload | Medium (before full Metrics module) |
| **Beads framework** | PM Integration — project/token management patterns | Medium (before PM module) |
| **Linear API** | PM Integration — LinearAdapter implementation | Medium (future) |
| **Claude agent team coordination** | Managed Executor — how do agent swarms handle file conflicts? | Low (before Managed Executor) |
| **Git worktrees for agent isolation** | Managed Executor — validate worktree approach for multi-agent dev | Low (before Managed Executor) |

---

## 13. Package Structure

### Architecture: Monorepo with Enforced Layer Boundaries

Single `pyproject.toml`, single install — but with **enforced import boundaries** via `import-linter` so coupling can't creep in. Unit tests live with their modules (grab a module, its tests come with it). Integration and E2E tests live at the top level.

**Layered architecture:**
- **Layer 0** (foundation) — no internal dependencies, any module can import these
- **Layer 1** (workflow) — may import Layer 0 only
- **Layer 2** (coordination) — may import Layer 0 and Layer 1

```mermaid
graph BT
    subgraph "Layer 0 — Foundation"
        PROV[providers/]
        MET[metrics/]
        CTX[context/]
        VAL[validation/]
    end

    subgraph "Layer 1 — Workflow"
        INT[interview/]
        PM_M[pm/]
        REV[review/]
    end

    subgraph "Layer 2 — Coordination (optional)"
        EX[executor/]
    end

    subgraph "CLI (top-level entry point)"
        CLI_M[cli/]
    end

    INT --> PROV
    INT --> MET
    PM_M --> PROV
    PM_M --> MET
    REV --> PROV
    REV --> MET
    REV --> VAL
    REV --> PM_M
    EX --> PM_M
    EX --> VAL
    EX --> REV
    EX --> MET
    CLI_M --> INT
    CLI_M --> PM_M
    CLI_M --> REV
    CLI_M --> VAL
    CLI_M --> MET
    CLI_M --> CTX
    CLI_M -.-> EX

    style PROV fill:#e1f5fe
    style MET fill:#e1f5fe
    style CTX fill:#e1f5fe
    style VAL fill:#e1f5fe
    style INT fill:#fff3e0
    style PM_M fill:#fff3e0
    style REV fill:#fff3e0
    style EX fill:#f0f0f0,stroke-dasharray: 5 5
    style CLI_M fill:#e8f5e9
```

**Key rules:**
- Layer 0 modules NEVER import from each other
- Layer 1 modules NEVER import from each other (except review → pm for ticket status updates)
- The executor is optional — dashed border means the system works without it
- The CLI is the only module that imports across layers (it's the entry point, not a library)

```
teambuild/
├── src/
│   └── teambuild/
│       ├── __init__.py
│       │
│       ├── cli/                    # CLI entry point — teambuild commands
│       │   ├── __init__.py
│       │   ├── main.py             # CLI dispatcher (click or typer)
│       │   ├── init_cmd.py         # teambuild init — project analysis + index gen
│       │   ├── check_cmd.py        # teambuild check — validation runner
│       │   ├── review_cmd.py       # teambuild review — AI code review
│       │   ├── interview_cmd.py    # teambuild interview — interactive interview
│       │   ├── metrics_cmd.py      # teambuild metrics — dashboard + export
│       │   ├── setup_cmd.py        # teambuild setup <runtime> — optional config gen
│       │   └── code_cmd.py         # teambuild code <ticket> — managed executor
│       │
│       ├── providers/              # LAYER 0: Provider Abstraction
│       │   ├── __init__.py         # Public API only
│       │   ├── base.py             # AgentProvider ABC, AgentResult, TokenUsage
│       │   ├── pydantic_ai.py      # Pydantic AI implementation
│       │   ├── config.py           # ProviderConfig, ModelRoster
│       │   ├── mock.py             # MockProvider for testing
│       │   └── tests/
│       │       ├── __init__.py
│       │       ├── test_base.py
│       │       ├── test_pydantic_ai.py
│       │       └── test_mock.py
│       │
│       ├── context/                # LAYER 0: Context & Index Manager
│       │   ├── __init__.py
│       │   ├── budget.py           # ContextBudget tracking
│       │   ├── index.py            # Hierarchical .index.md read/write/update
│       │   ├── analyzer.py         # Layer 1+2: static analysis + tree-sitter AST
│       │   ├── summarizer.py       # Layer 3: AI-powered module summarization
│       │   └── tests/
│       │       ├── __init__.py
│       │       ├── test_budget.py
│       │       ├── test_index.py
│       │       └── test_analyzer.py
│       │
│       ├── metrics/                # LAYER 0: Metrics
│       │   ├── __init__.py
│       │   ├── collector.py        # Lightweight MetricsCollector
│       │   ├── store.py            # MetricsStore ABC + implementations
│       │   ├── models.py           # Metric, TokenUsage, AggregatedMetric
│       │   └── tests/
│       │       ├── __init__.py
│       │       ├── test_collector.py
│       │       └── test_store.py
│       │
│       ├── validation/             # LAYER 0: Validation Runner
│       │   ├── __init__.py
│       │   ├── runner.py           # ValidationRunner — runs all gates
│       │   ├── gates.py            # Gate ABC + built-in gates (test, lint, type, etc.)
│       │   ├── detection.py        # Language/toolchain detection from project files
│       │   ├── models.py           # ValidationResult, GateResult
│       │   └── tests/
│       │       ├── __init__.py
│       │       ├── test_runner.py
│       │       ├── test_gates.py
│       │       └── test_detection.py
│       │
│       ├── interview/              # LAYER 1: Interview Agent
│       │   ├── __init__.py         # Public API: InterviewAgent, models
│       │   ├── agent.py            # InterviewAgent — main entry point
│       │   ├── question_gen.py     # Dynamic question generation
│       │   ├── completeness.py     # Completeness tracking (1-10)
│       │   ├── notes.py            # Internal note-keeping + profile building
│       │   ├── output.py           # Output formatting per domain
│       │   ├── models.py           # InterviewSession, InterviewTurn, etc.
│       │   ├── domains/            # Domain libraries (grow over time)
│       │   │   ├── __init__.py
│       │   │   ├── software_requirements.py
│       │   │   ├── feature_specs.py
│       │   │   └── architecture_decisions.py
│       │   └── tests/
│       │       ├── __init__.py
│       │       ├── test_agent.py
│       │       ├── test_question_gen.py
│       │       └── test_completeness.py
│       │
│       ├── pm/                     # LAYER 1: PM Integration
│       │   ├── __init__.py
│       │   ├── adapter.py          # PMAdapter ABC
│       │   ├── plane.py            # PlaneAdapter
│       │   ├── linear.py           # LinearAdapter
│       │   ├── ticket.py           # Ticket parsing, scope markers
│       │   ├── models.py
│       │   └── tests/
│       │       ├── __init__.py
│       │       ├── test_adapter.py
│       │       └── test_ticket.py
│       │
│       ├── review/                 # LAYER 1: Critique/Review Layer
│       │   ├── __init__.py
│       │   ├── reviewer.py         # AI review agent (Pass 2)
│       │   ├── circuit_breaker.py  # Circuit breaker logic
│       │   ├── issue.py            # ReviewIssue with agentPrompt
│       │   ├── models.py
│       │   └── tests/
│       │       ├── __init__.py
│       │       ├── test_reviewer.py
│       │       └── test_circuit_breaker.py
│       │
│       └── executor/               # LAYER 2: Managed Executor (optional)
│           ├── __init__.py
│           ├── base.py             # CodingExecutor ABC
│           ├── claude_code.py      # ClaudeCodeExecutor
│           ├── manual.py           # ManualExecutor
│           ├── models.py           # ExecutionContext, ExecutionResult
│           └── tests/
│               ├── __init__.py
│               ├── test_claude_code.py
│               └── test_manual.py
│
├── tests/                          # Cross-module tests ONLY
│   ├── integration/                # Tests that cross module boundaries
│   └── e2e/                        # Full system tests
│
├── pyproject.toml                  # Includes [tool.teambuild] for self-config
├── CLAUDE.md
└── README.md
```

### Import Boundary Enforcement

`import-linter` runs in CI and fails the build if any module violates the layer rules:

```toml
[tool.importlinter]
root_package = "teambuild"

[[tool.importlinter.contracts]]
name = "Foundation layer has no internal dependencies"
type = "independence"
modules = [
    "teambuild.providers",
    "teambuild.metrics",
    "teambuild.context",
    "teambuild.validation",
]

[[tool.importlinter.contracts]]
name = "Layered architecture"
type = "layers"
layers = [
    "teambuild.executor",
    "teambuild.interview | teambuild.pm | teambuild.review",
    "teambuild.providers | teambuild.metrics | teambuild.context | teambuild.validation",
]
```

This gives us:
- **Zero packaging overhead** — single install, single CI pipeline
- **Real enforcement** — import-linter catches coupling in CI, not six months later in code review
- **Tests colocated** — grab a module, its tests come with it. Run one module: `pytest src/teambuild/interview/tests/`
- **Trivial to split later** — if demand arises for `pip install teambuild-interview`, the boundaries are already clean and the split is mechanical
- **Every module replaceable** — clean `__init__.py` public APIs mean any module can be swapped
- **Executor is optional** — remove the `executor/` directory and everything else still works

### Modularity Principle

Every module must be able to function even if other modules are absent. The `__init__.py` of each module defines its public API — nothing outside that API should be imported by other modules. If a module needs something from another module that isn't in its `__init__.py`, that's a design problem, not an import problem.

---

## 14. Build Sequence

### Step 1: Project Scaffolding
- `pyproject.toml` with uv, ruff, mypy, pytest, import-linter
- Directory structure as defined in section 13
- CI basics (lint, type check, test on commit)
- `[tool.teambuild]` self-config section

### Step 2: Provider Abstraction (Layer 0)
- `AgentProvider` ABC and `AgentResult` model
- `PydanticAIProvider` implementation
- `MockProvider` for testing without API keys
- `ProviderConfig` and `ModelRoster`
- Unit tests with mock provider

### Step 3: Metrics Collection (Layer 0, lightweight)
- `MetricsCollector` with `track_invocation` and `track_operation`
- `LocalJSONLStore` for initial storage
- Pydantic models for metrics data

### Step 4: Interview Agent (Layer 1)
- `InterviewAgent` class with `start_interview`, `process_response`, `conclude`
- `QuestionGenerator` with candidate generation and selection
- `CompletenessTracker` with sub-dimension scoring
- `NoteKeeper` for internal state
- `OutputFormatter` for requirements doc generation
- Domain library: `software_requirements.py` (first domain)
- Unit tests with mock provider
- CLI command: `teambuild interview`

### Step 5: PM Integration (Layer 1)
- `PMAdapter` ABC
- `PlaneAdapter` implementation
- Ticket models with scope markers
- CLI command: `teambuild plan`

### Step 6: Validation Runner (Layer 0)
- `ValidationRunner` with pluggable gates
- Language/toolchain auto-detection
- Built-in gates: test, lint, type, format, security
- CLI command: `teambuild check`

### Step 7: Critique/Review Layer (Layer 1)
- Two-pass architecture (automated checks via validation runner + AI deep review)
- `ReviewIssue` with `agentPrompt` for AI-to-AI handoff
- Circuit breaker
- False positive prevention (5-point self-check)
- CLI command: `teambuild review`

### Step 8: Cost/Performance Metrics (Full Module)
- Full `MetricsStore` implementations (JSONL + DuckDB/SQLite)
- Aggregation queries, time-series, comparisons
- PM export for ticket-level cost tracking
- CLI command: `teambuild metrics`
- **Built BY steps 1-7 as the dogfooding test**

### Step 9: Context & Index Manager (Layer 0)
- Three-layer project analysis (static + AST + lazy AI)
- `.index.md` generation and update logic
- CLI commands: `teambuild init`, `teambuild index`

### Step 10: Managed Executor (Layer 2, optional)
- `CodingExecutor` ABC
- `ClaudeCodeExecutor` — wraps Claude Code with rules + monitoring
- `ManualExecutor` — sets up workspace, waits for `teambuild check`
- CLI command: `teambuild code <ticket>`
- **Built last, after everything else is proven through manual use**

### Step 11: Optional Setup Generators
- `teambuild setup claude` — writes CLAUDE.md pointing at indexes
- `teambuild setup cursor` — writes .cursorrules
- `teambuild setup generic` — writes AGENTS.md
- Thin, one-shot generators. Not adapters.

### What Makes This Sequence Work

1. **Foundation first** — Provider, Metrics, and Validation are Layer 0 with no dependencies. Everything else builds on them.
2. **Interview Agent is the first proof of value** — exercises provider and metrics, produces structured output for PM. Conversations are naturally scoped (no codebase context needed).
3. **Validation before execution** — `teambuild check` is proven reliable before wrapping it in automation.
4. **Managed executor last** — building modules 1-8 manually (using Claude Code directly, running `teambuild check` by hand) reveals where handoffs are vague, validation is incomplete, or metrics miss things. That feedback makes the executor better.
5. **The Interview Agent has a real baseline** — conversation 001 was a manual interview. We can compare agent output against it.
