Skip to content

Development

conda run -n cosmotron python -m pytest tests/ -q     # full suite (synthetic data only)

Run this after any change to cosmotron_mcp/; it must stay green. The cosmotron conda env holds every dependency, including the optional covariance stack (sacc/pyccl/tjpcov) and the inference stack (firecrown/cosmosis/lsstdesc-crow — conda-forge only, see Install).

Full developer guidance — agent-prompt editing rules, the tool-priority invariant in detail — lives in CLAUDE.md at the repo root; the tool + agent contract the runtime agents themselves read is AGENTS.md. This page is a shorter, docs-site-native summary of the parts most relevant to someone extending the pipeline.

Repo layout

cosmotron_mcp/
├── server.py              FastMCP server — thin @mcp.tool wrappers; no logic here.
├── tools/                 Deterministic pipeline functions (catalogue, maps, spectra,
│                          covariance, ingest, readers, io, scripting, jobs, inference).
├── schemas.py             Pydantic models (PipelineConfig, Manifest, SessionContext,
│                          CatalogueProfile, DatasetRecord) + SCHEMA_VERSION.
├── profiles.py            Catalogue-type profile loader (catalogue_profiles.yaml).
├── registry.py            Persistent SQLite dataset registry (L1).
├── pipeline_resolve.py    Deterministic pipeline_config resolution + provenance.
├── base.py                Session/manifest/artefact I/O + validation.
├── gates.py               Human gates (results/gates/<gate_id>.json), closed only by
│                          authorise_gate (permission: ask). See Human gates.
├── reviewer_tools.py      Deterministic review evidence block.
├── output_validation.py   Post-run invariant checks (Nyquist, Knox, SACC shape).
└── plotting.py            Deterministic figures (no fabricated data).
.opencode/
├── agents/                Agent prompts.
└── skills/                Static reference skills.
tests/                     pytest suite (synthetic data, no real surveys).
docs-site/                 This documentation site (MkDocs + mkdocs-material).

Tool-priority invariant

"A capability was shipped as a tool, but the model wrote its own script instead" is the single most common regression in this repo's history. It's structural, not a one-off, so any new pipeline/plot/inference capability must do all of the following or it will regress:

  1. Ship it as a first-class MCP tool. Deterministic Python, not model-authored code.
  2. Make the tool cover the actual request, name the capability in the signature. If users keep escaping to hand-written code to get X, X belongs as a named parameter on the existing tool, not a new one.
  3. Close the escape hatch mechanically. run_analysis_script rejects matplotlib/pyplot/ savefig by default; @cosmotron's tool-deny list is enforced by tests/test_cosmotron_toolmap.py, not a prose "never".
  4. Keep every doc surface in sync — the agent prompt's tool table, AGENTS.md, the matching skill, and (now) this docs site's API reference. A capability the agent can't see, it won't use.
  5. Add a mechanical test that the escape is blocked or the tool covers the request (e.g. tests/test_scripting_plot_guard.py, tests/test_plotting_show_noise.py, tests/test_docs_tool_coverage.py).

The same logic applies to inference config: the model picks a family/choice, the tool owns the syntax — never let the model author raw CosmoSIS INI or Firecrown YAML (see Writing TASK.md).

Extending this documentation

  • New @mcp.tool in server.py → add its name to server.py's __all__ list. That's it — docs-site/gen_reference_pages.py runs on every build, parses server.py's imports to find which real module the tool delegates to (via tests/_tool_inventory.tool_module_map), and writes it onto that module's API reference page automatically. No page to hand-edit, no category to pick. tests/test_docs_tool_coverage.py fails the suite until the tool is in __all__.
  • New agent in .opencode/agents/ → one new agents/<name>.md page + one nav: line in docs-site/mkdocs.yml.
  • New skill in .opencode/skills/ → one new ## section in skills.md.
  • New survey familycosmotron_mcp/catalogue_profiles.yaml needs no doc change (the field reference in Catalogue-type profiles already covers every field); only add an example if the new family exercises a field the existing KiDS-1000 example doesn't.
  • New human-confirmation point → prefer a human gate (cosmotron_mcp/gates.py::open_gate) over a mandatory string argument on the tool that would otherwise resolve it — a string is something the model writes, a gate file closed by authorise_gate behind permission: ask is not. Add the new gate kind to gates.py's kind table and to Human gates's table; if it has no safe default and resolves by re-calling with corrected input rather than by authorise_gate (like nside/probe/cores), do NOT persist it as a gate file — see that page for why.
  • New COSMOTRON_* env var → add a row to Configuration & environment's table — that page is the one place a user-facing env var should be documented; several existed with no doc entry anywhere before this rule.

Build and preview locally:

pip install -e ".[docs]"
mkdocs serve -f docs-site/mkdocs.yml     # http://127.0.0.1:8000
mkdocs build --strict -f docs-site/mkdocs.yml