Skip to content

The agent roster

The pipeline tools in the API reference are deterministic Python — they don't decide anything. Decisions (which tool to call, when a step is done, whether a result passes review) are made by a roster of prose-prompt opencode agents in .opencode/agents/ — the agent's name is its filename, there is no separate registry. Only @cosmotron is user-facing; every other agent is a subagent dispatched by it.

Agent Role
cosmotron Primary orchestrator — the entry point
session_bootstrapper Creates the session via bootstrap_session
literature_scout Light ADS/arXiv context lookup
planner Drafts the analysis plan — the human is the plan gate
data_ingestor Standardises each catalogue via ingest_to_session
analysis_coder Runs spectra/covariance/SACC/plot tools in sequence
systematics_checker Systematics cross-correlation, deprojection, B-mode null tests
inference Builds the Firecrown config, launches/polls CosmoSIS
reviewer Judges the deterministic evidence block, emits PASS/FAIL
plot_reviewer Advisory vision agent — reads result PNGs

Static reference material the agents read (NaMaster API, the LSS pipeline domain, plotting conventions, workspace layout, CosmoSIS samplers) lives in .opencode/skills/ — see Skills.

How a run flows

@cosmotron is the hub — every arrow below is a delegation to/from it, never subagent-to-subagent. The human plan gate and the systematics/review gates are the two points where a run can stop and wait rather than proceed:

%%{init: {"sequence": {"useMaxWidth": false}}}%%
sequenceDiagram
    actor User
    participant C as cosmotron
    participant SB as session_bootstrapper
    participant PL as planner
    participant DI as data_ingestor
    participant AC as analysis_coder
    participant INF as inference
    participant SC as systematics_checker
    participant RV as reviewer

    User->>C: task (@cosmotron / /cosmotron)
    C->>SB: bootstrap session
    SB-->>C: session_context.json
    C->>PL: draft plan
    PL-->>C: plan.json
    C->>User: plan for approval
    User-->>C: human gate: approve
    loop per catalogue
        C->>DI: ingest_to_session
        DI-->>C: manifest.json
    end
    C->>AC: compute spectra / covariance / SACC
    AC-->>C: results/ + SACC
    opt inference requested
        C->>INF: build_cosmosis_inference / run_inference
        INF-->>C: posterior job
    end
    C->>SC: systematics gate
    SC-->>C: PASS / FAIL / MISSING
    C->>RV: build_review_evidence
    RV-->>C: REVIEW: PASS / FAIL
    alt REVIEW is FAIL (capped at 2 fix-then-re-review cycles)
        RV-->>C: root cause
        C->>AC: fix & recompute
        C->>RV: re-review
    end
    C->>User: results gate + review verdict

Two things this simplifies: literature_scout isn't shown — it's dispatched ad hoc for abstracts-only context lookups or citations, not a fixed pipeline step. plot_reviewer isn't shown either — it's currently parked, not dispatched by @cosmotron at all (see plot_reviewer). A NEEDS_INPUT/ERROR signal from any subagent (see Subagents have no interactive channel below) routes back through cosmotron to the user at whichever step it occurs, rather than following this happy path.

Platform conventions

These apply across the whole roster and are worth understanding before editing any .opencode/agents/*.md prompt.

@cosmotron never calls pipeline tools

@cosmotron is the only mode: primary agent. It delegates everything via @mention and calls no pipeline tools itself — enforced by an explicit per-tool deny in its frontmatter, not a whole-server switch. opencode's Agent.tools is a flat {tool: bool} map with no "disable this MCP server" key, so every cosmotron_* tool must be listed false individually except a fixed allow-list of coordination/read tools (read_memory, append_memory, audit_memory, get_active_session, read_session_context_tool, build_review_evidence, write_plan/read_plan/set_plan_step_status, mark_plan_approved, check_job, list_jobs, cancel_job, authorise_gate). tests/test_cosmotron_toolmap.py mechanically enforces this: every @mcp.tool in server.py must have a corresponding cosmotron_<name>: true|false line in cosmotron.md's frontmatter, and only the allow-list above may be true. A new tool added to server.py without a matching false line in cosmotron.md leaks to the orchestrator and fails this test.

authorise_gate additionally carries permission: ask in cosmotron.md's frontmatter — the only tool gated this way. Being true in the tool map just makes it reachable; ask is what makes it unforgeable, by suspending the call for a real runtime confirmation dialogue before it runs. See Human gates.

Subagents have no interactive channel

opencode TUI bug #7654 means a nested subagent's free-form question never surfaces to the user. So subagents never end a turn with a question — instead they emit exactly one terminal signal:

NEEDS_INPUT: <question> | options: … | default: …
ERROR: <what went wrong> | tried: …

@cosmotron routes NEEDS_INPUT to the user and caps retries at 2 attempts per step. Any edit to a subagent prompt must preserve this protocol.

Model choice

The orchestrator needs a non-thinking instruct model — a per-agent model: override pins this. Confirmed failures: thinking variants spiral and never reach @planner; qwen3-coder-* variants autocomplete code well but follow the non-interactive/tool-first/no-fabrication operating contract poorly. Subagents use the global (thinking-capable) model. See Configuration for the full local-model rationale (small models only — this runs on a DGX Spark shared with the numerical pipeline).

Tool-first

Agents call the MCP tools for any step one already covers — never raw pymaster/healpy/sacc/pyccl for something a tool does. analysis_coder in particular has run_analysis_script as its one sanctioned escape hatch for a genuinely uncovered non-plotting step, and even that mechanically rejects plotting code. See Development.