Nexus decouples the Machine Implementation (code) from the Human Intent (narrative) by maintaining a synchronized, human-readable shadow branch alongside your code. Instead of reviewing a code diff, a reviewer reads a short, jargon-free explanation of what changed and why.
main— your code, unchanged. Always the source of truth.explainer— an orphan branch mirroringmain's file structure, one Markdown file per code file, narrating intent instead of syntax.
This repo is the standalone nexus CLI: it manages the explainer branch
(nexus init, nexus show, nexus map, ...) and ships the narrate
skill that a coding agent uses to actually write the narrative. It does not
depend on any other project — a plain git repository is all it needs.
go install github.com/sunprema/nexus-cli/cmd/nexus@latestThis installs nexus into $(go env GOPATH)/bin (~/go/bin by default). Make
sure that directory is on your PATH — add this to your shell profile if
nexus isn't found afterward:
export PATH="$(go env GOPATH)/bin:$PATH"Verify the install:
nexus --version # or: nexus -vOr build from source:
git clone https://github.com/sunprema/nexus-cli.git
cd nexus-cli
go build -o nexus ./cmd/nexusPrebuilt binaries for macOS/Linux/Windows are attached to each GitHub release.
nexus init # create the 'explainer' branch, .nexus/ config, and the post-commit hook
nexus sync # list commits queued for narration
nexus show <path> # print a file's current explainer entry
nexus map # index every narrated file and guided tour
nexus diff <path> # diff a file's last two narrated versions
nexus check # report files still flagged with a desync marker
nexus tour <slug> # print a guided tour's stops
nexus history [path] # incidents, decisions, and reverts recorded against a path
nexus speak <path> # read a file's explainer entry aloud (--summary for the gist)nexus init installs a post-commit git hook that queues every commit for
narration in .nexus/pending.json — cheaply, with no LLM call. Narration
itself happens later, via the narrate skill running inside your coding
agent (see below): it drains that queue, writes the explainer entries, and
verifies each one against the code with an independent pass before
committing.
Run nexus <command> --help for full flag and argument details.
nexus init writes .nexus/settings.json, the repo's Nexus configuration:
{
"source_of_truth": "main",
"explainer_branch": "explainer",
"verifier_model": ""
}-
source_of_truth— always"main". Recorded, not configurable: a code/explainer disagreement is always resolved in favor of the code (see Desync markers), never by picking a different authority per repo. -
explainer_branch— always"explainer". Recorded, not configurable: the rest of Nexus's tooling assumes this name, so nothing is gained by letting it drift per repo. -
verifier_model— the only field meant to be edited. Names the model thenarrateskill's independent Verifier subagent should run on (see Desync markers). Empty (the defaultnexus initwrites) means "use the coding agent's normal subagent model." Set it to pin verification to a specific model, e.g.:"verifier_model": "claude-opus-5"
nexus init only writes this file if it doesn't already exist — it never
overwrites or adds fields to a settings.json from a previous run, so
edit it by hand.
nexus mcp runs a read-only Model Context Protocol
server over stdio, exposing the explainer branch as five tools instead of
requiring an agent to shell out to nexus and parse its output:
nexus_explainer— a code file's current explainer entry (same data asnexus show <path> --json). An agent should call this before reading or editing a file: the explainer often already captures intent and edge cases that would otherwise have to be re-derived from the code.nexus_map— the whole-branch index of every narrated file and guided tour (same data asnexus map --json). Meant to be called first when orienting in an unfamiliar repo — the cheapest way to learn what's there before reading any code.nexus_tour— one guided tour's ordered stops (same data asnexus tour <slug> --json).nexus_history— the incident/decision/revert records anchored to a file or directory (same data asnexus history [path] --json). An agent should call this before changing an area it doesn't know well — a record often says exactly what not to change and why. See History records.nexus_explaineralready embeds the same records for a single file.nexus_speak— reads an entry (or any text the agent composes) aloud through the machine's own text-to-speech, for "read me the summary of auth.py" (same engine asnexus speak; see Reading aloud). The one tool here with a side effect: it returns as soon as audio starts, andstop: trueinterrupts it.
All five share the exact same lookup code the CLI commands use, so an MCP client and a shell script can never see different results. Use MCP over shelling out when the host doesn't want to spawn a subprocess per lookup, or when it can hold a longer-lived server connection across a whole session instead of one CLI invocation per question.
Any MCP host that can launch a stdio server works. The general shape:
{
"mcpServers": {
"nexus": {
"command": "nexus",
"args": ["mcp"]
}
}
}- Claude Code:
claude mcp add nexus -- nexus mcp(add-s projectto commit it to the repo's.mcp.jsonfor the whole team, instead of just your own local config). - Cursor / other JSON-config hosts: add the block above to the host's
MCP config file (e.g. Cursor's
.cursor/mcp.json). - Any other MCP-host agent: point it at the
nexus mcpcommand the same way — it only needs to know how to launch a stdio server.
nexus must be on PATH for the host to find it. Verify the server
responds by asking the agent to call nexus_map.
nexus speak reads an explainer entry through the operating system's own
text-to-speech engine — macOS say, Linux espeak-ng/espeak/spd-say,
Windows System.Speech — so it works from a bare terminal and from any
MCP-host agent (via nexus_speak) with nothing else installed. No browser,
no editor extension.
nexus speak src/auth.py # read the whole narrative
nexus speak src/auth.py --summary # just the one-sentence gist
nexus speak --text "Anything else" # arbitrary text; "-" reads stdin
nexus speak src/auth.py --print # show what would be read, silently
nexus speak --stop # interrupt whatever is playingMarkdown syntax, code fences and mermaid diagrams are stripped first so the
audio is prose rather than punctuation; a desynced entry is announced as
"this explainer may be out of date with the code" instead of reading the
marker line. Only one thing speaks at a time — a new speak replaces the
one in progress.
Pick a voice with --voice <name>, or set NEXUS_SPEAK_VOICE once for your
machine (a personal preference, so it's an environment variable rather than
a field in the committed settings.json). The names are whatever your
engine accepts — say -v ? lists them on macOS.
With an agent, just ask: "read me the summary of src/auth.py", "read me
the request-lifecycle tour", "stop reading". The agent fetches the text via
the other tools where it needs to and hands it to nexus_speak.
Narration requires an LLM, so it isn't built into the nexus binary — it's
a skill (skills/narrate/SKILL.md) that a coding agent runs. This repo
doubles as a plugin source for the agents that support skill/plugin
discovery:
- Claude Code:
/plugin marketplace add sunprema/nexus-cli, then/plugin install nexus. - Codex / Cursor: point their plugin config at this repo
(
.codex-plugin/plugin.json,.cursor-plugin/plugin.json). - OpenCode: see
.opencode/INSTALL.md. - Gemini:
gemini-extension.jsonat the repo root.
Once installed, ask your agent to "narrate this change" after making a
commit, or let it pick up .nexus/pending.json on its own.
The prompt/style the skill writes in is editable per-repo at
.nexus/skills/narrator-prompt.md (created by nexus init) — tune tone,
vocabulary, or conventions without a CLI release.
Every explainer file starts with a small YAML block, the same idea as a
SKILL.md's name/description frontmatter — a cheap way to know what a
file is about before reading the whole narrative:
---
path: src/auth.py
summary: One sentence — the gist, for scanning across many files fast.
source_commit: <the code commit this narrative describes>
desynced: false
---summaryis deliberately shorter than the body's own "What this does" section — it's built for skimming many files quickly (nexus map,nexus_mapover MCP), not for understanding one file deeply.source_committies the narrative to the exact code commit it describes.desyncedis the machine-readable version of the desync marker below —nexus check/nexus showtrust this field over scanning prose for the marker text whenever it's present, since prose that merely mentions the marker text can't be confused with an actual one.
A file with no frontmatter (narrated before this feature existed) still works fine — commands fall back to scanning the file body directly.
Every time the narrate skill writes an explainer entry, a second,
independent LLM pass (the "Verifier") checks the drafted narrative against
the actual code. If they disagree — e.g. the code retries 3 times but the
narrative says 5 — the skill doesn't block or reject the commit; main
stays authoritative no matter what. Instead it marks that one explainer
entry as desynced:
- an inline
> [!WARNING]Nexus desync callout in the Markdown body, so it's visible to a human just reading the file on GitHub or in an editor preview, and desynced: truein the file's frontmatter (see above), so a tool can check status without scanning prose.
A marker just means "treat this explainer entry as stale/unreliable until
it's re-narrated" — it's informational, not blocking. It clears itself the
next time that file is narrated: the Verifier re-checks from scratch, and
the marker is only written again if the disagreement still exists. There's
no separate nexus resolve command — fix the code, or hand-edit the
narrative, and let the next narration pass confirm agreement.
nexus check scans the explainer branch and reports every file still
carrying an unresolved marker, so a desync doesn't require reading every
file to notice. nexus show <path> and nexus_explainer (MCP) surface the
same desynced status for one file at a time.
By default the Verifier runs on whatever model drafted the narrative; set
verifier_model in Settings to pin it to a different model
instead.
An explainer entry describes what a file is now. It has no memory of
what happened to it: after a revert it reads as if nothing changed, and
"we tried X, it broke production, we went back" survives only in
git log. History records hold that — tiny, path-anchored notes under
.nexus/history/ on the explainer branch, one per event:
---
kind: incident # incident | decision | revert
title: "Partial refunds timed out under load"
date: 2026-03-04
source_commit: <the code commit>
paths:
- src/payments
ref: "INC-4471" # a pointer to the team's ticket/ADR — never its contents
link: "https://…" # optional
---
The ledger check retried 5 times and each retry re-locked the row. Retries
were cut to 3 with backoff; don't raise them again without load-testing.The narrate skill writes one only when the commit itself carries a
signal, so nothing new has to be remembered:
- an
Incident: INC-4471orDecision: ADR-0006git trailer in the commit message (plus an optionalLink: <url>trailer), - a revert (
git revert's own message shape), or - a commit that adds or changes a file under an
adr/directory.
It never guesses from words like "fix" in a subject — a false record costs more trust than a missed one — and every record must be anchored to at least one path; that's the line between "context for the code" and "a wiki in git", and Nexus stays on the code side of it.
Records deliberately stay out of the explainer file, so the narrative reads clean. They surface where a reader is already looking:
nexus history # every record, newest first
nexus history src/payments # records for a directory (or a file, or a parent/child of one)
nexus show src/payments/refund.go --json # 'history' field carries the same recordsand over MCP via nexus_history, or embedded in nexus_explainer's
result — so an agent about to edit a file sees what has gone wrong there
before, without a second lookup.
nexus-vscode is a VS Code
extension for reading explainer entries without leaving the editor: a
CodeLens on every file shows its narration status, and clicking it opens
the explainer split-screen beside the code. It shells out to this CLI
(nexus show/diff/map/tour), so it needs nexus on PATH.
docs/ is a static single-page viewer for any repo's explainer branch —
paste owner/repo, get every narrated file with its summary, the
narrative beside the code, and the guided tours. Nothing to install: it
reads the branch listing from GitHub's tree API once and every file from
raw.githubusercontent.com, so a Nexus repo can be shown to someone from
a link:
https://<owner>.github.io/nexus-cli/?repo=sunprema/nexus-cli&file=internal/cli/show.go&view=split
Every piece of state (file, line, tour stop, layout) lives in the query
string, so any view is shareable. Public repos only — the page holds no
token. See docs/README.md for the parameters, the
conventions it mirrors from this CLI, and how it is deployed
(.github/workflows/pages.yml, Pages source set to "GitHub Actions").
go build ./...
go vet ./...
go test ./...
golangci-lint run ./...CI (.github/workflows/ci.yml) runs the same checks on Linux, macOS, and
Windows. Releases are built with goreleaser on
tag push (.github/workflows/release.yml).
MIT — see LICENSE.