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.
[](https://github.com/agustincbajo/Coral/actions/workflows/ci.yml)
[](https://github.com/agustincbajo/Coral/releases)
[](LICENSE)
[](rust-toolchain.toml)
[](https://modelcontextprotocol.io/)
[](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.

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

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

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

### 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