Metadata-Version: 2.5
Name: entiendo
Version: 0.2.0
Summary: The enforced system map for AI-built software: units with contracts and evals, a reconciler that fails the build on drift (undeclared deps, stale docs, silent model swaps), and a steerable Universe — where the unit, not the file tree, is the unit of work.
Project-URL: Homepage, https://entiendo.dev
Project-URL: Specification, https://github.com/akashdatageek/entiendo/blob/main/SPEC.md
Author: Entiendo
License: Apache-2.0
License-File: LICENSE
Keywords: agents,codegen,control-plane,drift-detection,evals,instrumentation,llm,mcp,observability,system-map
Requires-Python: >=3.10
Requires-Dist: jsonschema>=4.0
Requires-Dist: pyyaml>=6.0
Provides-Extra: detect
Requires-Dist: time-machine>=2.13; extra == 'detect'
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: time-machine>=2.13; extra == 'dev'
Provides-Extra: extract
Provides-Extra: history
Requires-Dist: duckdb>=0.9; extra == 'history'
Requires-Dist: pyarrow>=14.0; extra == 'history'
Provides-Extra: instrument
Requires-Dist: opentelemetry-api>=1.20; extra == 'instrument'
Requires-Dist: opentelemetry-sdk>=1.20; extra == 'instrument'
Provides-Extra: mcp
Requires-Dist: mcp>=1.0; extra == 'mcp'
Provides-Extra: serve
Requires-Dist: anthropic>=0.40; extra == 'serve'
Description-Content-Type: text/markdown

# Entiendo — steer your codebase like mission control

<!-- mcp-name: io.github.akashdatageek/entiendo -->

[![CI](https://github.com/akashdatageek/Entiendo/actions/workflows/ci.yml/badge.svg)](https://github.com/akashdatageek/Entiendo/actions/workflows/ci.yml)

> **The map that fails your build when it lies.** Every architecture diagram
> goes stale; Entiendo's is **generated and enforced**. Declare what each unit
> is, what it depends on, and which model answers for it — and the reconciler
> turns every gap between declaration and reality into a build failure: an
> undeclared dependency, a description bound to code that changed, **a model
> your app started using that nobody reviewed**. Alerts tell you something
> moved; Entiendo refuses to ship it until a human either fixes the code or
> accepts the change as a new, diffable version.

> **The control plane for AI-built software.** Manifests hold the declared desired
> state; a reconciler continuously verifies reality against it; evals are the
> health probes; fingerprints are the versioned identities; and the Universe is
> the surface you steer through. **Human = operator, coding agent = workload,
> Entiendo = control plane.** Works *with* your IDE and your agent — it is the
> plane they operate under.

**When AI writes the code, the file tree stops being the right interface.** The
unit of work becomes the **unit** — a declared component with a task, a contract,
an eval, a **fingerprint**, and a history. Entiendo makes that unit the surface a
human steers through *and* the retrieval unit an AI edits through.

> **The law:** a boundary is a valid unit *iff it can be evaluated independently
> on given data.* Not evaluable alone → not a unit → boundary error. That single
> test is what makes this *control*, not decoration.

> Instrumentation at **build time**, not forensics after breakage. Sensors go in
> while you build, so "which part broke" is already answered when something turns
> red. Entiendo is a read-only observer — never in the request path.

What's implemented today is tracked in **[STATUS.md](./STATUS.md)** (the single
status source). The full specification is **[SPEC.md](./SPEC.md)** (the source of
truth), the vocabulary is **[LEXICON.md](./LEXICON.md)**, and the roadmaps are
**[PLAN_v3.md](./PLAN_v3.md)** (units → fingerprints → Bridge) and
**[PLAN_v4.md](./PLAN_v4.md)** (the rendered Universe — interiors, real lenses,
diff-first approval — now fully implemented). This README is the map to the
scaffold.

> **Naming:** v3 speaks of *units*, *fingerprints*, and *reflex / golden / judge*
> evals; the older *node* / *version* / *tier0–2* names still appear in code and
> some docs and mean the same things (the mechanical rename is a later phase). The
> manifest format — `entiendo.node.yaml`, `claims:`, `apiVersion: entiendo/v1` —
> is unchanged.

---

## Quickstart — under a minute to your first Universe

Measured on a clean virtualenv (2-core Linux container): install 8.7s, first
graph 0.2s, full eval pass 0.6s.

```bash
# not on PyPI yet — install from the repo
pip install "entiendo[mcp] @ git+https://github.com/akashdatageek/Entiendo"
# or, from a checkout: pip install -e ".[dev,mcp]"

# try it on the bundled example
cp -r examples/refundly /tmp/refundly && cd /tmp/refundly
ent extract                     # → entiendo/graph.json + coverage, reconciled
ent eval --all                  # → every unit executes its reflex evals
ent dev                         # → the Universe on http://127.0.0.1:7373,
                                #   live-reloading as you edit
```

The map opens as a **layered DAG** — callers on the left, foundations on the
right, each layer labelled in plain words (the constellation view remains a
toggle). From there: click a unit → its window opens (**inside** shows the
functions and classes it holds, and — if the unit declares `interior.steps` —
*how it works, in order*, each step typed by the OTel GenAI span kinds and
optionally hash-bound to a file so the story cannot silently rot) → press
**f** to focus the unit's *cone* (everything it depends on, everything that
depends on it; the rest fades) → hit **Steer**, and your coding agent makes
the change through the unit's claims, with the verdict and blast radius
surfacing in the map.

**Use it inside your builder.** Entiendo speaks **MCP**, so any MCP-capable
editor can read and write *through units* — **Claude Code**, **Cursor**,
**Google Antigravity**, and anything else that speaks the protocol. One page
covers all of them: **[docs/builders.md](./docs/builders.md)**.

```jsonc
// the universal registration — one stdio server, eleven tools
{ "mcpServers": { "entiendo": { "command": "ent", "args": ["mcp", "--root", "."] } } }
```

Claude Code additionally installs the skills and the boundary hook as one
plugin:

```
/plugin marketplace add akashdatageek/Entiendo
/plugin install entiendo@entiendo-marketplace
```

**Platform support:** macOS and Linux are first-class. On Windows, the core
works with degraded guarantees — history locking falls back from `fcntl` to
`msvcrt`, and the eval sandbox skips POSIX rlimits (timeouts still apply) —
so **WSL2 is the recommended way to run Entiendo on Windows**. Nothing
crashes natively; you just lose the memory/CPU caps.

## Status: L0 → L5 + Phase 7 + the v4 Universe implemented

All six phases (SPEC.md §8), **Phase 7 (real evals)**, and the whole **v4 layer**
are implemented. The full loop works end to end: declare units → reconcile the
graph → instrument → **execute + eval** → record history → render the Universe →
steer + approve through the unit.

**Entiendo manages itself.** The repo is retrofitted into **14 semantic units**
under `units/`, every file claimed or explicitly acknowledged, every declared
edge verified by the reconciler, and **all 14 units run a real eval and are
green**. Eight of the nine evals unblocked by `contract.harness` are proven able
to *fail* — `scripts/mutation_check.py` breaks each unit's code on purpose and
watches the verdict flip. (The ninth is the eval runner judging itself; that
limit is documented rather than papered over.) CI gates the repo's own map with
`ent validate` + `ent extract --check`, exactly like any project you point it at.

**What v4 added (PLAN_v4.md, H0–H5):** the render surface is now a single
navigable **Universe** — one canvas with a world-coordinate camera, `/`-search,
keyboard nav, a minimap, and group collapse — dressed in a celestial design
system, replacing the old six-tab layout. The lenses became *real*: **trace
playback** (a comet walks a recorded request's hops and halts red on a failed
one), a **timeline scrubber** over a real commit axis (replays a unit's
fingerprint against any past commit), and a **cost/budget overlay**. Agentic
units now **render their interior** — each tool a satellite on an orbit ring,
tethered across the border to the unit it crosses — and trace playback descends
into it, lighting each tool as the agent calls it. Finally, **diff-first
approval**: steering an approval-gated unit holds the change back as a
*proposal*, and the unit's **steer** tab shows the unified diff + behaviour
delta + verdict together with real Approve / Reject, while the map pulses a gold
ring on any unit awaiting sign-off. You approve the change you can *see*.

```
$ ent validate            # schema + semantic checks (incl. restricted invariants)
$ ent init                # scaffolds entiendo/ (+ a starter manifest)
$ ent new <id> --task ... --fixture ... --expect ...   # fixture-first unit birth; refuses without the pair (the law)
$ ent extract             # graph.json + coverage.json; fails on drift; proposes entrypoints
$ ent eval <node>         # tier0 EXECUTES the node → GREEN/RED/UNTESTED/ERROR
$ ent eval --all --tier 1 # golden: minRuns + significance + budgets (the pre-merge gate)
$ ent bless <node>        # sign a golden dataset's content (humanBlessed, void on change;
                          #   prints the oracle-class census, quarantines implementation-derived rows)
$ ent baseline accept <n> # promote a pending baseline
$ ent snapshot            # record composite versions + verdicts to append-only history
$ ent render              # self-contained HTML map: seven lenses + "executable N/M"
$ ent edit <node>         # scoped edit loop: context + boundary + verdict + approval
$ ent otel <otlp.json>    # ingest standard GenAI spans: tokens, models, per-unit rollup
$ ent pin <n> model=<id>  # pin a fingerprint dimension; the fingerprint moves onto the Timeline
$ ent replay <n> --against <fp>  # golden metric now vs an old fingerprint, delta attributed by dimension
$ ent retrofit <root>     # infer nodes in an unmanaged repo → staged manifest proposals
$ ent serve               # the Universe: click a unit, steer it from your agent, watch reflex
```

> **The one-line test (Phase 7 §15):** break `ranker.py` and run
> `ent eval retrieval.chunk_ranker`. It goes **RED** and names the failed
> invariant with the real numbers (`len(output.chunks)=2 <= input.k=1`). That is
> the difference between an instrument and a diagram — see [`docs/phase7.md`](./docs/phase7.md).

**Why you can trust the green.** Agents demonstrably game verifiers they can
write to (the reward-hacking literature puts it at 54–100% when the evaluator
is reachable), so Entiendo's propose-verify split is **access control, not
policy** (SPEC §17): the deterministic spine never calls a model; the claims
hook fail-closes on the oracle (history, baselines, blessing signatures,
steering verdicts, the generated map, any blessed golden dataset); golden
rows carry `oracleClass` provenance so expected values derived from the code
under test are quarantined until a human consciously accepts them; the eval
sandbox's effect probe turns a false `sideEffects: none` into a RED; and
every language adapter publishes its blind spots into the graph, with each
edge graded `complete | partial | none`. The green is trustworthy because
the agent is *mechanically unable* to produce it except by making the code
actually conform.

> **The model-identity test:** pin a unit's model
> (`ent pin refundly.decide model=claude-sonnet-5`), point `ent otel` at the
> OTLP/JSON your tracing already exports, and let `ent ci` compare the pin to
> `gen_ai.response.model`. A silent swap **fails the build** and the fix is
> printed: repair the app, or accept the swap with `ent pin` — which moves the
> unit's composite fingerprint, so the swap becomes a reviewed, diffable
> version instead of a dismissed alert. (A pin of `claude-sonnet-5` accepts its
> dated forms; a dated pin accepts nothing looser.)

What **is** real today:

- **[`SPEC.md`](./SPEC.md)** — the complete specification (v3).
- **[`schemas/node.schema.json`](./schemas/node.schema.json)** — the manifest
  JSON-Schema. This is *the contract for the entire system* (SPEC.md §12).
- **`ent validate` / `ent init`** — L0 boundaries: schema conformance plus the
  semantic rules (id uniqueness, `$ref` resolution, claim existence, the
  `humanBlessed` gate on tier1 golden sets). See `src/ent/validation.py`.
- **`ent extract`** — L1 reconciler: AST import analysis derives actual edges and
  checks them against declared `dependencies`. Undeclared edges are drift and
  fail the build (Invariant 5); it emits `graph.json` + `coverage.json`. See
  `src/ent/extractor.py`.
- **`ent eval` + `@ent.node()`** — L2 instrumentation + **Phase 7 real evals**:
  the decorator emits an OTel-compatible span carrying `entiendo.node_id` (and
  `ent.record()` meters cost/tokens), never in the request path (Invariant 2).
  **tier0 now executes the node** over fixture rows in isolation (dependency calls
  served from stubs; any unstubbed call is a `TIER0_IO_VIOLATION`) and evaluates
  the real invariants against real output via a restricted AST evaluator (no
  `eval`/`exec`) → GREEN/RED/UNTESTED/ERROR. **tier1** replays `minRuns` times,
  scores with the metric, and applies anti-flicker statistics
  (WITHIN_BAND/REGRESSED/IMPROVED/UNSTABLE) + budgets (DEGRADED); `humanBlessed`
  is enforced by a content signature. See `src/ent/evals/`, `src/ent/invariants.py`,
  `src/ent/testing.py`, `docs/phase7.md`.
- **`ent snapshot` + `ent render`** — L3/L4: `snapshot` records composite
  versions (code/prompt/config/model) + tier0 verdicts to an append-only history
  log (version events dedup, so the timeline shows *changes*); `render` builds the
  **Universe** — one self-contained, navigable canvas (camera, search, minimap,
  celestial design) whose **seven lenses** are all real: structure (kind/group),
  flow (edge kinds + traffic), **trace** (a comet plays a recorded request's hops
  and descends into agentic interiors), health (verdict colour, matches
  `ent eval`), **timeline** (a scrubber over the real commit axis that replays
  fingerprints), blast radius (dependents ranked by coupling), and **city** (a
  unit's *area* is its real file mass — territory as truth). Agentic units
  render their `interior` as orbiting, tethered tool satellites. Record a request
  with `history.capture_trace(root, trace_id=...)`. Read-only, never in the
  request path (Invariant 2). See `src/ent/render.py`, `src/ent/universe.html`,
  `src/ent/history.py`, `src/ent/version.py`.
- **`ent edit`** — L5 scoped edit loop: assembles a context of only the node's
  claimed file bodies + immediate neighbours' contracts (no bodies) + recent
  evals + baseline — the AI edits through the node, not the repo (Invariant 8).
  `--changed` enforces the claim boundary, reruns tier0, shows blast radius, and
  applies the approval gate. See `src/ent/editloop.py`.
- **`ent retrofit`** — the §12 v2 path: infers node boundaries in an *unmanaged*
  repo (directory grouping, kind from extensions, deps from static imports,
  entrypoint from a lone public function) and stages one manifest proposal per
  node for node-by-node review (`--accept`). Semi-automated migration, never a
  silent scan. `examples/legacy/` is the demo input. See `src/ent/retrofit.py`.
- **`ent serve`** — the interactive surface: the Universe over a localhost web app
  (stdlib backend, self-contained frontend). Select a unit, see its scoped
  context, run tier0/tier1, and **Steer** it in natural language — edited **only
  within the unit's claims**, tier0 reruns, verdict + blast radius surface live,
  with one-click **Revert**. An approval-gated unit's change is held as a
  **proposal** you Approve / Reject from the diff. The workload is either an LLM
  directly (`pip install -e '.[serve]'` + an API key) or **your coding agent via
  the Bridge** (steer → `await_steering`/`post_verdict`; the
  `entiendo-operator` skill ships for Claude Code, and any MCP client can drive
  the same two tools). The map stays read-only (Invariant 2); only steer / approve / revert
  write. See `src/ent/server.py`, `src/ent/steering.py`, `src/ent/agent.py`,
  `docs/edit-surface.md`, `docs/bridge.md`.
- **[`examples/greenfield/`](./examples/greenfield/)** — a five-node example
  project laid out the Entiendo way. Full loop:
  `cd examples/greenfield && ent validate && ent extract && ent snapshot && ent render && ent edit retrieval.chunk_ranker`.
- **[`examples/refundly/`](./examples/refundly/)** — the reference project and the
  v4 demo: a support-refund **pipeline of six units** — `parse_email` (compute) →
  `orders` (state) → `policy` (config) → `decide` (the **agentic unit**) →
  `gateway` (external) → `ledger` (state). `refundly.decide` has an `interior` (a
  five-tool registry — parse / order_lookup / read_policy / issue_refund /
  write_ledger, each crossing to another unit — plus `maxSteps`) and a
  **trajectory eval** — a reflex check that the *path* is right (`order_lookup`
  before `issue_refund`, no tool outside the registry), not just the answer.
  Border-crossing tools are reconciled against declared edges (`ent.guard`
  enforces the registry at runtime); `refundly.gateway` is `irreversible` +
  approval-gated, so steering it produces a **proposal** you approve from the
  diff. Its committed traces (including a bad-order run where the refund is issued
  before the order is verified) drive trace playback. See SPEC §14.
- **`src/ent/`** — the package: CLI, one module per layer.

---

## What a project looks like

Point Entiendo at a repo and every declared component becomes a **node** on one
topology you steer through — not a folder in a tree. This is
[`examples/greenfield/`](./examples/greenfield/): five nodes, reconciled at 100%
coverage. Run `cd examples/greenfield && ent extract` and this is the graph it
derives:

```mermaid
flowchart LR
  subgraph retrieval[" retrieval "]
    ranker["retrieval.chunk_ranker<br/><small>compute · 🟢 GREEN</small>"]
    vstore["retrieval.vector_store<br/><small>compute · 🟢 GREEN</small>"]
    idx["state.doc_index<br/><small>state · ⚪ untested</small>"]
    cfg["config.retrieval<br/><small>config · ⚪ untested</small>"]
  end
  subgraph llm[" llm "]
    gw["llm.gateway<br/><small>external · ⚪ untested</small>"]
  end

  ranker -->|calls ✓| vstore
  ranker -->|calls ✓| gw
  ranker -.->|reads| idx
  ranker -.->|config| cfg
  vstore -.->|reads| idx
  vstore -.->|config| cfg
  gw    -.->|config| cfg

  classDef compute fill:#3b82f6,stroke:#1c1c22,color:#fff;
  classDef state fill:#8b5cf6,stroke:#1c1c22,color:#fff;
  classDef config fill:#64748b,stroke:#1c1c22,color:#fff;
  classDef external fill:#f59e0b,stroke:#1c1c22,color:#111;
  class ranker,vstore compute;
  class idx state;
  class cfg config;
  class gw external;
```

**Reading the map:** colour is the node **kind** (blue `compute` · violet `state`
· slate `config` · amber `external`). A **solid** arrow is an edge the extractor
*verified* against a real import (`✓`); a **dashed** arrow is declared but not
statically provable (`reads`/`config`). Health is the node's tier0 verdict —
🟢 GREEN means the node **executed** and its invariants held, ⚪ means no
executable eval yet. An undeclared import would fail `ent extract` naming both
nodes (Invariant 5), so what you see is guaranteed to match the code.

### The rendered surface — the Universe (`ent render`)

`ent render` builds a **self-contained HTML page** (inline CSS/JS, no build step,
read-only) — the **Universe**: one navigable canvas, not a wall of tables. Pan
and zoom with a world-coordinate camera, `/` to search, arrow keys to walk units,
a minimap for the whole system, and groups you collapse at scale. The six
**lenses** don't switch pages — they change what the *same* canvas shows:

```
┌──────────────────────────────────────────────────────────────────────────┐
│  ✦ Entiendo   5 units · 1 untested · 4 green · coverage 100% · reconciled │
│                          [ Structure ][ Flow ][ Real runs ][ Health ] …   │
│                                    ┌──────── chunk_ranker ────────┐        │
│         ( ranker )────✓───▶( vstore)│ inside identity promises …  │        │
│            │  ╲                     │ Ranks retrieved chunks…     │        │
│            ✓   ╲config              │ 12 parts across 3 files     │        │
│            ▼    ▼                   │  ƒ rank   Score and order…  │        │
│        ( gw )  ( cfg )  ○ doc_index │  ▣ Ranker Holds the model…  │        │
│         ▲ minimap ▫                 │ [ Steer ][ Revert ]         │        │
│                                     └─────────────────────────────┘        │
└──────────────────────────────────────────────────────────────────────────┘
```

Click a unit and it opens as a **window** over the living map — several at once,
each tabbed: **inside** (the functions and classes it actually holds) ·
**identity** · **promises** · **checks** · **history** · **impact** · **steer**.
The words are deliberately plain: *"writes data"*, not `sideEffects: writes`;
*"nothing else depends on this — changing it cannot break another unit"*, not
`no downstream dependents`.

- **Structure** — kind + group; the map you read first.
- **Health** — recolours every unit by its tier0 verdict; it calls the same
  `run_tier0` as `ent eval`, so the colour matches by construction (🟢 executed +
  invariants held, ⚪ no executable eval).
- **Flow** — edge direction with per-edge kind labels and per-unit traffic volume.
- **Trace** — pick a recorded request and a **comet walks its hops** in order,
  annotating each with latency + cost; a failed hop halts it and pulses red. Over
  an agentic unit the comet **descends into the interior**, lighting each tool as
  the agent calls it — so an out-of-order call shows even when the answer is right.
- **Timeline** — a **scrubber over the real commit axis**; drag it and a unit's
  fingerprint replays against that past commit, the changed dimension attributed
  (code / prompt / config / model).
- **Blast radius** — select a unit → its transitive downstream dependents light
  up, ranked by contract coupling.

Agentic units aren't opaque orbs: their `interior` renders as **satellites on an
orbit ring**, each tethered across the border to the unit its tool crosses (the
ring dashes when the registry isn't enforced). A unit can also declare
`interior.steps` — its ordered story, each step one of the five OTel GenAI span
kinds (*asks a model, uses a tool, hands off to an agent, embeds text, runs a
sub-flow*) and optionally **hash-bound** to a file: edit the file and the step
goes stale, a reconciliation error that prints the new hash. Descriptions that
cannot silently rot.

### Steer + approve on the canvas — `ent serve`

`ent serve` puts the Universe behind a localhost web app and turns the window
into a control panel. Select a unit → **Steer**: describe a change in English. The
change is made **within the unit's claims**, tier0 reruns, and the verdict + blast
radius surface live, with one-click **Revert**. Two ways the workload edits: an
LLM directly (`.[serve]` + an API key), or **Claude Code as the operator** — the
steer request lands on a file-based **Bridge** queue (`await_steering` →
`get_node_context` → `apply_edit` → `post_verdict`, the `entiendo-operator`
skill), so the map steers the same agent you already code with.

For an **approval-gated** unit (`approval.required`), the change is not applied
live — it is held back as a **proposal**. The steer tab shows the change you'd be
approving: the **unified diff, the behaviour delta, and the after-verdict
together**, with real **Approve** / **Reject**. On the map, any unit with a
proposal waiting pulses a gold ring.

```
┌ Universe ─────────────────────────┬─ refundly.gateway ────────────────────┐
│                                    │ external · irreversible · approval ✋  │
│   parse ▶ orders ▶ policy          │ ── Proposal · awaiting approval ──     │
│              │                     │ clamp refund to order amount · 🟢      │
│         ( decide )  ◜orbit◝        │ behaviour Δ  0.91 → 0.94 (IMPROVED)    │
│           tools: order_lookup…     │ ┌ src/gateway/pay.py ────────────┐    │
│              │                     │ │ - amount = req.amount          │    │
│         ((gateway))✦ ← pulsing     │ │ + amount = min(req.amount, ord)│    │
│              │      gold ring      │ └────────────────────────────────┘    │
│           ( ledger )               │        [ Approve ]   [ Reject ]        │
└────────────────────────────────────┴────────────────────────────────────────┘
```

The map stays read-only (Invariant 2); only the steer / approve / revert
endpoints write, and only inside the claims. A red edit is **blocked**, the
pre-edit content is backed up for revert, and an approval gate is never bypassed —
Reject leaves the working tree untouched.

---

## How you work with it

Two ways in, same guarantees. Either you drive the loop from the **CLI**, or a
coding agent **edits through the unit** — `ent serve` for the canvas, or
`ent mcp` from whichever builder you use (see
**[docs/builders.md](./docs/builders.md)**).

### The loop

```mermaid
flowchart LR
  D["declare<br/><small>entiendo.node.yaml</small>"] --> V["ent validate<br/><small>L0 schema + rules</small>"]
  V --> X["ent extract<br/><small>graph.json + coverage.json<br/>fail on drift</small>"]
  X --> E["ent eval<br/><small>tier0 executes the node<br/>GREEN / RED</small>"]
  E --> R["ent render<br/><small>the Universe · seven lenses</small>"]
  R --> C["steer + approve<br/><small>ent edit · serve · mcp</small>"]
  C -->|"confined to claims<br/>tier0 reruns"| E
```

The manifest **is** the retrieval index: an edit loads only the node's claimed
file bodies + its immediate neighbours' contracts (no bodies) — never the whole
repo (Invariant 8). Every edit is boundary-checked, re-evaluated, and gated
(`ready-to-merge` / `awaiting-signoff` / `blocked`) before it counts as done.

### Editing through the unit from any MCP builder (`ent mcp`)

Register Entiendo as an MCP server — the same JSON in every editor that speaks
the protocol — and your agent reads and writes *through the unit*, not the file
tree. Setup per builder (Claude Code, Cursor, Antigravity) is in
**[docs/builders.md](./docs/builders.md)**:

```mermaid
sequenceDiagram
  participant CC as your coding agent
  participant E as Entiendo · ent mcp
  CC->>E: get_node_context(node)
  E-->>CC: manifest + claimed file bodies<br/>+ neighbour contracts only
  CC->>E: apply_edit(node, files)
  Note over E: rejects paths outside claims<br/>backs up · reruns tier0
  E-->>CC: verdict · blast radius · approval
  Note over CC: red → revert_node(node)
```

A quick tour, end to end:

```bash
pip install -e '.[dev,mcp]'
cd examples/greenfield
ent validate                        # L0: manifests conform
ent extract                         # L1: graph.json + coverage.json (no drift)
ent eval retrieval.chunk_ranker     # L2/Phase 7: executes → 🟢 GREEN
ent render && open entiendo/render.html  # L4: the seven-lens map above
ent serve                           # L5: click-and-edit surface (needs [serve])
ent mcp                             # L5: the same surface as MCP tools, for any builder
```

---

## The unit

Everything hangs off one schema. A unit is declared by an `entiendo.node.yaml`
colocated with the code it owns (the filename keeps the `node` spelling for
back-compat — see [LEXICON.md](./LEXICON.md) → Compatibility):

```yaml
apiVersion: entiendo/v1
kind: Node
id: retrieval.chunk_ranker      # stable, globally unique
nodeKind: compute               # compute | state | schema | config | external | pipeline
owner: mehar                    # human accountable, not the AI
claims: [src/retrieval/ranker.py, src/retrieval/prompts/rank_v3.md]
contract:
  invariants: ["len(output.chunks) <= input.k"]
  sideEffects: none
dependencies: { calls: [retrieval.vector_store, llm.gateway], reads: [state.doc_index] }
evals:
  tier0: [{ type: schema_validation }, { type: invariant_check }]
```

See the fully-annotated version in
[`examples/greenfield/src/retrieval/entiendo.node.yaml`](./examples/greenfield/src/retrieval/entiendo.node.yaml)
and the field-by-field reference in [`docs/manifest.md`](./docs/manifest.md).

---

## CLI

| Command | Layer | Does |
|---|---|---|
| `ent init` | L0 | scaffold `entiendo/` + a first unit manifest |
| `ent new <id>` | L0 | fixture-first unit birth (refuses without a fixture/expect pair) |
| `ent validate` | L0 | validate manifests against the schema |
| `ent extract` | L1 | emit `graph.json` + `coverage.json`; fail on drift |
| `ent eval <unit>` | L2 | run a unit's evals — reflex (default) / golden / judge |
| `ent bless` / `ent baseline` | L2 | sign a golden dataset / promote a baseline (human only) |
| `ent snapshot` | L3 | record composite fingerprints + verdicts to history |
| `ent render` | L4 | the Universe render surface (seven lenses, self-contained HTML) |
| `ent pin` / `ent replay` | L4 | pin a fingerprint dimension / replay a metric against an old one |
| `ent edit <unit>` | L5 | scoped edit loop: context → boundary → verdict → approval |
| `ent serve` | L5 | the Universe live: steer + approve on the canvas |
| `ent mcp` | L5 | the same surface as MCP tools, for any MCP builder |
| `ent retrofit <root>` | — | infer units in an unmanaged repo → staged proposals |
| `ent doctor` | — | self-diagnose the environment + project (deps, key, schema, reconcile) |
| `ent fixtures <unit>` | — | propose tier0 smoke fixtures for a unit from recorded traces |
| `ent ci` | — | one gate: validate + reconcile + eval (CI / pre-commit) |

> **Lexicon:** the CLI, the Universe, and these docs speak of **units**,
> **fingerprints**, and **reflex / golden / judge** evals. The *format* is
> unchanged — `entiendo.node.yaml`, `claims:`, `apiVersion: entiendo/v1`,
> `kind: Node` — and old forms (`--node-id`, `--tier 0/1/2`) keep working. See
> [LEXICON.md](./LEXICON.md).

All layers are implemented (L0 → L5 + Phase 7 + the v4 Universe); see the build
order below.

---

## Architecture (L0 → L5)

Strictly separable layers, each testable alone, built in order
(SPEC.md §3, §8). See [`docs/architecture.md`](./docs/architecture.md) and
[`docs/build-order.md`](./docs/build-order.md).

```
L0  Manifest & schema      declaration + validation          src/ent/manifest.py, schemas/
L1  Extractor / reconciler graph.json + coverage.json         src/ent/extractor.py, version.py
L2  Instrumentation        @ent.node() spans; eval runner     src/ent/instrument.py, evals/
L3  History store          append-only versions + evals       src/ent/history.py
L4  The Universe           one canvas, six real lenses         src/ent/render.py, universe.html
L5  Steer + approve        unit → context → edit → verdict     src/ent/editloop.py, server.py, steering.py
```

---

## Repo layout

```
Entiendo/
  SPEC.md                     the specification (source of truth)
  README.md                   this file
  pyproject.toml              package + `ent` console script (`entiendo` alias for uvx)
  server.json                 MCP Registry entry (prepared; publishes after PyPI)
  schemas/
    node.schema.json          manifest contract (JSON-Schema)
  src/ent/                    the tool
    cli.py                    argparse entry; one file per subcommand under commands/
    commands/                 init, new, validate, extract, eval, bless, baseline,
                              snapshot, render, pin, replay, edit, serve, mcp,
                              retrofit, doctor, fixtures, ci, otel
    manifest.py               L0  unit model: discover, load, Node
    schema.py                 L0  schema load + validator
    validation.py             L0  schema + semantic checks
    extractor.py              L1  reconciler (AST edges vs declared deps; drift = fail)
    languages/                L1  per-language adapters + capability manifests
                              (python AST; TypeScript PoC — declared blind spots)
    version.py                L1/L3 composite fingerprinting (code/prompt/config/model)
    instrument.py             L2  @ent.node() decorator + ent.guard registry gate
    evals/, invariants.py     L2  tiered eval runner + restricted-AST invariants
                              (incl. contract.secondStage — deferred contracts w/ blame)
    sandbox.py                L2  bounded eval child (rlimits, timeout, effect probe)
    goldens.py                L2  oracle-class provenance (the tautological-oracle guard)
    otel.py                   L2  OTel GenAI span reader (tokens, models, drift rows)
    history.py                L3  append-only versions/evals/traces store
    render.py, universe.html  L4  the Universe: one canvas, seven lenses, interiors
    editloop.py               L5  scoped context + boundary + verdict + behaviour delta
    server.py, agent.py       L5  ent serve backend + the editing model
    steering.py, mcp_server.py L5 the Bridge (steer queue → operator → proposal/verdict)
    replay.py                 L4  fingerprint replay for the Timeline scrubber
  examples/greenfield/        a five-unit example project (the MVP walkthrough)
  examples/refundly/          the 6-unit agentic pipeline + v4 demo (interiors, approval)
  docs/                       architecture, build order, builders, registry, ci, bridge
  tests/                      the suite (531 tests, ~22s)
```

---

## Develop

```bash
pip install -e ".[dev]"     # editable install; provides the `ent` command
ent --version
pytest                       # the full suite (531 tests, ~22s)
```

Guiding invariants (SPEC.md §2): the map is generated never drawn; Entiendo is a
read-only observer, never in the request path; no node without a contract, no
contract without a tier-0 eval; every file is claimed exactly once or explicitly
unclaimed; manifests are verified, not trusted; secrets are never rendered;
health is baseline + significance, never a raw score; the AI edits through the
node, not the repo; and the oracle is not agent-writable (SPEC §17 — the
verifier's state is closed to the proposer by access control).
