Back to the catalog

coral

Coral turns any git repo into a queryable Karpathy-style LLM wiki (.wiki/), preserves a bi-temporal history of the codebase + the docs about

Open source Repository Open in the app JSON README (API)

About

Coral turns any git repo into a queryable Karpathy-style LLM wiki (.wiki/), preserves a bi-temporal history of the codebase + the docs about the codebase, and exposes it to Claude Code via an MCP server so you can ask architecture questions without re-reading the whole codebase. Five auto-invoked skills (bootstrap, query, onboard, ui, doctor) plus two deterministic slash commands cover the entire lifecycle: generate the wiki with cost-confirmed bootstrap, query it conversationally, onboard new contributors, browse a force- directed graph WebUI, or diagnose environment issues. A SessionStart hook reports repo state to Claude on every session open so the right next action is suggested without the user needing to know skill names. A 4-path provider mini-wizard (Anthropic API key / Gemini / Ollama / claude CLI) onboards users who don't have claude CLI yet. Single-binary distribution (~14 MiB stripped) with Sigstore provenance, cross-platform install (Linux / macOS / Windows), SLSA L3-equiv

Details

Kind
Plugins
Topic
AI, RAG & memory
Publisher
agustincbajo
Origin
marketplace
Category
ferramentas
Last push
2026-05-17T23:08:13Z
Repository state
ativo
Language
Rust
License
MIT
Added
2026-08-30 01:48:58
Updated
2026-08-30 01:48:58
Origin id
agustincbajo/coral/coral

README

# Coral

> **The project manifest for AI-era development.** Multi-repo wiki + dev environments + functional testing + Model Context Protocol server, in a single Rust binary.

[![CI](https://github.com/agustincbajo/Coral/actions/workflows/ci.yml/badge.svg)](https://github.com/agustincbajo/Coral/actions/workflows/ci.yml)
[![Release](https://img.shields.io/github/v/release/agustincbajo/Coral?display_name=tag)](https://github.com/agustincbajo/Coral/releases)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Rust](https://img.shields.io/badge/rust-1.89%2B-orange?logo=rust)](rust-toolchain.toml)
[![MCP](https://img.shields.io/badge/MCP-2025--11--25-blue?logo=anthropic)](https://modelcontextprotocol.io/)
[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/agustincbajo/Coral/badge)](https://scorecard.dev/viewer/?uri=github.com/agustincbajo/Coral)

Coral 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**.

> *"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."*

---

## Getting Started in 60 seconds

> *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).*

### The fast path — one line + zero pastes (`--with-claude-config`)

```bash
# 1. Install the Coral binary AND register the marketplace in this project.
curl -fsSL https://raw.githubusercontent.com/agustincbajo/Coral/main/scripts/install.sh \
  | bash -s -- --with-claude-config

# 2. Open Claude Code in this repo. Type anything ("hi", "set up coral",
#    "where do I start?"). Coral's CLAUDE.md routes Claude to suggest
#    the right next step (bootstrap, doctor, or a query).
```

On Windows:

```powershell
# Run from PowerShell — pins the binary under %LOCALAPPDATA%\Coral\bin.
iwr -useb https://raw.githubusercontent.com/agustincbajo/Coral/main/scripts/install.ps1 `
  | iex
# Then `coral self-register-marketplace` from inside the target repo.
```

### The default path — 3 paste lines

```bash
# 1. Install the Coral binary (no Claude Code config patch).
curl -fsSL https://raw.githubusercontent.com/agustincbajo/Coral/main/scripts/install.sh | bash

# 2. Paste these 3 lines into Claude Code (one at a time, `&&` chains
#    don't work in Claude Code's prompt parser):
/plugin marketplace add agustincbajo/Coral
/plugin install coral@coral
/reload-plugins

# 3. Type anything in Claude Code. CLAUDE.md + the SessionStart hook
#    route Claude from there.
```

### What happens next

1. The `SessionStart` hook runs `coral self-check --quick --format=json` and reports your repo state to Claude (silent, < 100 ms p95).
2. Claude's first response — to **any** prompt — follows the routing block in `CLAUDE.md`:
   - No `.wiki/` yet? → suggests `/coral:coral-bootstrap` (cost-confirmed).
   - No LLM provider configured? → suggests `/coral:coral-doctor` (4-path mini-wizard).
   - All set? → answers from your wiki via MCP.
3. **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.

### Don't have Claude Code yet?

You can drive the same onboarding from your shell — **fully autonomous, no wizard required** (v0.41+):

```bash
# One command does everything (recommended):
coral setup                # init + estimate + confirm + bootstrap + welcome

# After setup finishes:
coral tour                 # interactive 2-min walkthrough of features
coral query "how does authentication work?"
```

The `coral setup` flow:
1. Scans your repo (file count, LOC)
2. Shows a cost estimate with page count
3. Asks for one Y/n confirmation
4. Bootstraps all pages with per-page progress (`[3/24] ▶ Generating auth-middleware...`)
5. Runs `lint --fix` automatically
6. Shows a welcome screen with next steps

For granular control, the individual commands still work:

```bash
coral init                 # scaffolds .wiki/ + CLAUDE.md + .gitignore
coral bootstrap --estimate # see the upper-bound cost first
coral bootstrap --apply --max-cost=5.00
```

If `claude` isn't on your PATH, or you want a different provider:

```bash
coral init --provider claude_cli   # explicit provider (no auto-detect needed)
coral doctor --wizard              # interactive 4-path wizard (Anthropic API / Gemini / Ollama / claude CLI)
```

For the full install reference (flags, troubleshooting, uninstall, upgrade) see [`docs/INSTALL.md`](docs/INSTALL.md).

---

### Use it from Claude Code in one command

If 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:

```
/plugin marketplace add agustincbajo/Coral
/plugin install coral@coral
```

That'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.

Prereq: 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.

---

## Table of contents

**Getting started**
- [Getting Started in 60 seconds](#getting-started-in-60-seconds) (fast path + default 3-paste path)
- [What you get](#what-you-get) · [Why Coral](#why-coral) · [Install](#install)
- [Quickstart](#quickstart) (single-repo, multi-repo, environments+tests, MCP server, session-distill)

**Use it**
- [Cookbook — 7 common workflows](#cookbook--common-workflows)
- [MCP client integration](#mcp-client-integration) (Claude Code · Cursor · Continue · Cline · Goose · raw JSON-RPC · HTTP/SSE)
- [Output examples](#output-examples) — what each command actually prints

**Reference**
- [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)
- [Multi-provider LLM support](#multi-provider-llm-support) · [Auth setup](#auth-setup) · [Configuration](#configuration)

**Operations**
- [Backward compatibility](#backward-compatibility) · [Security model](#security-model) · [CI integration](#ci-integration) · [Performance](#performance) · [Testing & CI](#testing--ci)
- [Troubleshooting](#troubleshooting) · [FAQ](#faq) · [Glossary](#glossary)

**Project**
- [Architecture](#architecture) · [Comparison vs adjacent tools](#comparison-vs-adjacent-tools) · [Roadmap](#roadmap)
- [How Coral itself was built](#how-coral-itself-was-built) · [Releasing](#releasing) · [Contributing](#contributing) · [References](#references--related-work) · [License](#license)

---

## What you get

A 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:

| Layer | Commands | Since |
|---|---|---|
| **Wiki** | `init` `bootstrap` `ingest` `query` `lint` `consolidate` `stats` `sync` `onboard` `prompts` `search` `export` `notion-push` `validate-pin` `diff` `status` `history` | v0.1+ |
| **Multi-repo** | `project new/list/add/sync/doctor/lock/graph` | v0.16 |
| **Environments** | `up` `down` `env status/logs/exec/import/devcontainer emit` | v0.17, v0.19.7 (`import`), v0.21.0 (`devcontainer emit`) |
| **Functional testing** | `test` `test-discover` `verify` `contract check` | v0.18, v0.19 (`contract`) |
| **AI ecosystem** | `mcp serve` `export-agents` `context-build` | v0.19 |
| **Sessions** | `session capture/list/show/forget/distill` | v0.20 |
| **Deep Code Intelligence** | `index` `graph build/show/callers/callees/hot/impact/deps` `find` `embed` `implement run/plan/sketch/validate/apply/patterns` `stale` | v0.41 |

Plus:

- **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`.
- **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).
- **5 embeddings providers** (`Voyage`, `OpenAI`, `Anthropic`, `ONNX/nomic` local behind feature flag, `Mock`).
- **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`).
- **Hybrid search engine**: BM25 keyword (tantivy) + TF-IDF semantic + structural graph + vector embeddings — fused with weighted Reciprocal Rank Fusion (RRF, k=60).
- **2 storage backends** (JSON default, SQLite via `CORAL_EMBEDDINGS_BACKEND=sqlite`).
- **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.
- **5 export formats** for the wiki (`markdown-bundle`, `json`, `notion-json`, `jsonl`, `html`).
- **5 export formats** for AI agent instructions (`agents-md`, `claude-md`, `cursor-rules`, `copilot`, `llms-txt`) — manifest-driven, NOT LLM-driven.
- **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]`.
- **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.
- **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).
- **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.
- **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.

---

## WebUI (`coral ui serve`)

Since v0.32.0 Coral ships a modern React SPA embedded in the binary. Single command:

```bash
coral ui serve
# opens http://localhost:3838 in your browser
```

### The four views

**Pages** — filterable list with bi-temporal awareness, status & confidence overlays, Markdown detail panel.

![Pages view: filter sidebar + table of 20 wiki pages with type/status/confidence/backlinks columns](docs/assets/ui-pages-en.png)

**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.

![Graph view: ForceAtlas2 layout of 20 nodes coloured by status with bi-temporal slider](docs/assets/ui-graph-en.png)

**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.

![Query playground: textarea + Local/Global/Hybrid mode selector + LLM cost warning](docs/assets/ui-query-en.png)

**Manifest** — `coral.toml` + `coral.lock` + a live stats breakdown.

![Manifest view: 20 pages, 91% avg confidence, 46 backlinks, status & page-type distributions](docs/assets/ui-manifest-en.png)

### What's unique to Coral here

- **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.
- **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.
- **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.
- **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.

### Write tools in the WebUI

Since 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`).

### Why end-users don't need Node

The 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.

> **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.

Full docs: [`docs/UI.md`](docs/UI.md).

To opt out of the WebUI in a minimal install:

```bash
cargo install coral-cli --no-default-features --features mcp,cli
```

## Why Coral

Three problems in one tool.

### 1. The naive `AGENTS.md` problem

Giving 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.

**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.

| Aspect | Naive `AGENTS.md` | Coral wiki |
|---|---|---|
| Storage | Single growing file | Constellation of small Markdown pages |
| State | Implicit, drifts | Explicit, `last_updated_commit` per page |
| Lock-in | None | None — plain Markdown in Git |
| Auditability | Opaque | Each page cites verifiable `sources` |
| Maintenance | Manual | Incremental ingest on every push |
| Search | grep | TF-IDF default + Voyage embeddings opt-in |

### 2. The microservices problem

Most 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.

**How Coral mitigates it** — concrete mechanisms, not slogans:

- **`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.
- **`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.
- **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.
- **`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.
- **`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.
- **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.

The 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.

### 3. The functional testing problem

Unit 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.

**How Coral mitigates it** — the actual mechanisms:

- **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.
- **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.
- **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.
- **`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.
- **`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.
- **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."
- **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.

The 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."

> **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.

**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`.

---

## Install

### Prerequisites

- **Rust** 1.89+ (stable). Install via [rustup](https://rustup.rs/).
- **Git** 2.30+.
- **`curl`** (universally available; used by the test runner for HTTP probes — no libcurl FFI dep).
- **Optional:** `docker compose` v2.22+ (for `coral up` / `coral down` / `coral env *` and `coral verify`). `podman compose` and `docker-compose` v1 are also detected.
- **Optional:** [Claude Code CLI](https://claude.com/code) (`claude` in `$PATH`) for LLM-backed subcommands.

### One-line installer (Linux/macOS/Windows)

Fetches 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.

```bash
# Linux / macOS  (writes to /usr/local/bin or ~/.local/bin)
curl -fsSL https://raw.githubusercontent.com/agustincbajo/Coral/main/scripts/install.sh | bash
```

```powershell
# Windows  (writes to %LOCALAPPDATA%\Coral\bin and prepends it to user PATH)
iwr -useb https://raw.githubusercontent.com/agustincbajo/Coral/main/scripts/install.ps1 | iex
```

Pin 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.

> **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`.

### From a tagged release (recommended)

```bash
cargo install --locked --git https://github.com/agustincbajo/Coral --tag v0.40.2 coral-cli
```

(Replace `v0.40.2` with the latest tag from the [Releases page](https://github.com/agustincbajo/Coral/releases).)

### From `main` (latest)

```bash
cargo install --locked --git https://github.com/agustincbajo/Coral coral-cli
```

### From source (development)

```bash
git clone https://github.com/agustincbajo/Coral
cd Coral
./scripts/dev-setup.sh           # one-time: cargo-sweep, sccache, cargo-nextest
cargo build --release
./target/release/coral --version
```

Disk hygiene: `cargo build`/`cargo test` cycles inflate `target/`
fast (typical sustained dev session: ~5–8 GiB; a 7-release sprint
that forgets maintenance: ~45 GiB). One-liner umbrella:

```bash
./scripts/dev-cleanup.sh --auto       # Linux / macOS
.\scripts\dev-cleanup.ps1 -Mode auto  # Windows
```

Full strategy + thresholds in [`docs/DEVELOPMENT.md`](docs/DEVELOPMENT.md).

#### Windows — extra prereqs before `cargo build`

The 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:

- **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.
- **GNU:** install MinGW-w64 (e.g. `winget install MartinStorsjo.LLVM-MinGW`) so `dlltool.exe` lands on `PATH`.

Common 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.

### Pre-built binaries

Each 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.

```bash
# Replace VERSION and TARGET with the values for the release you want; e.g.
#   VERSION=v0.40.2
#   TARGET=aarch64-apple-darwin   # x86_64-apple-darwin, x86_64-unknown-linux-gnu, or x86_64-pc-windows-msvc
VERSION=v0.40.2
TARGET=aarch64-apple-darwin
curl -L -o coral.tar.gz "https://github.com/agustincbajo/Coral/releases/download/${VERSION}/coral-${VERSION}-${TARGET}.tar.gz"
shasum -a 256 -c coral.tar.gz.sha256  # if you also downloaded the .sha256 sidecar
tar -xzf coral.tar.gz
sudo mv "coral-${VERSION}-${TARGET}/coral" /usr/local/bin/
coral --version
```

#### macOS — first run is blocked by Gatekeeper

The 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:

> *"No se ha abierto coral. Apple no ha podido verificar que coral no contenga software malicioso..."*
> *"coral cannot be opened because Apple cannot check it for malicious software."*

This is expected — the binary is fine, Apple just hasn't been paid to vouch for it. Two ways to allow it:

**Terminal (one line):**

```bash
xattr -d com.apple.quarantine /usr/local/bin/coral
```

That removes the quarantine flag macOS pinned on the file when you downloaded it. After that, `coral --version` runs cleanly forever.

**GUI (System Settings):**

1. When the warning appears, click **Aceptar / Cancel** (do NOT click "Trasladar a Papelera / Move to Trash").
2. Open **System Settings → Privacy & Security**.
3. Scroll to the *Security* section — there's a "coral was blocked..." line with an **"Open Anyway / Abrir igualmente"** button.
4. Click it, confirm once more, and Coral opens. macOS remembers the exception.

Either 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.

---

## Quickstart

Five entry points, in increasing scope. Each is a copy-paste sequence that
ends in something you can show your team. Start at the one that matches
your project shape; the rest layer on top.

| Scope | Section | Time |
|---|---|---|
| One repo, just the wiki | [Single-repo](#quickstart--single-repo-2-minutes) | 2 min |
| N repos with a manifest | [Multi-repo](#quickstart--multi-repo-5-minutes) | 5 min |
| Wiki + dev env + tests | [Environments + tests](#quickstart--environments--tests) | 10 min |
| Plug into a coding agent | [MCP server](#quickstart--mcp-server-for-coding-agents) | 3 min |
| Curate sessions into the wiki | [Session capture + distill](#quickstart--capture-and-distill-agent-sessions) | 10 min |

### Quickstart — single-repo (2 minutes)

The v0.15 workflow still works exactly as before — no `coral.toml` needed.

```bash
cd /path/to/your/repo
coral init                              # scaffold .wiki/ + auto-configure provider
coral bootstrap --apply                 # first-time wiki compilation (LLM)
coral ingest --apply                    # incremental updates on subsequent pushes
coral query "how does authentication work?"
coral status                            # daily-use dashboard
```

Full reference: [docs/USAGE.md](docs/USAGE.md), [docs/TUTORIAL.md](docs/TUTORIAL.md).

---

### Quickstart — multi-repo (5 minutes)

```bash
mkdir orchestra && cd orchestra
coral project new orchestra              # creates coral.toml + coral.lock + .wiki/
coral project add api    --url git@github.com:acme/api.git    --tags service team:platform
coral project add shared --url git@github.com:acme/shared.git --tags library
coral project add worker --url git@github.com:acme/worker.git \
                         --tags service team:data \
                         --depends-on api shared
coral project sync                       # parallel git clone via rayon
coral project graph --format mermaid     # render dependency graph (renders inline in GitHub Markdown)
coral project doctor                     # drift / missing clones / stale lockfile entries
coral ingest --apply                     # ingest aggregated wiki across all 3 repos
coral query "how does worker talk to api"
```

A `coral.toml` looks like this:

```toml
apiVersion = "coral.dev/v1"

[project]
name = "orchestra"

[project.toolchain]
coral = "0.19.0"                         # pin so cross-team workflows are reproducible

[project.defaults]
ref           = "main"
remote        = "github"
path_template = "repos/{name}"

[remotes.github]
fetch = "git@github.com:acme/{name}.git"

[[repos]]
name = "api"
ref  = "release/v3"
tags = ["service", "team:platform"]

[[repos]]
name       = "worker"
remote     = "github"
tags       = ["service", "team:data"]
depends_on = ["api"]
```

The `[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.

---

### Quickstart — environments + tests

After `coral project new`, declare a `[[environments]]` block:

```toml
[[environments]]
name            = "dev"
backend         = "compose"              # compose | kind | tilt (only compose in v0.19)
mode            = "managed"              # managed: Coral generates docker-compose.yml; adopt: bring your own
compose_command = "auto"                 # auto-detects docker compose v2 / docker-compose v1 / podman compose
production      = false                  # set true to require --yes on `down`/`exec`/destructive ops

# Services hang off `[environments.services.<name>]` — note the
# parent table name is `environments` (NOT `environments.dev`)
# because `[[environments]]` already opened the dev block.

[environments.services.api]
kind       = "real"
repo       = "api"                       # references [[repos]].name
build      = { dockerfile = "Dockerfile", target = "dev" }
ports      = [3000]
depends_on = ["db"]

[environments.services.api.healthcheck]
kind = "http"
path = "/health"
expect_status = 200

[environments.services.db]
kind  = "real"
image = "postgres:16"
ports = [5432]

[environments.services.db.healthcheck]
kind = "tcp"
port = 5432
```

For multiple environments, repeat the `[[environments]]` block (each entry gets its own `name`); the `[environments.services.*]` tables apply to whichever array entry is currently open.

Then bring it up and run tests:

```bash
coral up --env dev                       # docker compose up -d --wait, with healthcheck loop
coral env status --format markdown       # | service | state | health | restarts | ports |
coral env logs api --tail 100
coral verify                             # liveness only, <30s — exits non-zero if any healthcheck fails
coral test --tag smoke                   # functional smoke tests, <2min
coral test --format junit > junit.xml    # consumed by GitHub Actions reporter / CircleCI / Jenkins
coral down                               # tear down
```

### Live reload (`coral up --watch`, v0.21.2+)

Declare what to sync, rebuild, or restart on file changes:

```toml
[environments.services.api.watch]
rebuild      = ["./Dockerfile", "./go.sum"]
restart      = ["./config.yaml"]
initial_sync = true                       # compose ≥ 2.27 — fires once on attach

[[environments.services.api.watch.sync]]
path   = "./src"
target = "/app/src"

[[environments.services.api.watch.sync]]
path   = "./templates"
target = "/app/templates"
```

Then:

```bash
coral up --watch --env dev               # up -d --wait, then `compose watch` foreground until Ctrl-C
coral env watch --env dev                # alias for `coral up --watch`
```

`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.

> **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.

Author tests as YAML in `.coral/tests/*.yaml`:

```yaml
name: api smoke
service: api
tags: [smoke]
retry: { max: 3, backoff: exponential, on: ["5xx"] }
steps:
  - http: GET /users
    expect:
      status: 200
      body_contains: "users"
  - http: POST /users
    body: { name: "test" }
    capture: { user_id: "$.id" }
    expect:
      status: 201
  - http: GET /users/${user_id}           # ${var} substitution from previous capture
    expect:
      status: 200
      snapshot: "fixtures/user.json"      # snapshot assertion; --update-snapshots accepts new outputs
  - exec: ["psql", "-U", "postgres", "-c", "select count(*) from users"]
    expect:
      exit_code: 0
      stdout_contains: "1"
```

Or in `.hurl` syntax (one block per request, no extra metadata required):

```hurl
# coral: name=api-smoke service=api tags=smoke,api
GET /health
HTTP 200

GET /users
Authorization: Bearer test-token
HTTP 200
[Asserts]
jsonpath "$.users" exists
```

Or auto-generate them from your OpenAPI spec — **no LLM, deterministic**:

```bash
coral test-discover                              # print summary
coral test-discover --emit yaml                  # emit YAML to stdout
coral test-discover --commit                     # write under .coral/tests/discovered/
coral test --include-discovered                  # include discovered cases in the run
```

### Multi-repo interface change detection

The 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:

```bash
coral contract check                  # markdown summary; exit 0 if only warnings
coral contract check --strict         # fail on any finding (CI gate)
coral contract check --format json    # CI-friendly machine-readable output
```

What it detects (deterministic, no LLM):

| Drift | Severity | Example |
|---|---|---|
| **Unknown endpoint** | Error | worker tests `GET /users/{id}` but api removed it |
| **Unknown method** | Error | worker tests `POST /users` but api only declares `GET /users` |
| **Status drift** | Warning (Error in `--strict`) | worker expects `200` but api now documents only `201` |
| **Missing provider spec** | Warning | worker `depends_on api` but no `openapi.yaml` at `repos/api/` |

Coverage 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.

For Pact-style consumer-driven contracts with a `coral.contracts.lock` and `--can-i-deploy`, see the v0.20+ roadmap.

---

### Quickstart — MCP server for coding agents

Coral 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.

```bash
coral mcp serve                                  # default: stdio transport, --read-only
```

Wire it into Claude Code with a `.claude/mcp.json` snippet (see [docs/CLAUDE_CODE.md](docs/CLAUDE_CODE.md) for the full setup):

```json
{
  "mcpServers": {
    "coral": {
      "command": "coral",
      "args": ["mcp", "serve"]
    }
  }
}
```

Or generate the agent instruction files directly (deterministic, no LLM):

```bash
coral export-agents --format agents-md       --write    # writes AGENTS.md
coral export-agents --format claude-md       --write    # writes CLAUDE.md
coral export-agents --format cursor-rules    --write    # writes .cursor/rules/coral.mdc
coral export-agents --format copilot         --write    # writes .github/copilot-instructions.md
coral export-agents --format llms-txt        --write    # writes llms.txt
```

**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.

For prompt-paste workflows where you don't have an MCP-speaking client:

```bash
coral context-build --query "how does authentication work" --budget 50000 > context.md
# Pastes a curated, budget-bounded markdown blob ready for any prompt.
```

The 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.

---

### Quickstart — capture and distill agent sessions

**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.

```bash
# 1. Capture the most-recent Claude Code session whose `cwd` matches this repo.
#    Privacy scrubber is on by default — API keys, JWTs, AWS creds, etc.
#    are replaced with [REDACTED:<kind>] markers before bytes hit disk.
coral session capture --from claude-code
# captured 5c359daf-… (412 messages, 7 redactions)
#   → .coral/sessions/2026-05-08_claude-code_a1b2c3d4.jsonl

# 2. Inspect captures.
coral session list
coral session show 5c359daf

# 3. Distill into wiki-shaped synthesis pages (one LLM call).
#    Pages always land as `reviewed: false` — `coral lint` blocks the commit
#    until a human flips the flag.
coral session distill 5c359daf --apply
# → .coral/sessions/distilled/<slug>.md      (always)
# → .wiki/synthesis/<slug>.md                (with --apply, also reviewed: false)

# 4. Review the page in your editor, flip `reviewed: true`, commit.
$EDITOR .wiki/synthesis/<slug>.md

# 5. (Optional) drop the raw transcript once curated.
coral session forget 5c359daf --yes
```

Storage 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.

Privacy posture and the full design-question rationale live in [docs/SESSIONS.md](docs/SESSIONS.md). TL;DR:

- Scrubber is on by default. Opt-out requires both `--no-scrub` AND `--yes-i-really-mean-it`.
- Distilled pages always carry `reviewed: false`. `coral lint --rule unreviewed-distilled` raises Critical and the bundled pre-commit hook blocks the commit.
- 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.

### Patch mode (`--as-patch`, v0.21.3+)

Default `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.

v0.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.

```bash
# 1. Capture as before.
coral session capture --from claude-code

# 2. Patch-emit. Top-K=10 BM25-ranked candidate pages from .wiki/ are
#    surfaced in the prompt by default; tune with --candidates N (or 0
#    to skip candidate collection entirely).
coral session distill 5c359daf --as-patch --candidates 10
# distilled 5c359daf… → 2 patch(es):
#   0. modules/authentication: The session revealed JWT refresh uses sliding window
#   1. modules/rate-limit: Per-tenant counters, not global
# written:
#   - .coral/sessions/patches/5c359daf-0.patch
#   - .coral/sessions/patches/5c359daf-0.json
#   - .coral/sessions/patches/5c359daf-1.patch
#   - .coral/sessions/patches/5c359daf-1.json

# 3. Review each .patch by eye, OR pre-validate with --apply.
coral session distill 5c359daf --as-patch --apply
# applied:
#   - .wiki/modules/authentication.md (reviewed: false)
#   - .wiki/modules/rate-limit.md (reviewed: false)
```

**Validation pipeline** — every patch passes through this gauntlet BEFORE any file lands:

1. **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).
2. **Wiki existence.** The resolved page MUST exist in `list_page_paths(.wiki)`. Patches against non-existent pages reject at parse time.
3. **Diff header agreement.** The `--- a/<X>.md` and `+++ b/<X>.md` headers must agree with `target_slug`. Mismatches reject at parse time.
4. **`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.)

**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.

**Sidecar `.json` shape:**

```json
{
  "target_slug": "modules/authentication",
  "rationale": "The session revealed JWT refresh uses a sliding window…",
  "prompt_version": 2,
  "runner_name": "claude",
  "session_id": "5c359daf-…",
  "captured_at": "2026-05-08T10:00:00+00:00",
  "reviewed": false
}
```

**`--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.

**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.

**`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).

---

## Cookbook — common workflows

Real-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.

### Recipe 1 — Stand up a new microservices project from zero

You have nothing. You want a multi-repo project with wiki, dev environment, and smoke tests.

```bash
mkdir orchestra && cd orchestra
git init -q && git commit --allow-empty -qm "init"

# 1. Multi-repo manifest
coral project new orchestra
coral project add api    --remote github --tags service,team:platform
coral project add worker --remote github --tags service,team:data
coral project add shared --remote github --tags library

# 2. Resolve every repo's URL via the [remotes.github] template,
#    parallel-clone, write coral.lock with resolved SHAs.
coral project sync

# 3. Aggregated wiki — Coral compiles a Markdown page per concept
#    cross-repo. Slugs become `<repo>/<slug>` automatically.
coral bootstrap --apply

# 4. Verify everything's coherent
coral lint --severity critical          # exits 0 → ready to ship
coral status --format markdown          # daily-use dashboard
```

After 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).

### Recipe 2 — Migrate from raw `docker-compose.yml`

You already have a `docker-compose.yml` and don't want to author the `[[environments]]` block from scratch.

```bash
coral env import docker-compose.yml > /tmp/imported.toml
# Review the output. Things Coral couldn't translate cleanly land as
# `# TODO:` comments — addresses long-form depends_on, list-form
# environment, port ranges, extends/profiles/volumes/networks.

# Paste the contents into your coral.toml as a top-level [[environments]]
# block. Then bring it up:
coral up --env dev
coral verify                            # runs the imported healthchecks
```

The 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.

### Recipe 3 — Onboard a new contributor in 30 seconds

The wiki is the persistent memory. Use it.

```bash
# 1. Generate a personalized reading path. The runner picks 5–10 pages
#    in dependency order based on the profile.
coral onboard --profile backend --apply

# 2. Or, agent-friendly: dump a curated context-budgeted bundle.
coral context-build --query "how does the auth flow work" --budget 80000 > context.md
# Paste context.md into Claude Code, Cursor, ChatGPT, anything with a
# context window — the bundle sorts by (confidence desc, length asc)
# under the budget cap. No LLM was invoked to assemble it.

# 3. For a structured first day:
coral export-agents --format claude-md --write    # CLAUDE.md
coral export-agents --format cursor-rules --write # .cursor/rules/coral.mdc
coral export-agents --format llms-txt --write     # llms.txt
```

The 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.

### Recipe 4 — Cross-repo contract testing

Catch interface drift between a provider's `openapi.yaml` and a consumer's `.coral/tests/` BEFORE the test environment even comes up.

```bash
# Setup: provider repo declares its API; consumer repo declares its
# expectations as test fixtures.
echo '
openapi: 3.0.0
info: { title: api, version: 1.0 }
paths:
  /users:
    get:
      responses: { "200": { description: ok } }
' > repos/api/openapi.yaml

mkdir -p repos/worker/.coral/tests
echo '
name: worker-against-api
service: worker
steps:
  - http: GET /users
    expect: { status: 200 }
' > repos/worker/.coral/tests/api.yaml

# Drift detection — deterministic, no LLM. Use --strict to gate CI.
coral contract check --strict --format json > contract-report.json
# exit 0 → consumer + provider agree
# exit non-zero → drift report with structured findings
```

`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.

### Recipe 5 — Continuous wiki maintenance with `coral ingest`

Wire `coral ingest` into your post-commit / post-merge workflow so the wiki stays current automatically.

```bash
# In CI (.github/workflows/ingest.yml):
- name: Update Coral wiki
  run: |
    coral ingest --apply --severity warning  # idempotent; uses last_commit
    if [ -n "$(git status --porcelain .wiki/)" ]; then
      git config user.name  "coral-bot"
      git config user.email "coral-bot@example.com"
      git add .wiki/
      git commit -m "chore(wiki): coral ingest"
      git push
    fi
```

Or with `--affected` for sub-repo selectivity in multi-repo projects:

```bash
coral ingest --affected --since main~10 --apply
# Only repos whose tip changed since main~10 are re-ingested,
# DFS-walking depends_on so downstream consumers also refresh.
```

### Recipe 6 — Hardened production posture

If your wiki is committed to a public repo and accepts external PRs, lock it down.

```bash
# 1. Reject prompt-injection patterns at lint time. The scan is
#    **on by default since v0.20.2** — keep it that way (or pass
#    `--no-check-injection` only if you have a parallel mitigation).
coral lint --severity warning
# Detects `<|system|>`, `</system>`, base64 runs >100 chars, unicode
# bidi (U+202E) and tag chars (U+E0000–U+E007F), confidence-drop
# instruction patterns.

# 2. Tag every repo with a trust_level (manifest field, planned for
#    v0.20+). Until then, gate `coral query` with --strict so cross-repo
#    citations are required.

# 3. Run `coral project doctor` on every PR.
coral project doctor --format json
# Checks: clones present, ref drift, uncommitted changes, lockfile
# staleness, auth setup per remote.

# 4. The CI workflow already runs cargo audit + cargo deny.
#    Add a step that re-asserts no dependencies bring in unsafe
#    licenses or known CVEs.
```

### Recipe 7 — Connect Coral to a coding agent

See the next section ([MCP client integration](#mcp-client-integration)) for vendor-specific configuration. Quick taste:

```bash
# Boot Coral as an MCP server (stdio transport, read-only by default).
coral mcp serve --transport stdio &

# Write tools (run_test, up, down) are ENABLED by default since v0.41.
# To disable them, pass `--no-write-tools`:
coral mcp serve --transport stdio --no-write-tools &
```

> **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.

Test the boot manually:

```bash
echo '{"jsonrpc":"2.0","id":1,"method":"resources/list","params":{}}' | coral mcp serve --transport stdio
# → {"jsonrpc":"2.0","id":1,"result":{"resources":[...6 catalog URIs...]}}
```

---

## MCP client integration

Coral speaks Model Context Protocol 2025-11-25. Below are copy-paste configs for the common clients.

### Claude Code (`claude` CLI)

**Preferred — install the Coral plugin.** Inside Claude Code:

```
/plugin marketplace add agustincbajo/Coral
/plugin install coral@coral
```

The 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).

**Manual fallback** — edit `~/.claude/settings.json` (or `.claude/settings.json` in the project root) yourself:

```json
{
  "mcpServers": {
    "coral": {
      "command": "coral",
      "args": ["mcp", "serve", "--transport", "stdio"],
      "env": {
        "RUST_LOG": "coral_mcp=info"
      }
    }
  }
}
```

Either 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`).

Write tools (`run_test`, `up`, `down`) are **enabled by default** since v0.41. To disable them:

```json
"args": ["mcp", "serve", "--transport", "stdio", "--no-write-tools"]
```

Every write-tool invocation is logged to `.coral/audit.log` (rotates at 16 MiB).

### Cursor

In Cursor's MCP settings (Cmd+, → MCP Servers):

```json
{
  "name": "coral",
  "command": "coral mcp serve --transport stdio",
  "cwd": "/absolute/path/to/your/project"
}
```

Same resource + tool catalog as Claude Code.

### Continue

`~/.continue/config.yaml`:

```yaml
mcpServers:
  - name: coral
    command: coral
    args:
      - mcp
      - serve
      - --transport
      - stdio
```

### Cline

Cline reads `.cline/mcp.json`:

```json
{
  "mcpServers": {
    "coral": {
      "command": "coral",
      "args": ["mcp", "serve", "--transport", "stdio"]
    }
  }
}
```

### Goose

`~/.config/goose/config.yaml`:

```yaml
extensions:
  coral:
    type: stdio
    cmd: coral mcp serve --transport stdio
```

### Generic JSON-RPC over stdio

For 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.

### HTTP/SSE transport (v0.21.1+)

Streamable HTTP per the MCP 2025-11-25 spec. Three endpoints under `/mcp`:

| Method | Body / required headers | Server response |
|---|---|---|
| `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`) |
| `GET /mcp` | `Accept: text/event-stream` | `200 text/event-stream` empty stream + `: keep-alive\n\n` heartbeat every 15s |
| `DELETE /mcp` | `Mcp-Session-Id: <id>` | `204` if session existed; `404` otherwise |
| `OPTIONS /mcp` | (CORS preflight) | `200` with `Access-Control-Allow-Methods: POST, GET, DELETE, OPTIONS` |

Worked example (initialize):

```bash
coral mcp serve --transport http --port 3737 &
curl -sS -X POST -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' \
  http://127.0.0.1:3737/mcp
# → {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2025-11-25","capabilities":{...},"serverInfo":{"name":"coral","version":"0.21.1"}}}
# Response also carries: Mcp-Session-Id: <uuid-shaped opaque cookie>
```

Echo the `Mcp-Session-Id` cookie on subsequent POSTs so the server can correlate the conversation:

```bash
curl -sS -X POST -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Mcp-Session-Id: <uuid from initialize>" \
  -d '{"jsonrpc":"2.0","id":2,"method":"resources/list","params":{}}' \
  http://127.0.0.1:3737/mcp
```

Tear down explicitly with `DELETE`:

```bash
curl -sS -X DELETE \
  -H "Mcp-Session-Id: <uuid>" \
  http://127.0.0.1:3737/mcp
# → 204 No Content (session removed); subsequent DELETE on the same id returns 404.
```

Default port is `3737`. `--port 0` asks the OS to pick a free port; the resolved port is logged to stderr (`coral mcp serve — l

More