chore: import upstream snapshot with attribution
CI / Clippy (push) Failing after 15m13s
CI / Test (ubuntu-latest) (push) Failing after 16m1s
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Build (no embeddings / no ORT) (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Cookbook (Node) (push) Has been cancelled
CI / Pi Extension (Node) (push) Has been cancelled
CI / Rust SDK (lean-ctx-client) (push) Has been cancelled
CI / Embed SDK (lean-ctx-sdk) (push) Has been cancelled
CI / Python SDK (leanctx) (push) Has been cancelled
CI / Hermes Plugin (Python) (push) Has been cancelled
CI / SDK Conformance Matrix (push) Has been cancelled
CI / Coverage (push) Has been cancelled
CI / cargo-deny (push) Has been cancelled
CI / Adversarial Safety (push) Has been cancelled
CI / Benchmarks (push) Has been cancelled
CI / Output-Quality Gate (eval A/B) (push) Has been cancelled
CI / Documentation (push) Has been cancelled
CI / CI Green (push) Has been cancelled
JetBrains Plugin / Actionlint (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (rust) (push) Has been cancelled
JetBrains Plugin / Validation (push) Has been cancelled
JetBrains Plugin / Build (push) Has been cancelled
JetBrains Plugin / Test (push) Has been cancelled
Security Check / Security Scan (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 12:35:30 +08:00
commit 26382a7ac6
2353 changed files with 629146 additions and 0 deletions
+192
View File
@@ -0,0 +1,192 @@
# Addon Bootstrap Engine — Phase 2 (implemented)
> Status: **implemented** in `rust/src/core/addons/bootstrap.rs` (+ manifest,
> policy, store, CLI wiring). This document is the design of record for the
> GitLab epic *Addon Bootstrap Engine* (`root/lean-ctx#1105`, subtasks
> `#1106``#1110`). Where the shipped behaviour refines the original plan it is
> noted inline.
## Problem
Today `lean-ctx addon add` is **declarative**: it appends a
`[[gateway.servers]]` entry to the global config and records the install — it
never fetches or installs a package. That is sufficient for **ephemeral
runners** (`npx`, `uvx`), which download and execute their package lazily on the
first tool call. So `repomix` and `serena` already install on add.
It is **not** sufficient for tools that need a real, one-time bootstrap before a
runnable command exists:
| Tool | Why a runner can't do it |
|-----------|----------------------------------------------------------------------|
| Headroom | Ships as `headroom-ai[all]`; `uvx --from` breaks on its entry points — needs `uv tool install`. |
| Graphify | `uv tool install "graphifyy[mcp]"` **and** a pre-built `graph.json`. |
| Cognee | Clone + `uv sync`; no single-command runner. |
| Letta | `npm i -g` plus a long-running server instance. |
For these the registry stays **listed** (homepage + manual instructions). The
bootstrap engine closes that gap: a declarative `[install]` block that lean-ctx
can execute idempotently, with a clean uninstall path and the same security bar
as the rest of the addon system.
## Goals / non-goals
**Goals**
- One declarative `[install]` block per addon, pinned and auditable.
- Idempotent install + reliable uninstall (no orphaned global packages).
- Reuse the existing trust/audit pipeline — no new ad-hoc shell-outs.
- Keep Phase-1 behaviour unchanged when no `[install]` block is present.
**Non-goals**
- No arbitrary script execution (no `curl | sh`, no inline shell).
- No secret provisioning (Mem0 / Claude-Context keys stay the user's job; the
engine only documents and validates the required env names).
- No new network fetch of the registry itself (still compiled-in / signed override).
## The `[install]` manifest block
```toml
[install]
manager = "uv" # one of: pip | uv | cargo | npm | brew | dotnet
package = "headroom-ai[mcp]" # the package spec the manager understands
version = "0.27.0" # MANDATORY exact pin (no ranges, no "latest")
bin = "headroom" # binary the [mcp] command expects (PATH idempotency)
# verify = ["headroom", "--version"]# optional argv probe; exit 0 ⇒ already installed
```
Rules (enforced by `AddonInstall::validate()`, called from `manifest.validate()`):
- `manager` ∈ a fixed allowlist (`uv`/`pip`/`cargo`/`npm`/`brew`/`dotnet`). Each manager
maps to a **fixed argv template** the engine owns — the manifest never supplies
raw shell.
- `version` is required and must be an exact pin (empty / `latest` / `*` are
rejected).
- `package`, `version`, `bin` and every `verify` element are rejected if they
contain shell metacharacters (`| ; & $ \` > <`, newlines) — defence-in-depth,
since the engine never uses a shell.
- **Idempotency check** (shipped refinement): `verify` is *optional*. With no
`verify`, the engine checks whether `bin` resolves on `PATH`; `verify` is an
escape hatch (argv, exit 0 ⇒ installed) for tools whose presence needs a
deeper probe.
- The block is only meaningful together with a runnable `[mcp]` block whose
`command` is produced by the install (e.g. `headroom`).
### Manager → argv templates (engine-owned)
| `manager` | install argv | uninstall argv |
|-----------|--------------------------------------------------|----------------------------------|
| `uv` | `uv tool install {package}=={version}` | `uv tool uninstall {base}` |
| `pip` | `pip install --user {package}=={version}` | `pip uninstall -y {base}` |
| `cargo` | `cargo install {base} --version {version}` | `cargo uninstall {base}` |
| `npm` | `npm install -g {package}@{version}` | `npm rm -g {base}` |
| `brew` | `brew install {package}` (formula carries the pin, e.g. `node@22`) | `brew uninstall {base}` |
| `dotnet` | `dotnet tool install --global {package} --version {version}` | `dotnet tool uninstall --global {base}` |
`{base}` is `{package}` with extras and any inline version stripped
(`headroom-ai[mcp]` → `headroom-ai`), keeping an npm scope intact
(`@scope/pkg`). The manifest chooses a manager + package + pin; it **cannot**
influence the flags or inject extra argv. Every value is passed as a *discrete*
argv element via `std::process::Command` — no shell, no interpolation.
## Install lifecycle
The executor lives in `addons/bootstrap.rs` (`ensure_installed` / `uninstall`)
and is orchestrated by the CLI (`cli/addon_cmd.rs`) *after* consent and *before*
the health probe. The core `addons/install.rs` stays pure — it only persists the
receipt — so its unit tests never spawn a process.
```mermaid
flowchart TD
add["addon add <name>"] --> has{has [install]?}
has -- no --> wire["wire [[gateway.servers]] (Phase 1)"]
has -- yes --> gate["bootstrap gate: validate + consent"]
gate --> present{already present? (verify argv)}
present -- yes --> wire
present -- no --> run["run engine-owned install argv (pinned)"]
run --> verify["run verify argv → must exit 0"]
verify -- ok --> record["record install receipt (manager, package, version, bin)"]
record --> wire
verify -- fail --> rollback["best-effort uninstall + abort, no wiring"]
```
- **Idempotency**: check presence *first* (`verify` argv, else `bin` on `PATH`);
if already satisfied, skip the manager entirely and just wire. Re-running `add`
is safe and reports `Already installed — skipped`.
- **Pre-flight**: when an install *is* needed, verify the manager itself exists
(`LEANCTX_BOOTSTRAP_<MGR>` override path, else the bare name on `PATH`) before
spawning it. A missing manager fails with an install hint
(`install uv → https://docs.astral.sh/uv/…`) instead of a raw spawn error, and
the `add` disclosure shows a `requires: <manager> on PATH — ✓/✗` line up front
so the gap is visible *before* consent.
- **Receipt**: `<data_dir>/addons/installed.json` carries an `install` record
(manager, package, version, bin) — content-only, no timestamps, so it stays
determinism-friendly (#498). `remove` reads it to uninstall.
- **Uninstall**: `addon remove` runs the manager's uninstall argv for packages
*this engine installed* (tracked by receipt) — never something the user had
already. It is best-effort: a failed uninstall logs a note but never blocks the
unwire that already succeeded.
- **Failure**: a non-zero manager exit aborts `add` before anything is wired. A
clean install whose `bin` is not yet on `PATH` is a non-fatal warning (a PATH
setup issue, not a failed install), and the subsequent health probe still
guards a truly broken wiring.
## Security gates
The bootstrap surface is gated at four layers (shipped):
- **Structural validation** (`AddonInstall::validate()`, hard error): unknown
manager, missing/floating version, or shell metacharacters in
`package`/`version`/`bin`/`verify` reject the manifest. Because it runs from
`manifest.validate()`, every path is covered — `addon add`, `addon audit`,
`from_path`, and the registry validator (so a bad block fails CI's
`bundled_registry_passes_security_validator`).
- **Capability coherence**: a declared `[install]` block makes
`trust::wiring_uses_network` return `true`, so an addon that *also* declares
`[capabilities] network = "none"` trips the existing `cap_net_underdeclared`
audit — same gate as the `npx`/`uvx` runner case.
- **Consent**: the `add` preview prints the **exact** install + uninstall argv,
the manager, the package and the pin *before anything runs*, then requires the
standard yes/no (`--yes` to skip in CI). `add` itself is the user's explicit,
consented action.
- **Policy floor**: `addons.allow_bootstrap` (global-only). Default **on** — the
whole point is that `add` installs — but a team that forbids local
package-manager execution sets it to `false`, and `policy::gate` refuses any
`[install]` addon before a single command runs.
## What this unlocks — and the honest migration status
The engine is generic across all five managers. Registry entries flip to
install-on-add **only when the tool actually ships a clean, pinned,
runnable-out-of-the-box MCP server** — never with fabricated wiring.
| Tool | Status | Why |
|-----------|---------------|-----|
| **Headroom** | ✅ migrated | `uv tool install "headroom-ai[mcp]"` (pinned `0.27.0`) → `headroom mcp serve`; a local, secret-free stdio MCP server. The flagship install-on-add. |
| Graphify | listed | Package installs cleanly (`graphifyy[mcp]`), but its MCP server needs a **pre-built `graph.json`** (`python -m graphify.serve graph.json`) — no out-of-the-box server to probe. |
| Cognee | listed | MCP server needs a **repo clone + `uv sync`** (upstream issue #1815); no working pinned one-liner yet. |
| Letta | listed | A pinned `letta-mcp-server` package exists, but the server needs `LETTA_API_KEY` + a Letta backend to start — key-gated, not one-click. |
Mem0 and Claude-Context likewise remain key-gated: the engine *could* install
their package, but cannot provision `MEM0_API_KEY` / `OPENAI_API_KEY` + Milvus —
those stay documented prerequisites. Each tool above flips to installable with a
**one-line registry change** (an `[install]` + `[mcp]` block) the moment upstream
ships a clean server — no further engine work.
## Rollout — done
1. ✅ `[install]` parsing + validator gates.
2. ✅ Install/uninstall executor (`bootstrap.rs`), gated by `addons.allow_bootstrap`.
3. ✅ Headroom migrated; the bundled registry stays green on
`bundled_registry_passes_security_validator`. Graphify/Cognee/Letta wait on a
clean upstream MCP server (see table) rather than shipping broken wiring.
## Operational notes & open questions
- **Manager path override** (shipped): set `LEANCTX_BOOTSTRAP_<MANAGER>` (e.g.
`LEANCTX_BOOTSTRAP_UV=/opt/uv`) to pin the exact manager binary for locked-down
environments; otherwise the manager is resolved from `PATH`.
- Open: per-manager cache/location detection for richer "already present" checks
(today: `verify` argv, else `bin` on `PATH`).
- Partly shipped: `add` now pre-flights the manager's existence (with an install
hint); a full `doctor` sweep over *already-installed* addons is still open.
- Open: Windows support for the manager templates (the executable probe already
falls back to "is a file" off-unix; argv templates assume POSIX managers).