{
  "markdown": "# Coral\n\n> **The project manifest for AI-era development.** Multi-repo wiki + dev environments + functional testing + Model Context Protocol server, in a single Rust binary.\n\n[![CI](https://github.com/agustincbajo/Coral/actions/workflows/ci.yml/badge.svg)](https://github.com/agustincbajo/Coral/actions/workflows/ci.yml)\n[![Release](https://img.shields.io/github/v/release/agustincbajo/Coral?display_name=tag)](https://github.com/agustincbajo/Coral/releases)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![Rust](https://img.shields.io/badge/rust-1.89%2B-orange?logo=rust)](rust-toolchain.toml)\n[![MCP](https://img.shields.io/badge/MCP-2025--11--25-blue?logo=anthropic)](https://modelcontextprotocol.io/)\n[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/agustincbajo/Coral/badge)](https://scorecard.dev/viewer/?uri=github.com/agustincbajo/Coral)\n\nCoral is a Karpathy-style LLM wiki for your code, scaled to microservice-shaped projects: declare your repos in a `coral.toml`, bring up a multi-service environment, run functional tests, and expose the whole thing to coding agents (Claude Code, Cursor, Continue, Cline, Goose, Codex, Copilot) via Model Context Protocol — one binary, open source, all local. Hardened across **five multi-agent audit cycles**.\n\n> *\"The IDE is Claude Code. The programmer is you + the LLM. The wiki is the living memory of your codebase. Coral is the manifest that makes both intelligible across N repos.\"*\n\n---\n\n## Getting Started in 60 seconds\n\n> *A short GIF showing the full flow (install → first prompt → routing → bootstrap → query) is shipped in a follow-up release commit; see [`docs/getting-started.gif.placeholder`](docs/getting-started.gif.placeholder) for the storyboard. Until then, the two paste-blocks below are the canonical onboarding contract (PRD v1.4 §16 DoD #14).*\n\n### The fast path — one line + zero pastes (`--with-claude-config`)\n\n```bash\n# 1. Install the Coral binary AND register the marketplace in this project.\ncurl -fsSL https://raw.githubusercontent.com/agustincbajo/Coral/main/scripts/install.sh \\\n  | bash -s -- --with-claude-config\n\n# 2. Open Claude Code in this repo. Type anything (\"hi\", \"set up coral\",\n#    \"where do I start?\"). Coral's CLAUDE.md routes Claude to suggest\n#    the right next step (bootstrap, doctor, or a query).\n```\n\nOn Windows:\n\n```powershell\n# Run from PowerShell — pins the binary under %LOCALAPPDATA%\\Coral\\bin.\niwr -useb https://raw.githubusercontent.com/agustincbajo/Coral/main/scripts/install.ps1 `\n  | iex\n# Then `coral self-register-marketplace` from inside the target repo.\n```\n\n### The default path — 3 paste lines\n\n```bash\n# 1. Install the Coral binary (no Claude Code config patch).\ncurl -fsSL https://raw.githubusercontent.com/agustincbajo/Coral/main/scripts/install.sh | bash\n\n# 2. Paste these 3 lines into Claude Code (one at a time, `&&` chains\n#    don't work in Claude Code's prompt parser):\n/plugin marketplace add agustincbajo/Coral\n/plugin install coral@coral\n/reload-plugins\n\n# 3. Type anything in Claude Code. CLAUDE.md + the SessionStart hook\n#    route Claude from there.\n```\n\n### What happens next\n\n1. The `SessionStart` hook runs `coral self-check --quick --format=json` and reports your repo state to Claude (silent, < 100 ms p95).\n2. Claude's first response — to **any** prompt — follows the routing block in `CLAUDE.md`:\n   - No `.wiki/` yet? → suggests `/coral:coral-bootstrap` (cost-confirmed).\n   - No LLM provider configured? → suggests `/coral:coral-doctor` (4-path mini-wizard).\n   - All set? → answers from your wiki via MCP.\n3. **Deterministic fallback**: if Claude doesn't suggest anything, type `/coral:coral-doctor`. That slash command has `disable-model-invocation: true`, so it always runs without spending tokens.\n\n### Don't have Claude Code yet?\n\nYou can drive the same onboarding from your shell — **fully autonomous, no wizard required** (v0.41+):\n\n```bash\n# One command does everything (recommended):\ncoral setup                # init + estimate + confirm + bootstrap + welcome\n\n# After setup finishes:\ncoral tour                 # interactive 2-min walkthrough of features\ncoral query \"how does authentication work?\"\n```\n\nThe `coral setup` flow:\n1. Scans your repo (file count, LOC)\n2. Shows a cost estimate with page count\n3. Asks for one Y/n confirmation\n4. Bootstraps all pages with per-page progress (`[3/24] ▶ Generating auth-middleware...`)\n5. Runs `lint --fix` automatically\n6. Shows a welcome screen with next steps\n\nFor granular control, the individual commands still work:\n\n```bash\ncoral init                 # scaffolds .wiki/ + CLAUDE.md + .gitignore\ncoral bootstrap --estimate # see the upper-bound cost first\ncoral bootstrap --apply --max-cost=5.00\n```\n\nIf `claude` isn't on your PATH, or you want a different provider:\n\n```bash\ncoral init --provider claude_cli   # explicit provider (no auto-detect needed)\ncoral doctor --wizard              # interactive 4-path wizard (Anthropic API / Gemini / Ollama / claude CLI)\n```\n\nFor the full install reference (flags, troubleshooting, uninstall, upgrade) see [`docs/INSTALL.md`](docs/INSTALL.md).\n\n---\n\n### Use it from Claude Code in one command\n\nIf you already have [Claude Code](https://claude.com/code), you can skip the manual MCP wiring and let a plugin handle it. Inside Claude Code:\n\n```\n/plugin marketplace add agustincbajo/Coral\n/plugin install coral@coral\n```\n\nThat's it. Ask Claude: *\"set up Coral for this repo\"* — the plugin's `coral-bootstrap` skill takes over, confirms before the paid `bootstrap --apply` step, and gets you to a working wiki. Conceptual questions (\"how does auth work?\", \"I'm new here, where do I start?\") auto-route through the bundled `coral-query` and `coral-onboard` skills, which read the wiki via MCP before grepping source.\n\nPrereq: you still need the `coral` binary on `$PATH` first — install it via the [one-line installer](#one-line-installer-linuxmacoswindows) or any of the methods under [Install](#install). The plugin assumes `coral` is reachable; if it isn't, `/plugin` → Errors will say so.\n\n---\n\n## Table of contents\n\n**Getting started**\n- [Getting Started in 60 seconds](#getting-started-in-60-seconds) (fast path + default 3-paste path)\n- [What you get](#what-you-get) · [Why Coral](#why-coral) · [Install](#install)\n- [Quickstart](#quickstart) (single-repo, multi-repo, environments+tests, MCP server, session-distill)\n\n**Use it**\n- [Cookbook — 7 common workflows](#cookbook--common-workflows)\n- [MCP client integration](#mcp-client-integration) (Claude Code · Cursor · Continue · Cline · Goose · raw JSON-RPC · HTTP/SSE)\n- [Output examples](#output-examples) — what each command actually prints\n\n**Reference**\n- [Subcommand reference](#subcommand-reference) · [Wiki schema](#the-wiki-schema) ([Page types](#page-types) · [Status lifecycle](#status-lifecycle) · [Confidence](#confidence)) · [`coral.toml`](#the-coraltoml-manifest) · [`coral.lock`](#the-corallock-lockfile) · [Test schema](#test-schema-coraltestsyamlhurl)\n- [Multi-provider LLM support](#multi-provider-llm-support) · [Auth setup](#auth-setup) · [Configuration](#configuration)\n\n**Operations**\n- [Backward compatibility](#backward-compatibility) · [Security model](#security-model) · [CI integration](#ci-integration) · [Performance](#performance) · [Testing & CI](#testing--ci)\n- [Troubleshooting](#troubleshooting) · [FAQ](#faq) · [Glossary](#glossary)\n\n**Project**\n- [Architecture](#architecture) · [Comparison vs adjacent tools](#comparison-vs-adjacent-tools) · [Roadmap](#roadmap)\n- [How Coral itself was built](#how-coral-itself-was-built) · [Releasing](#releasing) · [Contributing](#contributing) · [References](#references--related-work) · [License](#license)\n\n---\n\n## What you get\n\nA single `coral` binary (~6.3 MB stripped, statically linked, MSRV 1.89, ad-hoc-codesigned on macOS) with **56+ leaf subcommands** (33 top-level commands, eight of which group sub-subcommands) across seven layers:\n\n| Layer | Commands | Since |\n|---|---|---|\n| **Wiki** | `init` `bootstrap` `ingest` `query` `lint` `consolidate` `stats` `sync` `onboard` `prompts` `search` `export` `notion-push` `validate-pin` `diff` `status` `history` | v0.1+ |\n| **Multi-repo** | `project new/list/add/sync/doctor/lock/graph` | v0.16 |\n| **Environments** | `up` `down` `env status/logs/exec/import/devcontainer emit` | v0.17, v0.19.7 (`import`), v0.21.0 (`devcontainer emit`) |\n| **Functional testing** | `test` `test-discover` `verify` `contract check` | v0.18, v0.19 (`contract`) |\n| **AI ecosystem** | `mcp serve` `export-agents` `context-build` | v0.19 |\n| **Sessions** | `session capture/list/show/forget/distill` | v0.20 |\n| **Deep Code Intelligence** | `index` `graph build/show/callers/callees/hot/impact/deps` `find` `embed` `implement run/plan/sketch/validate/apply/patterns` `stale` | v0.41 |\n\nPlus:\n\n- **13 Rust crates** in a workspace: `coral-cli`, `coral-core`, `coral-env`, `coral-test`, `coral-mcp`, `coral-runner`, `coral-lint`, `coral-stats`, `coral-session`, `coral-index`, `coral-graph`, `coral-search`, `coral-implement`.\n- **6 LLM runner implementations** (`Claude`, `AnthropicApi`, `Gemini`, `Local` llama.cpp, `Http` OpenAI-compat, `Mock` for tests). `AnthropicApi` (v0.41) auto-defaults inside Claude Code sessions — no API key, no subprocess, no auth issues. API keys never appear in process argv (piped via stdin); request bodies never appear in argv either (per-call tempfile mode 0600 via RAII guard).\n- **5 embeddings providers** (`Voyage`, `OpenAI`, `Anthropic`, `ONNX/nomic` local behind feature flag, `Mock`).\n- **7 language parsers** (Rust, TypeScript/JavaScript, Python, Go, Java, C, C++) via tree-sitter AST — behind feature flags (`lang-go`, `lang-java`, `lang-c`, `lang-cpp`).\n- **Hybrid search engine**: BM25 keyword (tantivy) + TF-IDF semantic + structural graph + vector embeddings — fused with weighted Reciprocal Rank Fusion (RRF, k=60).\n- **2 storage backends** (JSON default, SQLite via `CORAL_EMBEDDINGS_BACKEND=sqlite`).\n- **11 structural lint checks** (incl. `unreviewed-distilled` v0.20 + `injection-suspected` v0.19.5 default-on since v0.20.2) + 1 LLM-driven semantic check + auto-fix routing.\n- **5 export formats** for the wiki (`markdown-bundle`, `json`, `notion-json`, `jsonl`, `html`).\n- **5 export formats** for AI agent instructions (`agents-md`, `claude-md`, `cursor-rules`, `copilot`, `llms-txt`) — manifest-driven, NOT LLM-driven.\n- **4 fully wired test kinds today** (`Healthcheck`, `UserDefined`, `PropertyBased`, `Recorded`) **+ 4 stub runners** (`Contract`, `Event`, `Trace`, `E2eBrowser` — return `Skip` with a roadmap URL) **+ 1 reserved schema-only variant** (`LlmGenerated` — synthetic `Skip` emitted by the orchestrator, no runner impl). The `TestKind` enum carries all 9 variants so the wire format stays stable when their runners ship; `coral test --help` flags reserved kinds with `[reserved — not yet wired]`.\n- **8 MCP resources + 7 read-only tools + 3 write tools (enabled by default since v0.41; disable with `--no-write-tools`) + 3 prompts** exposed via JSON-RPC 2.0 stdio. MCP `mimeType` matches actual payload per resource (catalog-driven). `.coral/audit.log` rotates at 16 MiB. Notification methods (no `id`) silently no-op per JSON-RPC 2.0 §4.1.\n- **End-to-end concurrency safety**: atomic writes (`tmp + rename`), cross-process `flock(2)` locking, race-free parallel `coral ingest` AND `coral project sync`. `WikiLog::append_atomic` is race-free under contending writers (header+entry sequence cannot be reordered).\n- **Hardened against adversarial inputs**: slug allowlist (`is_safe_filename_slug` + `is_safe_repo_name`) at every interpolation site; `--` separator before user-controlled positionals in every `git` invocation (CVE-2017-1000117 / CVE-2024-32004 family); 32 MiB cap on every `read_to_string` of user-supplied content; secret scrubbing in every `RunnerError` Display.\n- **Backward-compat guarantee**: every v0.15 single-repo workflow keeps working — pinned by a dedicated `bc-regression` test job (6 fixtures) that runs on every PR.\n\n---\n\n## WebUI (`coral ui serve`)\n\nSince v0.32.0 Coral ships a modern React SPA embedded in the binary. Single command:\n\n```bash\ncoral ui serve\n# opens http://localhost:3838 in your browser\n```\n\n### The four views\n\n**Pages** — filterable list with bi-temporal awareness, status & confidence overlays, Markdown detail panel.\n\n![Pages view: filter sidebar + table of 20 wiki pages with type/status/confidence/backlinks columns](docs/assets/ui-pages-en.png)\n\n**Graph** — Sigma.js force-directed view of wikilinks with the unique **bi-temporal slider** that scrubs through `valid_from`/`valid_to` history. Color by status (Draft / Reviewed / Verified / Stale / Archived / Reference), size by degree, opacity by confidence. **Click a node** to highlight its connected edges in teal and dim unrelated nodes — makes dependency tracing visual.\n\n![Graph view: ForceAtlas2 layout of 20 nodes coloured by status with bi-temporal slider](docs/assets/ui-graph-en.png)\n\n**Query** — LLM-backed playground that streams `coral query` over Server-Sent Events. Selectable mode (Local / Global / Hybrid), explicit token-cost warning, sources cited back to the Pages view.\n\n![Query playground: textarea + Local/Global/Hybrid mode selector + LLM cost warning](docs/assets/ui-query-en.png)\n\n**Manifest** — `coral.toml` + `coral.lock` + a live stats breakdown.\n\n![Manifest view: 20 pages, 91% avg confidence, 46 backlinks, status & page-type distributions](docs/assets/ui-manifest-en.png)\n\n### What's unique to Coral here\n\n- **Bi-temporal scrubbing of the knowledge graph** — every other RAG/graph tool drops `valid_from` / `valid_to` / `superseded_by` on the floor. Coral's Graph view lets you scrub the slider to *\"as of\"* any date and watch nodes appear/disappear as the wiki's history changes.\n- **Status & confidence are first-class visuals** — node colour encodes the curation lifecycle (Draft → Reviewed → Verified → Stale → Archived), opacity encodes the `[0.0, 1.0]` confidence. You see at a glance which corners of your wiki are still rough.\n- **Interactive dependency tracing (v0.41)** — click any node and its connected edges turn teal while unrelated nodes and edges dim. Instantly see what a module depends on and what depends on it.\n- **Cited LLM answers** — the Query view streams tokens via SSE *and* pipes back slug references so the user can verify the wiki page directly. No black-box completions.\n\n### Write tools in the WebUI\n\nSince v0.41, the Herramientas/Tools page exposes **Verify**, **Run Test**, **Up**, and **Down** buttons enabled by default. Pass `--no-write-tools` to `coral ui serve` to disable them. The Claude Code plugin auto-launches the WebUI after every Coral operation and reminds the user of the URL (`http://localhost:3838`).\n\n### Why end-users don't need Node\n\nThe pre-built SPA is committed to `crates/coral-ui/assets/dist/` and embedded into the Rust binary at compile time via `include_dir!`. End-users **never** need Node or npm — `cargo install coral-cli` ships the UI with the binary. Loopback-only (`127.0.0.1`); write tools enabled by default since v0.41. A bearer token (`--token` / `CORAL_UI_TOKEN`) gates the LLM query endpoint and any non-loopback bind.\n\n> **Removed in v0.38.0:** the legacy `coral wiki serve` (HTML/Mermaid, single page from v0.25.0) was retired after a 3-version deprecation window (announced v0.34.1). Use `coral ui serve` — same `--port` / `--bind` defaults, modern SPA with graph + bi-temporal slider.\n\nFull docs: [`docs/UI.md`](docs/UI.md).\n\nTo opt out of the WebUI in a minimal install:\n\n```bash\ncargo install coral-cli --no-default-features --features mcp,cli\n```\n\n## Why Coral\n\nThree problems in one tool.\n\n### 1. The naive `AGENTS.md` problem\n\nGiving an LLM context about your repo by hand-writing one giant `AGENTS.md` file is fragile. It grows out of control, eats your context window, drifts out of sync with the code, and provides zero auditability. Recent context-engineering work — including [Anthropic's published guidance](https://www.anthropic.com/engineering/context-engineering) and broader empirical reports — has converged on **structured note-taking persisted across sessions** rather than monolithic context dumps; LLM-generated `AGENTS.md` files in particular have shown degraded agent task success vs. deterministic, manifest-driven templates.\n\n**Coral wiki** is a constellation of small (<300 line) Markdown pages, each tagged with frontmatter (`slug`, `type`, `confidence`, `sources`, `backlinks`), curated by an LLM bibliotecario subagent under a strict SCHEMA.\n\n| Aspect | Naive `AGENTS.md` | Coral wiki |\n|---|---|---|\n| Storage | Single growing file | Constellation of small Markdown pages |\n| State | Implicit, drifts | Explicit, `last_updated_commit` per page |\n| Lock-in | None | None — plain Markdown in Git |\n| Auditability | Opaque | Each page cites verifiable `sources` |\n| Maintenance | Manual | Incremental ingest on every push |\n| Search | grep | TF-IDF default + Voyage embeddings opt-in |\n\n### 2. The microservices problem\n\nMost production codebases span N repos. Coding agents (Cursor, Claude Code, Continue, …) treat each repo in isolation; your developers spend hours wiring up the dev environment by hand each onboarding. Cross-repo edits introduce drift — service A's OpenAPI changes, service B's consumer expectations don't follow, and nobody notices until staging.\n\n**How Coral mitigates it** — concrete mechanisms, not slogans:\n\n- **`coral.toml` as the project manifest.** Declare every repo *once*, with `remotes`, `depends_on`, `tags`. From any working tree, `coral env up` brings the whole stack online and `coral query \"how does X work\"` reads the aggregated wiki across all of them. Same role as `Cargo.toml`'s `[workspace]` — but for repos that don't share a build system.\n- **`coral.lock` pins resolved SHAs.** When repo A points at `main` and someone pushes a breaking change downstream, the lockfile catches it on `coral env up` and the diff against the previous lock is the audit trail. Same role as `Cargo.lock` / `package-lock.json` / `MODULE.bazel.lock`, just for `git+ssh://` sources instead of crate registries.\n- **Aggregated wiki.** Every repo has its own `.wiki/`; `coral consolidate` builds a single namespaced view (`<repo>/<slug>`) so a coding agent answering \"how does the order saga work\" can read entries from *all* services without you wiring it up. The wiki is plain Markdown — Git-native, auditable, diff-able in PRs.\n- **`coral diff <ref>` + `coral affected --since <ref>`.** Given a git ref, Coral computes which repos a change touches **and** which downstream consumers are affected (via `depends_on`). Combined with `coral contract check`, it's the blast-radius computation that lets a coding agent answer \"what else do I need to update?\" before pushing.\n- **`coral interface watch`.** A daemon that watches `.wiki/` for changes to `Interface`-typed pages and emits structured notifications. When repo A's contract page changes, repo B's agent gets a push event — closing the loop that human teams normally bridge through Slack and forgotten Notion comments.\n- **One MCP surface for all of it.** Every coding agent on the box (Claude Code, Cursor, Continue, Cline, Goose) reads the same `coral://wiki`, `coral://manifest`, `coral://lock`, `coral://contracts` resources through `coral mcp serve`. The agent doesn't need to know there are N repos; it sees one project.\n\nThe net effect: a coding agent operating on a single repo can answer multi-repo questions correctly, and a change in repo A that breaks repo B is surfaced *before* the test environment is brought up.\n\n### 3. The functional testing problem\n\nUnit tests don't tell you if your microservices actually work together. End-to-end browser tests are slow and brittle. The middle layer — *integration tests against a running multi-service stack* — is where most teams have nothing: tribal knowledge bash scripts, a fragile CI job nobody understands, and an \"it works on my machine\" rate that drifts up every quarter.\n\n**How Coral mitigates it** — the actual mechanisms:\n\n- **One env spec, one command.** `coral env up` reads `coral.toml`, brings up every declared service via `docker compose` (real binaries, real databases, real network), waits on per-service healthchecks, and prints a single line per service when it's ready. `coral env down` (with `--volumes`) is the matching teardown. No bash glue, no `docker-compose.yml` boilerplate per developer.\n- **TestCases as YAML/Hurl, not code.** Tests live in `.coral/tests/*.{yaml,hurl}` — declarative, reviewable, language-agnostic. A failing test points at the wire request it sent, the actual response, and the assertion that failed. Languages don't compose; YAML does.\n- **OpenAPI auto-discovery.** Drop an `openapi.{yaml,yml,json}` next to a service in `coral.toml` and `coral test-discover` synthesizes baseline TestCases for every operation — Schemathesis-style property tests with shrink-on-failure plus path/method/status checks. No \"we haven't written tests for that endpoint yet\" excuse.\n- **`coral contract check` runs *before* the env comes up.** It diffs each consumer's `.coral/tests/` against each provider's `openapi.yaml` — paths, methods, status codes, request body fields, parameter schemas — and exits non-zero on drift. No more \"20 minutes into a CI run, generic 404, no clue why.\" See [Recipe 4](#recipe-4--cross-repo-contract-testing) for the wire-level example.\n- **`coral test guarantee --can-i-deploy <env>`.** Aggregates lint + contract drift + functional tests + flake rate into a single **GREEN / YELLOW / RED** verdict. Use it as the last step of CI: green means the change *might* ship; red means it definitely shouldn't. Yellow flags warning-class drift (e.g. a new optional field added) that you can ship but should track.\n- **Recorded captures (`coral test record`, Linux).** Capture real HTTP traffic during exploratory testing with `keploy record`, replay it deterministically on every CI run as `coral test --kind recorded`. Closes the loop on \"the test passes but production behaves differently.\"\n- **JUnit XML out.** Every test runner emits JUnit XML so it slots into existing CI dashboards (GitHub Actions test reporting, GitLab, Jenkins, etc.) without per-tool plugins.\n\nThe combination — env bring-up + declarative TestCases + pre-flight contract gate + aggregate verdict — is what turns \"20 minutes of bash, then maybe it works\" into \"one command, deterministic exit code, parseable output.\"\n\n> **Scope, honestly.** Coral lives in the [microservice honeycomb middle layer](https://martinfowler.com/articles/2021-test-shapes.html) — integration, smoke, contract. Use `cargo test` / `pytest` / `jest` for unit tests; use Playwright for full browser E2E. Coral does the middle that's chronically under-served.\n\n**Coral mcp serve** exposes the wiki + manifest + lockfile + test results to *any* MCP-speaking agent, so your AI workflows operate on the same structured ground truth your team operates on. Per the [MCP 2025-11-25 spec](https://modelcontextprotocol.io/specification/2025-11-25), pinned in `coral-mcp::PROTOCOL_VERSION`.\n\n---\n\n## Install\n\n### Prerequisites\n\n- **Rust** 1.89+ (stable). Install via [rustup](https://rustup.rs/).\n- **Git** 2.30+.\n- **`curl`** (universally available; used by the test runner for HTTP probes — no libcurl FFI dep).\n- **Optional:** `docker compose` v2.22+ (for `coral up` / `coral down` / `coral env *` and `coral verify`). `podman compose` and `docker-compose` v1 are also detected.\n- **Optional:** [Claude Code CLI](https://claude.com/code) (`claude` in `$PATH`) for LLM-backed subcommands.\n\n### One-line installer (Linux/macOS/Windows)\n\nFetches the latest release tarball matching your platform/arch, verifies the SHA-256, drops `coral` on `$PATH`, and prints the two-line snippet to install the Claude Code plugin afterwards. Idempotent — re-running over the same release is a no-op.\n\n```bash\n# Linux / macOS  (writes to /usr/local/bin or ~/.local/bin)\ncurl -fsSL https://raw.githubusercontent.com/agustincbajo/Coral/main/scripts/install.sh | bash\n```\n\n```powershell\n# Windows  (writes to %LOCALAPPDATA%\\Coral\\bin and prepends it to user PATH)\niwr -useb https://raw.githubusercontent.com/agustincbajo/Coral/main/scripts/install.ps1 | iex\n```\n\nPin a version with `bash -s -- --version v0.40.2` (Linux/macOS) or `... | iex; & coral --version` (Windows, after install). For a manual download with full control, see [Pre-built binaries](#pre-built-binaries) below.\n\n> **macOS + Claude Code:** The installer detects when it's running inside a Claude Code shell (`CLAUDECODE=1`) on macOS Sequoia and **refuses** with an actionable message. Reason: macOS stamps every file a tracked process writes with `com.apple.provenance`, making the binary EPERM-inaccessible from a regular Terminal — and the provenance **cannot be stripped**, even via `sudo`. Run the installer from a plain Terminal instead. Override: `CORAL_INSTALL_ALLOW_TRACKED_PROCESS=1`.\n\n### From a tagged release (recommended)\n\n```bash\ncargo install --locked --git https://github.com/agustincbajo/Coral --tag v0.40.2 coral-cli\n```\n\n(Replace `v0.40.2` with the latest tag from the [Releases page](https://github.com/agustincbajo/Coral/releases).)\n\n### From `main` (latest)\n\n```bash\ncargo install --locked --git https://github.com/agustincbajo/Coral coral-cli\n```\n\n### From source (development)\n\n```bash\ngit clone https://github.com/agustincbajo/Coral\ncd Coral\n./scripts/dev-setup.sh           # one-time: cargo-sweep, sccache, cargo-nextest\ncargo build --release\n./target/release/coral --version\n```\n\nDisk hygiene: `cargo build`/`cargo test` cycles inflate `target/`\nfast (typical sustained dev session: ~5–8 GiB; a 7-release sprint\nthat forgets maintenance: ~45 GiB). One-liner umbrella:\n\n```bash\n./scripts/dev-cleanup.sh --auto       # Linux / macOS\n.\\scripts\\dev-cleanup.ps1 -Mode auto  # Windows\n```\n\nFull strategy + thresholds in [`docs/DEVELOPMENT.md`](docs/DEVELOPMENT.md).\n\n#### Windows — extra prereqs before `cargo build`\n\nThe default `rustup` host on Windows is `stable-x86_64-pc-windows-gnu`, which depends on `dlltool.exe` from MinGW-w64 binutils — and `dlltool.exe` is **not** shipped with the rustup toolchain. A fresh `cargo build` will fail with `error: error calling dlltool 'dlltool.exe': program not found`. Pick one of:\n\n- **MSVC (recommended):** `rustup default stable-x86_64-pc-windows-msvc`, then install [\"Build Tools for Visual Studio\"](https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022) and tick the **Desktop development with C++** workload.\n- **GNU:** install MinGW-w64 (e.g. `winget install MartinStorsjo.LLVM-MinGW`) so `dlltool.exe` lands on `PATH`.\n\nCommon gotcha: Git Bash's `C:\\Program Files\\Git\\usr\\bin\\link.exe` (a coreutils tool) shadows MSVC's `link.exe` on `PATH` and breaks the MSVC linker with `link: extra operand …rcgu.o`. Reorder `PATH` so the MSVC `link.exe` wins, or run the build from a \"x64 Native Tools Command Prompt for VS\" shell.\n\n### Pre-built binaries\n\nEach tagged release ships pre-built binaries for x86_64 Linux, x86_64 macOS, aarch64 macOS (Apple Silicon), and x86_64 Windows (MSVC) on the [Releases page](https://github.com/agustincbajo/Coral/releases). Linux/macOS ship as `.tar.gz`, Windows as `.zip`. Each has a `.sha256` sidecar. Download, verify, extract `coral` (or `coral.exe`), place it on your `$PATH`. For one-liner automation see [One-line installer](#one-line-installer-linuxmacoswindows) above.\n\n```bash\n# Replace VERSION and TARGET with the values for the release you want; e.g.\n#   VERSION=v0.40.2\n#   TARGET=aarch64-apple-darwin   # x86_64-apple-darwin, x86_64-unknown-linux-gnu, or x86_64-pc-windows-msvc\nVERSION=v0.40.2\nTARGET=aarch64-apple-darwin\ncurl -L -o coral.tar.gz \"https://github.com/agustincbajo/Coral/releases/download/${VERSION}/coral-${VERSION}-${TARGET}.tar.gz\"\nshasum -a 256 -c coral.tar.gz.sha256  # if you also downloaded the .sha256 sidecar\ntar -xzf coral.tar.gz\nsudo mv \"coral-${VERSION}-${TARGET}/coral\" /usr/local/bin/\ncoral --version\n```\n\n#### macOS — first run is blocked by Gatekeeper\n\nThe pre-built macOS tarballs are **ad-hoc signed** (free; just enough to satisfy the Apple Silicon kernel exec check) but **not notarized** (notarization requires a $99/year Apple Developer account, which Coral doesn't have yet). On first launch, macOS shows:\n\n> *\"No se ha abierto coral. Apple no ha podido verificar que coral no contenga software malicioso...\"*\n> *\"coral cannot be opened because Apple cannot check it for malicious software.\"*\n\nThis is expected — the binary is fine, Apple just hasn't been paid to vouch for it. Two ways to allow it:\n\n**Terminal (one line):**\n\n```bash\nxattr -d com.apple.quarantine /usr/local/bin/coral\n```\n\nThat removes the quarantine flag macOS pinned on the file when you downloaded it. After that, `coral --version` runs cleanly forever.\n\n**GUI (System Settings):**\n\n1. When the warning appears, click **Aceptar / Cancel** (do NOT click \"Trasladar a Papelera / Move to Trash\").\n2. Open **System Settings → Privacy & Security**.\n3. Scroll to the *Security* section — there's a \"coral was blocked...\" line with an **\"Open Anyway / Abrir igualmente\"** button.\n4. Click it, confirm once more, and Coral opens. macOS remembers the exception.\n\nEither of these is a one-time step per release. To skip it entirely, install via `cargo install --locked --git ...` instead — `cargo` builds the binary on your machine, so Gatekeeper has no quarantine flag to apply.\n\n---\n\n## Quickstart\n\nFive entry points, in increasing scope. Each is a copy-paste sequence that\nends in something you can show your team. Start at the one that matches\nyour project shape; the rest layer on top.\n\n| Scope | Section | Time |\n|---|---|---|\n| One repo, just the wiki | [Single-repo](#quickstart--single-repo-2-minutes) | 2 min |\n| N repos with a manifest | [Multi-repo](#quickstart--multi-repo-5-minutes) | 5 min |\n| Wiki + dev env + tests | [Environments + tests](#quickstart--environments--tests) | 10 min |\n| Plug into a coding agent | [MCP server](#quickstart--mcp-server-for-coding-agents) | 3 min |\n| Curate sessions into the wiki | [Session capture + distill](#quickstart--capture-and-distill-agent-sessions) | 10 min |\n\n### Quickstart — single-repo (2 minutes)\n\nThe v0.15 workflow still works exactly as before — no `coral.toml` needed.\n\n```bash\ncd /path/to/your/repo\ncoral init                              # scaffold .wiki/ + auto-configure provider\ncoral bootstrap --apply                 # first-time wiki compilation (LLM)\ncoral ingest --apply                    # incremental updates on subsequent pushes\ncoral query \"how does authentication work?\"\ncoral status                            # daily-use dashboard\n```\n\nFull reference: [docs/USAGE.md](docs/USAGE.md), [docs/TUTORIAL.md](docs/TUTORIAL.md).\n\n---\n\n### Quickstart — multi-repo (5 minutes)\n\n```bash\nmkdir orchestra && cd orchestra\ncoral project new orchestra              # creates coral.toml + coral.lock + .wiki/\ncoral project add api    --url git@github.com:acme/api.git    --tags service team:platform\ncoral project add shared --url git@github.com:acme/shared.git --tags library\ncoral project add worker --url git@github.com:acme/worker.git \\\n                         --tags service team:data \\\n                         --depends-on api shared\ncoral project sync                       # parallel git clone via rayon\ncoral project graph --format mermaid     # render dependency graph (renders inline in GitHub Markdown)\ncoral project doctor                     # drift / missing clones / stale lockfile entries\ncoral ingest --apply                     # ingest aggregated wiki across all 3 repos\ncoral query \"how does worker talk to api\"\n```\n\nA `coral.toml` looks like this:\n\n```toml\napiVersion = \"coral.dev/v1\"\n\n[project]\nname = \"orchestra\"\n\n[project.toolchain]\ncoral = \"0.19.0\"                         # pin so cross-team workflows are reproducible\n\n[project.defaults]\nref           = \"main\"\nremote        = \"github\"\npath_template = \"repos/{name}\"\n\n[remotes.github]\nfetch = \"git@github.com:acme/{name}.git\"\n\n[[repos]]\nname = \"api\"\nref  = \"release/v3\"\ntags = [\"service\", \"team:platform\"]\n\n[[repos]]\nname       = \"worker\"\nremote     = \"github\"\ntags       = [\"service\", \"team:data\"]\ndepends_on = [\"api\"]\n```\n\nThe `[remotes.<name>]` template + `defaults.remote` pattern (borrowed from Google's [git-repo](https://gerrit.googlesource.com/git-repo/+/master/docs/manifest-format.md) tool) keeps the manifest concise even with 20+ repos in the same org.\n\n---\n\n### Quickstart — environments + tests\n\nAfter `coral project new`, declare a `[[environments]]` block:\n\n```toml\n[[environments]]\nname            = \"dev\"\nbackend         = \"compose\"              # compose | kind | tilt (only compose in v0.19)\nmode            = \"managed\"              # managed: Coral generates docker-compose.yml; adopt: bring your own\ncompose_command = \"auto\"                 # auto-detects docker compose v2 / docker-compose v1 / podman compose\nproduction      = false                  # set true to require --yes on `down`/`exec`/destructive ops\n\n# Services hang off `[environments.services.<name>]` — note the\n# parent table name is `environments` (NOT `environments.dev`)\n# because `[[environments]]` already opened the dev block.\n\n[environments.services.api]\nkind       = \"real\"\nrepo       = \"api\"                       # references [[repos]].name\nbuild      = { dockerfile = \"Dockerfile\", target = \"dev\" }\nports      = [3000]\ndepends_on = [\"db\"]\n\n[environments.services.api.healthcheck]\nkind = \"http\"\npath = \"/health\"\nexpect_status = 200\n\n[environments.services.db]\nkind  = \"real\"\nimage = \"postgres:16\"\nports = [5432]\n\n[environments.services.db.healthcheck]\nkind = \"tcp\"\nport = 5432\n```\n\nFor multiple environments, repeat the `[[environments]]` block (each entry gets its own `name`); the `[environments.services.*]` tables apply to whichever array entry is currently open.\n\nThen bring it up and run tests:\n\n```bash\ncoral up --env dev                       # docker compose up -d --wait, with healthcheck loop\ncoral env status --format markdown       # | service | state | health | restarts | ports |\ncoral env logs api --tail 100\ncoral verify                             # liveness only, <30s — exits non-zero if any healthcheck fails\ncoral test --tag smoke                   # functional smoke tests, <2min\ncoral test --format junit > junit.xml    # consumed by GitHub Actions reporter / CircleCI / Jenkins\ncoral down                               # tear down\n```\n\n### Live reload (`coral up --watch`, v0.21.2+)\n\nDeclare what to sync, rebuild, or restart on file changes:\n\n```toml\n[environments.services.api.watch]\nrebuild      = [\"./Dockerfile\", \"./go.sum\"]\nrestart      = [\"./config.yaml\"]\ninitial_sync = true                       # compose ≥ 2.27 — fires once on attach\n\n[[environments.services.api.watch.sync]]\npath   = \"./src\"\ntarget = \"/app/src\"\n\n[[environments.services.api.watch.sync]]\npath   = \"./templates\"\ntarget = \"/app/templates\"\n```\n\nThen:\n\n```bash\ncoral up --watch --env dev               # up -d --wait, then `compose watch` foreground until Ctrl-C\ncoral env watch --env dev                # alias for `coral up --watch`\n```\n\n`compose watch` streams sync events (`syncing X files to Y`, `rebuilding service Z`) to your terminal — same UX as `tilt up` or `skaffold dev`. Ctrl-C tears the watch subprocess down cleanly without killing the running containers (`coral down` does that). At least one service must declare `[services.<name>.watch]`; running `--watch` against a manifest with no watch blocks fails fast with an actionable error.\n\n> **macOS caveat.** `compose watch` on macOS hits an upstream Docker fsevents flakiness — sometimes sync events stop firing after long sessions, or files on case-sensitive volumes are ignored. Tracked at [docker/for-mac#7832](https://github.com/docker/for-mac/issues/7832). Coral emits a one-line `WARNING:` to stderr on macOS so the issue is never silent. Workaround when sync stalls: restart Docker Desktop.\n\nAuthor tests as YAML in `.coral/tests/*.yaml`:\n\n```yaml\nname: api smoke\nservice: api\ntags: [smoke]\nretry: { max: 3, backoff: exponential, on: [\"5xx\"] }\nsteps:\n  - http: GET /users\n    expect:\n      status: 200\n      body_contains: \"users\"\n  - http: POST /users\n    body: { name: \"test\" }\n    capture: { user_id: \"$.id\" }\n    expect:\n      status: 201\n  - http: GET /users/${user_id}           # ${var} substitution from previous capture\n    expect:\n      status: 200\n      snapshot: \"fixtures/user.json\"      # snapshot assertion; --update-snapshots accepts new outputs\n  - exec: [\"psql\", \"-U\", \"postgres\", \"-c\", \"select count(*) from users\"]\n    expect:\n      exit_code: 0\n      stdout_contains: \"1\"\n```\n\nOr in `.hurl` syntax (one block per request, no extra metadata required):\n\n```hurl\n# coral: name=api-smoke service=api tags=smoke,api\nGET /health\nHTTP 200\n\nGET /users\nAuthorization: Bearer test-token\nHTTP 200\n[Asserts]\njsonpath \"$.users\" exists\n```\n\nOr auto-generate them from your OpenAPI spec — **no LLM, deterministic**:\n\n```bash\ncoral test-discover                              # print summary\ncoral test-discover --emit yaml                  # emit YAML to stdout\ncoral test-discover --commit                     # write under .coral/tests/discovered/\ncoral test --include-discovered                  # include discovered cases in the run\n```\n\n### Multi-repo interface change detection\n\nThe single most expensive bug in microservice testing: service A changes its OpenAPI, breaks service B's expectations, and you only find out 20 minutes into a CI run when the runtime test fails with a generic 404. **`coral contract check`** prevents this by diffing each consumer's `.coral/tests/` against each provider's `openapi.yaml` *before* the test environment is even brought up:\n\n```bash\ncoral contract check                  # markdown summary; exit 0 if only warnings\ncoral contract check --strict         # fail on any finding (CI gate)\ncoral contract check --format json    # CI-friendly machine-readable output\n```\n\nWhat it detects (deterministic, no LLM):\n\n| Drift | Severity | Example |\n|---|---|---|\n| **Unknown endpoint** | Error | worker tests `GET /users/{id}` but api removed it |\n| **Unknown method** | Error | worker tests `POST /users` but api only declares `GET /users` |\n| **Status drift** | Warning (Error in `--strict`) | worker expects `200` but api now documents only `201` |\n| **Missing provider spec** | Warning | worker `depends_on api` but no `openapi.yaml` at `repos/api/` |\n\nCoverage tested in [`crates/coral-cli/tests/multi_repo_interface_change.rs`](crates/coral-cli/tests/multi_repo_interface_change.rs) — 8 end-to-end scenarios. Both YAML and Hurl test files are scanned. Path matching honors OpenAPI `{param}` placeholders against consumer-side concrete paths and `${var}` runtime substitutions.\n\nFor Pact-style consumer-driven contracts with a `coral.contracts.lock` and `--can-i-deploy`, see the v0.20+ roadmap.\n\n---\n\n### Quickstart — MCP server for coding agents\n\nCoral exposes the wiki + manifest + lockfile + test results as a [Model Context Protocol](https://modelcontextprotocol.io/) server — any MCP-speaking agent (Claude Code, Cursor, Continue, Cline, Goose, Codex, Copilot, …) can read it cross-session.\n\n```bash\ncoral mcp serve                                  # default: stdio transport, --read-only\n```\n\nWire it into Claude Code with a `.claude/mcp.json` snippet (see [docs/CLAUDE_CODE.md](docs/CLAUDE_CODE.md) for the full setup):\n\n```json\n{\n  \"mcpServers\": {\n    \"coral\": {\n      \"command\": \"coral\",\n      \"args\": [\"mcp\", \"serve\"]\n    }\n  }\n}\n```\n\nOr generate the agent instruction files directly (deterministic, no LLM):\n\n```bash\ncoral export-agents --format agents-md       --write    # writes AGENTS.md\ncoral export-agents --format claude-md       --write    # writes CLAUDE.md\ncoral export-agents --format cursor-rules    --write    # writes .cursor/rules/coral.mdc\ncoral export-agents --format copilot         --write    # writes .github/copilot-instructions.md\ncoral export-agents --format llms-txt        --write    # writes llms.txt\n```\n\n**Why deterministic templates instead of LLM-generated?** Empirical work on context files (and [Anthropic's context-engineering guidance](https://www.anthropic.com/engineering/context-engineering)) has consistently found that LLM-synthesized `AGENTS.md` files degrade agent task success vs. human-curated or template-rendered ones. Coral's templates pull structured data from `coral.toml` (project name, repos, dependencies) — not synthesized prose. Richer manifest blocks (`[project.agents_md]`, `[hooks]`) are on the v0.20+ roadmap; today the renderer reads only the fields that ship parsed.\n\nFor prompt-paste workflows where you don't have an MCP-speaking client:\n\n```bash\ncoral context-build --query \"how does authentication work\" --budget 50000 > context.md\n# Pastes a curated, budget-bounded markdown blob ready for any prompt.\n```\n\nThe loader uses TF-IDF ranking + backlink BFS + greedy fill under your token budget, sorted by `(confidence desc, body length asc)` so the most-trusted concise sources lead.\n\n---\n\n### Quickstart — capture and distill agent sessions\n\n**Shipped in v0.20.0** ([#16](https://github.com/agustincbajo/Coral/issues/16)). Coral can now fold the conversations that produced your wiki *back into* the wiki — agent transcripts (Claude Code today; Cursor and ChatGPT tracked) become curated synthesis pages. The flow is opt-in at every step and gated by the same trust-by-curation contract that governs `coral test generate` output.\n\n```bash\n# 1. Capture the most-recent Claude Code session whose `cwd` matches this repo.\n#    Privacy scrubber is on by default — API keys, JWTs, AWS creds, etc.\n#    are replaced with [REDACTED:<kind>] markers before bytes hit disk.\ncoral session capture --from claude-code\n# captured 5c359daf-… (412 messages, 7 redactions)\n#   → .coral/sessions/2026-05-08_claude-code_a1b2c3d4.jsonl\n\n# 2. Inspect captures.\ncoral session list\ncoral session show 5c359daf\n\n# 3. Distill into wiki-shaped synthesis pages (one LLM call).\n#    Pages always land as `reviewed: false` — `coral lint` blocks the commit\n#    until a human flips the flag.\ncoral session distill 5c359daf --apply\n# → .coral/sessions/distilled/<slug>.md      (always)\n# → .wiki/synthesis/<slug>.md                (with --apply, also reviewed: false)\n\n# 4. Review the page in your editor, flip `reviewed: true`, commit.\n$EDITOR .wiki/synthesis/<slug>.md\n\n# 5. (Optional) drop the raw transcript once curated.\ncoral session forget 5c359daf --yes\n```\n\nStorage layout: raw `.jsonl` and `index.json` are gitignored (added to `.gitignore` automatically by `coral init`); curated `.wiki/synthesis/*.md` ships in git. The `.coral/sessions/distilled/` mirror is also gitignored — it's a holding cell, not the canonical wiki.\n\nPrivacy posture and the full design-question rationale live in [docs/SESSIONS.md](docs/SESSIONS.md). TL;DR:\n\n- Scrubber is on by default. Opt-out requires both `--no-scrub` AND `--yes-i-really-mean-it`.\n- Distilled pages always carry `reviewed: false`. `coral lint --rule unreviewed-distilled` raises Critical and the bundled pre-commit hook blocks the commit.\n- Cross-format support is staged: Claude Code first; `--from cursor` and `--from chatgpt` exist as CLI flags but currently emit a clear \"not yet implemented; track #16\" error.\n\n### Patch mode (`--as-patch`, v0.21.3+)\n\nDefault `coral session distill <id>` is **option (a) / page-emit**: 1–3 NEW synthesis pages land under `.coral/sessions/distilled/<slug>.md` (and at `.wiki/synthesis/<slug>.md` with `--apply`). When the session's insight is a small **edit to an EXISTING page** rather than a whole new page, that's the wrong shape.\n\nv0.21.3 adds an opt-in `--as-patch` flag — **option (b) / patch-emit**. Instead of synthesis pages, the LLM proposes 1–N **unified-diff patches** against existing `.wiki/<slug>.md` pages.\n\n```bash\n# 1. Capture as before.\ncoral session capture --from claude-code\n\n# 2. Patch-emit. Top-K=10 BM25-ranked candidate pages from .wiki/ are\n#    surfaced in the prompt by default; tune with --candidates N (or 0\n#    to skip candidate collection entirely).\ncoral session distill 5c359daf --as-patch --candidates 10\n# distilled 5c359daf… → 2 patch(es):\n#   0. modules/authentication: The session revealed JWT refresh uses sliding window\n#   1. modules/rate-limit: Per-tenant counters, not global\n# written:\n#   - .coral/sessions/patches/5c359daf-0.patch\n#   - .coral/sessions/patches/5c359daf-0.json\n#   - .coral/sessions/patches/5c359daf-1.patch\n#   - .coral/sessions/patches/5c359daf-1.json\n\n# 3. Review each .patch by eye, OR pre-validate with --apply.\ncoral session distill 5c359daf --as-patch --apply\n# applied:\n#   - .wiki/modules/authentication.md (reviewed: false)\n#   - .wiki/modules/rate-limit.md (reviewed: false)\n```\n\n**Validation pipeline** — every patch passes through this gauntlet BEFORE any file lands:\n\n1. **Slug allow-list.** Each `/`-separated component of `target_slug` must pass `is_safe_filename_slug` (kebab/snake-case ASCII, no `..`, no leading `.`, no shell metacharacters).\n2. **Wiki existence.** The resolved page MUST exist in `list_page_paths(.wiki)`. Patches against non-existent pages reject at parse time.\n3. **Diff header agreement.** The `--- a/<X>.md` and `+++ b/<X>.md` headers must agree with `target_slug`. Mismatches reject at parse time.\n4. **`git apply --check`.** Every patch is dry-run-validated against `project_root` via `git apply --check --unsafe-paths --directory=.wiki <patch>`. (`--unsafe-paths` permits paths outside the index — NOT untrusted paths. By the time we shell out, the slug is already allow-list-validated.)\n\n**Pre-apply atomicity** — if ANY patch in the set fails its check, NO files are written and the command exits non-zero with the patch index + git stderr verbatim. This is the same all-or-nothing contract option (a) has always provided.\n\n**Sidecar `.json` shape:**\n\n```json\n{\n  \"target_slug\": \"modules/authentication\",\n  \"rationale\": \"The session revealed JWT refresh uses a sliding window…\",\n  \"prompt_version\": 2,\n  \"runner_name\": \"claude\",\n  \"session_id\": \"5c359daf-…\",\n  \"captured_at\": \"2026-05-08T10:00:00+00:00\",\n  \"reviewed\": false\n}\n```\n\n**`--apply` semantics** — Coral OWNS the `reviewed: false` flip. After each `git apply` succeeds, Coral re-reads the touched page, sets `frontmatter.extra[\"reviewed\"] = false`, and re-writes. The LLM's job is body content; the trust gate is Coral's job. `coral lint --rule unreviewed-distilled` then blocks the commit until a human flips it.\n\n**Default vs. patch mode in one line:** if the LLM has something *new* to say (a clarifying paragraph, a counter-intuitive finding, an architectural note that didn't exist before) → page mode. If the LLM has a small surgical fix (a corrected line, an added caveat, a clarified sentence) → patch mode.\n\n**`forget` cleanup** — `coral session forget <id>` sweeps both `distilled_outputs` (page-mode artifacts) AND `patch_outputs` (patch-mode artifacts) from `.coral/sessions/`. **`.wiki/` mutations from `--apply --as-patch` are NOT undone** — distill-as-patch's apply is one-way (the user owns the wiki post-apply).\n\n---\n\n## Cookbook — common workflows\n\nReal-world recipes that show how the layers compose. Each one is copy-paste-ready — every command has been exercised against the test suite or in dogfooding.\n\n### Recipe 1 — Stand up a new microservices project from zero\n\nYou have nothing. You want a multi-repo project with wiki, dev environment, and smoke tests.\n\n```bash\nmkdir orchestra && cd orchestra\ngit init -q && git commit --allow-empty -qm \"init\"\n\n# 1. Multi-repo manifest\ncoral project new orchestra\ncoral project add api    --remote github --tags service,team:platform\ncoral project add worker --remote github --tags service,team:data\ncoral project add shared --remote github --tags library\n\n# 2. Resolve every repo's URL via the [remotes.github] template,\n#    parallel-clone, write coral.lock with resolved SHAs.\ncoral project sync\n\n# 3. Aggregated wiki — Coral compiles a Markdown page per concept\n#    cross-repo. Slugs become `<repo>/<slug>` automatically.\ncoral bootstrap --apply\n\n# 4. Verify everything's coherent\ncoral lint --severity critical          # exits 0 → ready to ship\ncoral status --format markdown          # daily-use dashboard\n```\n\nAfter this you have `coral.toml` + `coral.lock` + `repos/{api,worker,shared}/` + `.wiki/` + `.coral/`. Commit them all (`.gitignore` for `repos/` if you don't want to vendor — `coral project sync` re-clones on demand).\n\n### Recipe 2 — Migrate from raw `docker-compose.yml`\n\nYou already have a `docker-compose.yml` and don't want to author the `[[environments]]` block from scratch.\n\n```bash\ncoral env import docker-compose.yml > /tmp/imported.toml\n# Review the output. Things Coral couldn't translate cleanly land as\n# `# TODO:` comments — addresses long-form depends_on, list-form\n# environment, port ranges, extends/profiles/volumes/networks.\n\n# Paste the contents into your coral.toml as a top-level [[environments]]\n# block. Then bring it up:\ncoral up --env dev\ncoral verify                            # runs the imported healthchecks\n```\n\nThe importer is **conservative + advisory**. Only fields that round-trip cleanly through `EnvironmentSpec` are emitted. Heuristics infer `kind = \"http\"` from `CMD [\"curl\", \"-f\", \"http://.../health\"]` patterns and `kind = \"exec\"` from arbitrary `CMD-SHELL` lines via `sh -c`. Compose duration strings (`5s`, `1m30s`, `2h`) parse to seconds.\n\n### Recipe 3 — Onboard a new contributor in 30 seconds\n\nThe wiki is the persistent memory. Use it.\n\n```bash\n# 1. Generate a personalized reading path. The runner picks 5–10 pages\n#    in dependency order based on the profile.\ncoral onboard --profile backend --apply\n\n# 2. Or, agent-friendly: dump a curated context-budgeted bundle.\ncoral context-build --query \"how does the auth flow work\" --budget 80000 > context.md\n# Paste context.md into Claude Code, Cursor, ChatGPT, anything with a\n# context window — the bundle sorts by (confidence desc, length asc)\n# under the budget cap. No LLM was invoked to assemble it.\n\n# 3. For a structured first day:\ncoral export-agents --format claude-md --write    # CLAUDE.md\ncoral export-agents --format cursor-rules --write # .cursor/rules/coral.mdc\ncoral export-agents --format llms-txt --write     # llms.txt\n```\n\nThe agent-instruction files are **manifest-driven, not LLM-driven** — they render deterministically from `[project]`, `[[repos]]`, `[hooks]` (when present) so re-running produces byte-identical output. Empirical context-engineering work (incl. [Anthropic's published guidance](https://www.anthropic.com/engineering/context-engineering)) has consistently found LLM-synthesised AGENTS.md files degrade agent task success vs. deterministic templates.\n\n### Recipe 4 — Cross-repo contract testing\n\nCatch interface drift between a provider's `openapi.yaml` and a consumer's `.coral/tests/` BEFORE the test environment even comes up.\n\n```bash\n# Setup: provider repo declares its API; consumer repo declares its\n# expectations as test fixtures.\necho '\nopenapi: 3.0.0\ninfo: { title: api, version: 1.0 }\npaths:\n  /users:\n    get:\n      responses: { \"200\": { description: ok } }\n' > repos/api/openapi.yaml\n\nmkdir -p repos/worker/.coral/tests\necho '\nname: worker-against-api\nservice: worker\nsteps:\n  - http: GET /users\n    expect: { status: 200 }\n' > repos/worker/.coral/tests/api.yaml\n\n# Drift detection — deterministic, no LLM. Use --strict to gate CI.\ncoral contract check --strict --format json > contract-report.json\n# exit 0 → consumer + provider agree\n# exit non-zero → drift report with structured findings\n```\n\n`coral contract check` walks every `[[repos]] depends_on` edge, parses the upstream's OpenAPI spec, and diffs against every `.coral/tests/**` reference (yaml + hurl). Findings include `UnknownEndpoint`, `UnknownMethod`, `StatusDrift`, `MissingProviderSpec`, `MalformedProviderSpec`. Generates the same JSON shape as `coral test --format junit` so existing CI reporters can consume it.\n\n### Recipe 5 — Continuous wiki maintenance with `coral ingest`\n\nWire `coral ingest` into your post-commit / post-merge workflow so the wiki stays current automatically.\n\n```bash\n# In CI (.github/workflows/ingest.yml):\n- name: Update Coral wiki\n  run: |\n    coral ingest --apply --severity warning  # idempotent; uses last_commit\n    if [ -n \"$(git status --porcelain .wiki/)\" ]; then\n      git config user.name  \"coral-bot\"\n      git config user.email \"coral-bot@example.com\"\n      git add .wiki/\n      git commit -m \"chore(wiki): coral ingest\"\n      git push\n    fi\n```\n\nOr with `--affected` for sub-repo selectivity in multi-repo projects:\n\n```bash\ncoral ingest --affected --since main~10 --apply\n# Only repos whose tip changed since main~10 are re-ingested,\n# DFS-walking depends_on so downstream consumers also refresh.\n```\n\n### Recipe 6 — Hardened production posture\n\nIf your wiki is committed to a public repo and accepts external PRs, lock it down.\n\n```bash\n# 1. Reject prompt-injection patterns at lint time. The scan is\n#    **on by default since v0.20.2** — keep it that way (or pass\n#    `--no-check-injection` only if you have a parallel mitigation).\ncoral lint --severity warning\n# Detects `<|system|>`, `</system>`, base64 runs >100 chars, unicode\n# bidi (U+202E) and tag chars (U+E0000–U+E007F), confidence-drop\n# instruction patterns.\n\n# 2. Tag every repo with a trust_level (manifest field, planned for\n#    v0.20+). Until then, gate `coral query` with --strict so cross-repo\n#    citations are required.\n\n# 3. Run `coral project doctor` on every PR.\ncoral project doctor --format json\n# Checks: clones present, ref drift, uncommitted changes, lockfile\n# staleness, auth setup per remote.\n\n# 4. The CI workflow already runs cargo audit + cargo deny.\n#    Add a step that re-asserts no dependencies bring in unsafe\n#    licenses or known CVEs.\n```\n\n### Recipe 7 — Connect Coral to a coding agent\n\nSee the next section ([MCP client integration](#mcp-client-integration)) for vendor-specific configuration. Quick taste:\n\n```bash\n# Boot Coral as an MCP server (stdio transport, read-only by default).\ncoral mcp serve --transport stdio &\n\n# Write tools (run_test, up, down) are ENABLED by default since v0.41.\n# To disable them, pass `--no-write-tools`:\ncoral mcp serve --transport stdio --no-write-tools &\n```\n\n> **Transport status (v0.21.1+).** Both `--transport stdio` (the default — every shipped MCP client speaks it) and `--transport http --port <p>` (Streamable HTTP per MCP 2025-11-25) ship. HTTP defaults to binding `127.0.0.1` and validates `Origin` against `null` / `http://localhost*` / `http://127.0.0.1*` only — a DNS-rebinding mitigation. `--bind 0.0.0.0` is opt-in and emits a stderr warning banner. See [Security model for the HTTP transport](#security-model-for-the-http-transport) below for the full threat model.\n\nTest the boot manually:\n\n```bash\necho '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"resources/list\",\"params\":{}}' | coral mcp serve --transport stdio\n# → {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"resources\":[...6 catalog URIs...]}}\n```\n\n---\n\n## MCP client integration\n\nCoral speaks Model Context Protocol 2025-11-25. Below are copy-paste configs for the common clients.\n\n### Claude Code (`claude` CLI)\n\n**Preferred — install the Coral plugin.** Inside Claude Code:\n\n```\n/plugin marketplace add agustincbajo/Coral\n/plugin install coral@coral\n```\n\nThe plugin (defined in [`.claude-plugin/`](.claude-plugin/) in this repo) bundles three auto-invoked skills (`coral-bootstrap`, `coral-query`, `coral-onboard`), two slash commands (`/coral:coral-bootstrap`, `/coral:coral-status`), and registers the Coral MCP server automatically. After install, ask Claude *\"set up Coral for this repo\"* or any conceptual question about your code — the skills route it through the wiki. Plugin docs: [`.claude-plugin/README.md`](.claude-plugin/README.md).\n\n**Manual fallback** — edit `~/.claude/settings.json` (or `.claude/settings.json` in the project root) yourself:\n\n```json\n{\n  \"mcpServers\": {\n    \"coral\": {\n      \"command\": \"coral\",\n      \"args\": [\"mcp\", \"serve\", \"--transport\", \"stdio\"],\n      \"env\": {\n        \"RUST_LOG\": \"coral_mcp=info\"\n      }\n    }\n  }\n}\n```\n\nEither way, Claude Code can then read all 8 resources — `coral://manifest`, `coral://lock`, `coral://graph`, `coral://wiki/<repo>/<slug>`, `coral://wiki/_index`, `coral://stats`, `coral://test-report/latest`, `coral://contracts`, `coral://coverage` — and call the 7 read-only tools (`query`, `search`, `find_backlinks`, `affected_repos`, `verify`, `list_interfaces`, `contract_status`).\n\nWrite tools (`run_test`, `up`, `down`) are **enabled by default** since v0.41. To disable them:\n\n```json\n\"args\": [\"mcp\", \"serve\", \"--transport\", \"stdio\", \"--no-write-tools\"]\n```\n\nEvery write-tool invocation is logged to `.coral/audit.log` (rotates at 16 MiB).\n\n### Cursor\n\nIn Cursor's MCP settings (Cmd+, → MCP Servers):\n\n```json\n{\n  \"name\": \"coral\",\n  \"command\": \"coral mcp serve --transport stdio\",\n  \"cwd\": \"/absolute/path/to/your/project\"\n}\n```\n\nSame resource + tool catalog as Claude Code.\n\n### Continue\n\n`~/.continue/config.yaml`:\n\n```yaml\nmcpServers:\n  - name: coral\n    command: coral\n    args:\n      - mcp\n      - serve\n      - --transport\n      - stdio\n```\n\n### Cline\n\nCline reads `.cline/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"coral\": {\n      \"command\": \"coral\",\n      \"args\": [\"mcp\", \"serve\", \"--transport\", \"stdio\"]\n    }\n  }\n}\n```\n\n### Goose\n\n`~/.config/goose/config.yaml`:\n\n```yaml\nextensions:\n  coral:\n    type: stdio\n    cmd: coral mcp serve --transport stdio\n```\n\n### Generic JSON-RPC over stdio\n\nFor any client that speaks raw MCP JSON-RPC, `coral mcp serve --transport stdio` is the entry point. The server announces `protocolVersion: \"2025-11-25\"` in the `initialize` handshake and responds to `resources/list`, `resources/read`, `tools/list`, `tools/call`, `prompts/list`, `prompts/get`. Notifications (no `id` field) silently no-op per spec §4.1.\n\n### HTTP/SSE transport (v0.21.1+)\n\nStreamable HTTP per the MCP 2025-11-25 spec. Three endpoints under `/mcp`:\n\n| Method | Body / required headers | Server response |\n|---|---|---|\n| `POST /mcp` | JSON-RPC envelope + `Content-Type: application/json` + `Accept: application/json, text/event-stream` | `200 application/json` for single-answer; `204` for notification (no `id`) |\n| `GET /mcp` | `Accept: text/event-stream` | `200 text/event-stream` empty stream + `: keep-alive\\n\\n` heartbeat every 15s |\n| `DELETE /mcp` | `Mcp-Session-Id: <id>` | `204` if session existed; `404` otherwise |\n| `OPTIONS /mcp` | (CORS preflight) | `200` with `Access-Control-Allow-Methods: POST, GET, DELETE, OPTIONS` |\n\nWorked example (initialize):\n\n```bash\ncoral mcp serve --transport http --port 3737 &\ncurl -sS -X POST -H \"Content-Type: application/json\" \\\n  -H \"Accept: application/json\" \\\n  -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{}}' \\\n  http://127.0.0.1:3737/mcp\n# → {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"protocolVersion\":\"2025-11-25\",\"capabilities\":{...},\"serverInfo\":{\"name\":\"coral\",\"version\":\"0.21.1\"}}}\n# Response also carries: Mcp-Session-Id: <uuid-shaped opaque cookie>\n```\n\nEcho the `Mcp-Session-Id` cookie on subsequent POSTs so the server can correlate the conversation:\n\n```bash\ncurl -sS -X POST -H \"Content-Type: application/json\" \\\n  -H \"Accept: application/json\" \\\n  -H \"Mcp-Session-Id: <uuid from initialize>\" \\\n  -d '{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"resources/list\",\"params\":{}}' \\\n  http://127.0.0.1:3737/mcp\n```\n\nTear down explicitly with `DELETE`:\n\n```bash\ncurl -sS -X DELETE \\\n  -H \"Mcp-Session-Id: <uuid>\" \\\n  http://127.0.0.1:3737/mcp\n# → 204 No Content (session removed); subsequent DELETE on the same id returns 404.\n```\n\nDefault port is `3737`. `--port 0` asks the OS to pick a free port; the resolved port is logged to stderr (`coral mcp serve — l",
  "bytes": 60000,
  "sha": "860c1ba1e8acbd29fe6f95731766fbfbd05214e3ae7b692bd1558900a5e0422d",
  "repo_slug": "agustincbajo/coral",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/plg_agustincbajo_coral_coral_c438a4c2/readme"
}