# NEAT — Claude Code skill

NEAT does the investigation and the reasoning for a coding agent, so the agent
can spend its effort on the code. Agents are weak at investigating a system and
reasoning about its behaviour; given the right context, they are strong at
writing the change. The clearest example is a failing system: call `investigate`
with the service or the symptom and NEAT returns one work order — where the
failure is, the cause chain with provenance on each hop, what a fix reaches, the
policies that govern the code, and where code and runtime disagree — so the agent
starts at the fix instead of grepping for it. (`get_incident_card` composes the
same work order when you already have the exact node id.)

NEAT answers from a live graph that fuses declarations from code, data schemas
and infrastructure with runtime traffic, incidents and supported provider
telemetry, at the finest grain the evidence permits. Every claim has provenance
and confidence; an unseen path is not proof that it never runs.

## What NEAT investigates for you

- **Why something is failing.** `investigate` (a service, a symptom, or a node
  id) returns the work order; `get_incident_card` does the same from an exact
  node id; `expand` and `relate` verify its chain one hop at a time;
  `get_root_cause` and `get_incident_history` give the parts on their own.
- **What a change will break.** `get_blast_radius` for everything downstream,
  and `check_policies` for the architectural rules that govern the code you're
  editing.
- **How the system works and what actually runs.** `ask` in plain language;
  `get_dependencies` and `get_observed_dependencies` for a node you can name;
  `semantic_search` to find one by description.
- **Where code and production disagree.** `get_divergences`.
- **What changed or went quiet.** `get_graph_diff` and `get_recent_stale_edges`.

The server also reports instrumentation gaps and, when hosted control-plane
access is configured, manages supported provider connections. The table below is
generated from the registered tool descriptions, so its inventory follows the
shipped server.

<!-- MCP_TOOL_TABLE_START -->
| Tool | Server description |
| --- | --- |
| `get_root_cause` | Why is a node failing? Trace the failing node up its dependency graph toward likely root-cause candidates, ranked with per-candidate classification (primary-failure vs downstream symptom). Returns a provenance-scored cause chain and recorded error context that file search cannot establish from runtime evidence. For the whole work order on a failure, call investigate or get_incident_card first. |
| `get_blast_radius` | What depends on this node — what breaks if I change it? Before changing or redeploying a node, see its downstream dependents and evidence-bearing paths. Returns the bounded blast radius so an edit plan includes the affected services, routes, data, and callers. |
| `get_dependencies` | What does this node depend on? Map a node's outgoing dependencies across code, data, and infrastructure. Returns a bounded traversal (default depth 3, max 10) with distance, edge type, provenance, and confidence; depth=1 shows direct dependencies only. |
| `get_observed_dependencies` | What did this node actually call at runtime? Return only its OBSERVED outgoing dependencies, from spans or supported provider signals. Compare with get_dependencies or get_divergences to tell declared intent from seen behavior. |
| `get_incident_history` | What failed here, and when? Read a node's recorded error events — incidents, crashes, exceptions — most recent first, with their deploy/env context. The incident ledger preserves failure evidence and timestamps a source search cannot reveal. |
| `get_incident_card` | Compose the incident work order for an exact node id (a service, file, or symbol): the recorded incident, likely cause chain, blast radius, governing policies, and divergences, each claim provenance-tagged — the same card NEAT pushes when it detects a failure. Have a symptom or a bare service name instead of a node id? Call investigate; it resolves the name and composes this card. Omit errorId for the latest incident or pin a specific one, then use expand/relate to verify the path. |
| `investigate` | First call for a failing, slow, or crashing system. Give it a service name, a symptom ("why are reservations failing"), or a node id, and it returns the composed incident for the node it resolves: the recorded failure with its deploy/env context, the likely root cause and its provenance, the blast radius, the governing policies, and where declared and observed behavior diverge — one work order instead of several queries. Resolves a bare name to its service node, or the best graph match for a symptom; then use expand/relate to verify the chain. Same card get_incident_card composes from an exact node id, and the card NEAT pushes when it detects a failure. |
| `semantic_search` | When you cannot name a graph node, find candidate nodes by a natural-language description. Searches node labels through Ollama nomic-embed-text when reachable, then in-process MiniLM, then substring fallback; it does not search arbitrary source contents. MiniLM downloads a ~23 MB quantized model on a cold cache; set NEAT_SEARCH_PROVIDER=substring before daemon startup to avoid model initialization and download. |
| `get_graph_diff` | What changed since a known-good point? Compare a saved snapshot with the live graph. Returns added, removed, and changed nodes and edges plus both timestamps, so architecture drift and regressions are visible beyond a file diff. |
| `get_recent_stale_edges` | What traffic or integration went quiet? List recent OBSERVED → STALE edge transitions — the edges that stopped being seen, and when. Quiet is a signal to investigate, not proof the dependency is healthy or removed. |
| `check_policies` | Before an edit, ask which architectural policies apply to its node; before a proposed action, dry-run its policy effect. Returns advisory rules or violations across structure, compatibility, provenance, ownership, and blast radius. Policies inform the agent; this tool does not block changes. |
| `get_divergences` | Where do the code and what's actually running disagree? Return ranked divergences between declared code/config and observed behavior: missing edges, version or host mismatches, compatibility violations, symbol/field mismatches, and observed failures. Each carries confidence and severity; use it for a broad audit before choosing a specific failing node. |
| `expand` | Walk one evidence-bearing hop from a node after investigate or an incident card points to a locus. "up" finds callers/dependents and "down" finds callees/dependencies; each neighbor is classified primary-failure, symptom-only, or unrelated so you can separate cause from downstream symptoms. |
| `relate` | Are these two nodes cause and symptom? Test a suspected cause-and-symptom pair. Returns a bounded connecting path, direction, per-hop provenance, and whether error/latency signal carries end to end. No path within the bound is reported as such, not as proof the nodes are unrelated. |
| `ask` | Ask the graph a question in plain language — the front door to NEAT. Reach for this FIRST, before Read/Grep/Bash, for any question about this system's behaviour, dependencies, failures, root cause, or blast radius. You do NOT need to know which tool or the exact node id: `ask` resolves the entities in your question to graph nodes and routes it to the right traversal (root cause, dependencies, observed runtime calls, incidents, divergences, blast radius), returning one compact answer with every fact provenance-tagged (EXTRACTED/OBSERVED/INFERRED/STALE) and confidence-scored. Ask what a node talks to, connects to, uses, hits, calls, reads from, or writes to for dependencies; add actually, in production, or at runtime for observed calls. Ask who calls or depends on a node, or for its consumers or callers, for blast radius. Ask about slow, latency, p95, or timing for runtime evidence; a why/failure question leads with root cause. Use the structured tools (get_root_cause, get_dependencies, …) when you already have a node id and want just that one traversal. When something is failing, investigate returns the whole incident in one call. |
| `neat_list_uninstrumented` | When the graph lacks expected runtime evidence, list project libraries outside automatic instrumentation coverage. Returns first-party, third-party, and gap libraries that may need an explicit instrumentation package. |
| `neat_lookup_instrumentation` | When a library is an instrumentation gap, look up its supported registry recipe. Returns the instrumentation package, matching version range, and registration snippet when one exists. |
| `neat_describe_project_instrumentation` | When OBSERVED evidence is missing, inspect this project's instrumentation wiring. Returns hook-file presence, .env.neat presence, and installed OTel dependencies before you change code. |
| `neat_apply_extension` | After reviewing an instrumentation gap and preferably previewing it, apply the chosen library extension. Installs the package and updates the OTel hook, package.json, and lockfile; repeating the same extension is a no-op. |
| `neat_dry_run_extension` | Before filling an instrumentation gap, preview the extension. Returns the exact file diff, dependencies, and install command without changing the project. |
| `neat_rollback_extension` | If a library extension needs reversing, remove its package.json dependency and hook registration. Returns the rollback result; run the package manager afterward because this tool does not refresh the lockfile. |
| `neat_list_connectable` | When a hosted graph lacks provider-side evidence, list the providers this project can connect. Returns control-plane options, or a configuration note when NEAT_CP_URL and a neat_pat_ NEAT_API_KEY are unavailable. |
| `neat_connect` | When authorized to add hosted provider evidence, connect a listed provider with its API credential. The control plane verifies and seals the credential; the daemon then polls or receives the supported telemetry into OBSERVED. Hosted only. |
| `neat_connection_status` | When provider evidence is absent or stale in a hosted graph, inspect connections and their connecting, healthy, error, or needs-reconnect status. Returns control-plane state, not a live graph traversal. |
| `neat_disconnect` | When authorized to remove a hosted provider integration, disconnect it and drop its stored connection. Returns the control-plane result; this changes future provider evidence, not source code. |
<!-- MCP_TOOL_TABLE_END -->

Hosted connector tools need `NEAT_CP_URL` and `NEAT_API_KEY`, a `neat_pat_` NEAT API key. Keys are minted by the control plane's `POST /me/tokens`; the app.neat.is console doesn't offer them yet. `neat login` stores a daemon token for graph queries; it does not configure control-plane connector tools.

Graph queries read the daemon's live graph. Instrumentation tools can change local instrumentation files and dependencies. Hosted connector actions call the control plane and can change connection state. NEAT does not call an LLM to answer graph questions.

`semantic_search` uses Ollama (`nomic-embed-text`) when reachable, otherwise it can initialize the in-process `Xenova/all-MiniLM-L6-v2` model. MiniLM downloads its ~23 MB quantized model on a cold cache. Set `NEAT_SEARCH_PROVIDER=substring` for search without model initialization or download, `ollama` to use only Ollama, or `transformers` to use MiniLM explicitly. An unset value keeps automatic selection. The same setting applies to the daemon and `neat watch`.

## Where OBSERVED comes from

The observed-facing read tools — `get_observed_dependencies`, `get_divergences`, `get_incident_history`, `get_recent_stale_edges` — reflect two OBSERVED sources, not one:

- **OTel spans** — pushed by the instrumented app at runtime. The `/neat extend` tools above are how that gets wired up.
- **Provider connectors** — NEAT polls supported provider APIs or receives their telemetry through a configured drain, then folds that data into the OBSERVED layer. Run `npx neat.is connector --help` for the current provider list; its usage text reads the connector registry. A provider can supply observed edges, incidents, and staleness even without an app span.

Connectors are configured out of band, not through this skill: `npx neat.is connector add <provider>` / `list` / `remove <id>` / `test <id>` (ADR-130). Credentials are stored as an env-var reference (`$VAR`) resolved at run time and redacted everywhere, so the agent reads the resulting OBSERVED data but never sees a secret. `GET /:project/connectors` reports each connector's poll health over REST if you need it.

A `ServiceNode` may carry a static `platform` hint inferred from repository configuration. It is an EXTRACTED claim, separate from connector observations; inspect the node's provenance rather than assuming a provider is connected.

## Install

For an npx-based setup, run:

```bash
npx neat.is skill --apply
```

This merges the `neat` MCP server into `~/.claude.json` without replacing other entries. To inspect and merge the configuration manually, run `npx neat.is skill --print-config`. If `neat` is installed globally, the same commands work without `npx`.

<!-- GRAPH_FIRST_START -->
<!-- NEAT graph-first directive. Paste this block into your agent's project
     instructions — CLAUDE.md, AGENTS.md, .cursorrules, or the equivalent.
     Agent-agnostic: it is plain guidance, no Claude Code features required. -->

## Let NEAT investigate before you search files

This project has NEAT. It does the investigation for this system so you can
spend your effort on the code: what exists, what actually ran, where a failure
began, and what a change will reach. It answers from a live graph that fuses
code, data and infrastructure declarations with runtime traffic, incidents and
supported provider telemetry. The graph is deterministic: you supply the
reasoning about the fix; NEAT resolves named nodes and traverses recorded
evidence rather than asking an LLM to infer architecture from file names.

Every claim carries provenance and confidence. `EXTRACTED` comes from recognized
source or configuration, `OBSERVED` from spans or supported provider signals,
`INFERRED` from a bridged relationship, and `STALE` marks an observed edge that
went quiet. Missing runtime evidence does not prove a path never runs.

**For questions about this system's behavior, structure, data dependencies,
failures, or change impact, call the MCP `ask` tool (`mcp__neat__ask`) before
Read/Grep/Glob/Bash.** You do not need an exact node id. `ask` resolves names
and routes to the relevant graph traversal, returning provenance-tagged facts.
When MCP is unavailable, use the same door through the CLI:

```
npx neat.is ask "why is checkout failing?"
npx neat.is ask "what breaks if I change the orders table?"
npx neat.is ask "what does the payments service depend on at runtime?"
```

For a failing system, start with `investigate` — give it the service or the
symptom and it composes one work order: the recorded failure with its deploy/env
context, the likely cause chain with provenance, the blast radius, the governing
policies, and where declared and observed behaviour diverge. (`get_incident_card`
composes the same from an exact node id; `ask` what is failing first if you don't
know the node.) It is one view of the incident, not a separate source of truth;
NEAT also pushes this card to you when it detects a failure worth one (via `neat
monitor`), the work order handed to you rather than fetched. Then
`get_incident_history` and `get_root_cause` for the parts, and `expand` one hop at
a time with `relate` to test whether a suspected cause and symptom share a signal.

Before a change, use `get_blast_radius` and `check_policies` to see dependents
and advisory architectural rules. Use `get_divergences` to compare declared
intent with observed behavior, `get_graph_diff` to compare a saved snapshot
with the live graph, and `get_recent_stale_edges` when traffic goes quiet.
`get_dependencies` maps a node's outgoing graph; `get_observed_dependencies`
shows only seen runtime/provider calls. `semantic_search` finds node labels,
not arbitrary source text.

Trust the graph's answer by its provenance, and stop when the fault is localized
— the failing node and what is wrong with it. Match one query to the symptom
rather than re-running the same query or sweeping every tool; a provenance-tagged
result is the answer, not a cue to re-confirm it by reading source.

Read source when the graph does not model what you need: comments, arbitrary
string literals, config details, unsupported syntax, or a repository that has
not been extracted or connected. If a graph answer is empty, check the daemon
with `npx neat.is list` or restart it with `npx neat.is up`; wire MCP with
`npx neat.is skill --apply`.
<!-- GRAPH_FIRST_END -->

## Prerequisites

- Build a graph from this project with `npx neat.is` (or run `npx neat.is init . --apply` when setting it up manually). The first-run door starts a per-project daemon in the background.
- Run `npx neat.is skill --apply` to wire this MCP server into Claude Code. Use `npx neat.is list` to see the project's live daemon and its port; `npx neat.is up` restarts it if needed.
- The MCP server depends on `@neat.is/core`, so a fresh `npx -y @neat.is/mcp` installs about 560 MB the first time (about 300 MB with `--omit=optional`); a global `neat.is` install already carries it.

## What's not in MVP

- Auto-detection of an alternate Claude Code config path. The installer assumes `~/.claude.json`.
- Per-project skill overrides. The skill is user-scoped; project-level MCP config can be added later as a follow-up.
- Tool-level disable flags. Every tool is wired in; if you want to hide one, edit the snippet by hand.

## Where to look when it doesn't work

- `npx neat.is list` — shows registered projects and their daemon status/ports.
- `~/.claude.json` — the config file. Look for `mcpServers.neat`.
- `claude mcp list` — Claude Code's built-in inventory of MCP servers.
