# Journey 21 — lean-md (Addon Integration) > lean-md is an **external lean-ctx addon** — a macro/directive Markdown renderer. > It lives in its own repository (`dasTholo/lean-md`) with its own release cycle. > This page documents how lean-ctx **integrates** the addon. The full `@directive` > catalog, engine spec, and E-constructs live in the addon repo, not here. --- ## 1. What lean-md is lean-md renders `.lmd.md` / `.lean-md` files: `@directive` calls plus a macro engine (`@define`/`@call`), container gating (`@if`/`@consumer`), and pipes (`@render`). Code-intel directives (`@read`/`@refactor`/`@search`/…) call lean-ctx `ctx_*` tools **over the wire** (CLI/MCP); the renderer itself is standalone (`rushdown` + `evalexpr`) with **no** lean-ctx crate dependency. Engine, full directive catalog, and spec: **https://github.com/dasTholo/lean-md**. ## 2. Installation ```bash lean-ctx addon add @dasTholo/lean-md # hosted pack (ctxpkg.com) lean-ctx addon add ./lean-ctx-addon.toml # local manifest (dev/test) ``` `addon add` resolves a local manifest first, then a hosted `ns/slug` pack, then the bundled registry slug. The bundled `lean-md` entry is **listed** — it makes the addon discoverable through `lean-ctx addon search`, it is not an install path. After install, restart the MCP client so the gateway catalog is re-read. The addon is spawned as a stdio gateway child; its tools (`ctx_md_render`, `ctx_md_check`) become reachable through the lean-ctx server. ## 3. Integration points in lean-ctx lean-ctx keeps its lmd surface deliberately small: `.lmd.md` is read **raw** (§3.1), the addon ships as a registry entry (§3.2), and the addon calls back through the stable `ctx_*` surface (§3.3). Everything else is the addon's. ### 3.1 Raw `.lmd.md` read (no in-tree rendering) `ctx_read` treats `.lmd.md` like any other file: it returns the **raw** bytes and never renders (a half-rendered body would be worse than none). Rendering is the addon's job, reached explicitly through its `ctx_md_render` / `ctx_md_check` tools once installed. lean-ctx carries **no** `.lmd.md` special-casing in `ctx_read`; the earlier auto-render delegation hook was reverse-cut before merge. Source: `rust/src/tools/registered/ctx_read.rs` (no lmd branch), gate test `rust/tests/ctx_read_lmd_md_raw.rs`. ### 3.2 Addon registry entry `rust/data/addon_registry.json` carries the **listed** `lean-md` entry (no runnable `[mcp]` command, no `[install]` block), so `core::addons::manifest::is_installable` reports `false` and the entry serves discovery only. The validator (`core::addons::registry::validate_entries`) requires a homepage for a listed entry. ### 3.3 ctx_* outbound surface = addon contract Every lean-md code-intel directive calls back into lean-ctx via `backend.call("ctx_*", …)`. That tool set (`ctx_read`, `ctx_refactor`, `ctx_search`, `ctx_outline`, `ctx_impact`, `ctx_repomap`, `ctx_review`, `ctx_routes`, `ctx_smells`, `ctx_architecture`, `ctx_graph`, `ctx_callgraph`, `ctx_knowledge`, `ctx_handoff`, `ctx_agent`, …) is a stable **outbound contract** and must stay registered. Only `ctx_md_render` / `ctx_md_check` are addon-provided and absent from lean-ctx. ## 4. Decoupling rationale (vs. main) lean-md was developed in-tree (phases 1–9) and then **reverse-cut** before merge: the in-tree engine never reaches `main`. The lmd-related deltas this branch lands in lean-ctx are integration-only. | Class | Change (vs. main) | Why | |---------|-------------------------------------------------------------------------|--------------------------------------------------| | removed | `.lmd.md` auto-render delegation in `ctx_read.rs` → **raw read** | no in-tree engine renders; the addon renders on request | | changed | `addon_registry.json`: `lmd` placeholder → **listed** `lean-md` entry | discoverability; install goes through the hosted pack | | added | generic `extension_registry::RenderTransform` trait + registry | infra for `@render type=`, not lmd-exclusive | | kept | ctx_* outbound tool surface | the addon calls them over the wire | | added | gate tests `reverse_cut_gate.rs`, `ctx_read_lmd_md_raw.rs` | enforce the cut invariant + raw read | The engine, full `@directive` catalog, E-constructs, and spec now live in `dasTholo/lean-md` and are **not** mirrored here. ## 5. See also - Addon repo (engine + full directive reference): https://github.com/dasTholo/lean-md - Addon manifest contract: `docs/contracts/addon-manifest-v1.md` (upstream) - MCP tool catalog: [`appendix-mcp-tools.md`](appendix-mcp-tools.md) - Decoupling design: https://github.com/dasTholo/lean-md (addon repo — hosts engine, spec & decoupling design)