# AgenTeam Architecture

## Principle
OpenCode is the orchestrator. We configure it, not replace it.
Plugin provides: custom tools + workflow enforcement + debug logging.
Agent markdown files provide: role definitions with model/tool/permission config.

## What's Free (OpenCode native)
- Model routing per agent (`model` in agent config)
- Tool/permission restriction per agent
- Subagent dispatch (Task tool + child sessions)
- Session isolation (each subagent = fresh context)
- Structured JSON output (`json_schema` format)

## What We Build

| Component | Type | Cost | Purpose |
|-----------|------|------|---------|
| agenteam_triage | tool | 0 tokens | Scoring-based complexity analysis |
| agenteam_compress | tool | 0 tokens | Strip comments, extract signatures |
| agenteam_state | tool | 0 tokens | Read/write project state (in-memory cache + sync disk) |
| agenteam_dag | tool | 0 tokens | Create/validate/query task graph, retriage |
| agenteam_review_gate | tool | 0 tokens | Track reviews, enforce retry limits, set review_passed |
| agenteam_memory | tool | 0 tokens* | Store/query decisions with local vector search |
| enforcer | plugin hook | 0 tokens | State machine blocks out-of-order calls |
| debug logger | module | 0 tokens | Verbose trace to .agenteam/debug.jsonl |
| memory system | module | 0 tokens* | vectra + @huggingface/transformers for local embeddings |
| 5 agents | config | - | orchestrator, planner, coder, coder-hard, adversary |
| init CLI | bin script | - | `npx agenteam init` scaffolds project, `uninstall` removes it |

*Memory tool itself costs 0 LLM tokens, but the embedding pipeline downloads ~22MB on first use and uses local CPU for inference.

## Strict Enforcement

Plugin intercepts ALL tool calls via `tool.execute.before`.
Reads phase from `.agenteam/state.json` (via in-memory cache). Blocks violations with descriptive errors.
LLM self-corrects on next turn.

```
IDLE ──► triage ──► TRIAGED
                        │
           ┌────────────┴────────────┐
           │ simple                  │ complex
           ▼                         ▼
      dag(create)             Task(planner)
      1-task DAG               returns task list
           │                         │
           │                    dag(create)
           │                         │
           ├─────────────────────────┘
           ▼
        EXECUTING
           │
     ┌──►  dag(next) ──► ready tasks
     │         │
     │    Task(coder|coder-hard)
     │         │
     │    review-gate ──┬── pass ──► dag(complete) ──┐
     │                  ├── retry ──► re-dispatch     │
     │                  └── escalate ──► tier up/user  │
     │                                                │
     │         more tasks? ◄──────────────────────────┘
     │              │
     │         yes ─┘
     │
     └── no ──► DONE
```

### Review Gate Enforcement

The enforcer requires `review_passed = true` before `dag(complete)` will succeed. This is a hard gate — the orchestrator cannot skip the review step. The adversary agent reviews **all task tiers** (both cheap and smart). The flow:

1. After coder completes, call `agenteam_review_gate(task_id, lint_ok, ...)`
2. Review gate sets `task.review.review_passed = true` only on `decision: "pass"`
3. `agenteam_dag(complete)` checks `review_passed` and throws if not set

### Tier-Matched Dispatch

The enforcer blocks wrong-tier agent dispatches:
- `coder` is blocked for `tier=smart` tasks — must use `coder-hard`
- `coder-hard` is blocked for `tier=cheap` tasks — must use `coder`
- `adversary` is allowed for all tiers (uses smart model via `adversary_model` config)

### Re-triage

During execution, if a task's scope changes, the orchestrator can call `agenteam_dag(retriage, task_id, retriage_tier)` to upgrade or downgrade a task's tier. This is useful when:
- A "cheap" task turns out to need deeper analysis → upgrade to "smart"
- A "smart" task was over-scoped → downgrade to "cheap"

## Debug Logging

All operations write structured events to `.agenteam/debug.jsonl`:

```
{ ts, source, event, payload }
```

Sources: `enforcer`, `tool`, `agent`, `plugin`, `system`

Logged events:
- Every tool call (parameters, results, decisions)
- DAG transitions and task timing
- Review gate decisions with reasons
- State transitions and phase changes
- Memory operations (store, query, init)
- Embedding model loading

## Design Decisions

| # | Decision | Why |
|---|----------|-----|
| 1 | OpenCode = orchestrator | Already handles dispatch, routing, isolation |
| 2 | Plugin enforces workflow via tool.execute.before | LLM cannot skip steps |
| 3 | Triage is scoring-based deterministic code | 0 tokens. Multi-signal score > simple rules |
| 4 | Compress is deterministic code | 0 tokens. Regex-based |
| 5 | State in JSON, in-memory cache | Fast tool calls, durable on phase transitions |
| 6 | DAG validated by tool | Checks cycles, deps, readiness |
| 7 | Adversarial review mandatory for all tasks | Enforced by review_gate when always_adversary=true |
| 8 | Retry limits in review-gate | Deterministic. Max N then escalate |
| 9 | Fast path for simple tasks | 1 coder call, no planner, adversary still required |
| 10 | Two coder tiers, static config | No runtime model negotiation |
| 11 | Memory with semantic search | Local embeddings, auto-injected after triage |
| 12 | No file_map, no narrative memory | Filesystem = truth (memory is decision-only) |
| 13 | npm package + init CLI | `npx agenteam init` scaffolds everything |
| 14 | Debug log to file, not stdout | Keeps LLM context clean, persists across sessions |
| 16 | Lazy DAG generation | Prevents hallucinating dependencies on non-existent code |
| 17 | Re-triage action | Tasks can be upgraded/downgraded mid-execution |
| 18 | Adversary uses smart model | Better review quality, configurable via adversary_model |
| 19 | Memory is local-only | No external API calls, data stays in project |
| 20 | review_passed hard gate | Cannot complete tasks without passing review gate |
| 21 | Content stored outside vectra | Avoids vectra metadata size limits |
| 22 | State cache with sync disk writes | Fast tool calls, durable state |
| 23 | Parallel execution | dag(next) starts all ready tasks, orchestrator dispatches multiple subagents |
| 24 | Tier-matched dispatch | Enforcer blocks wrong-tier agent dispatches |
