Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 34 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ and serves it in your browser: the walkthrough, live code peeks, the diff,
commits, and a software map. You ask questions, leave anchored comments, and
approve or request changes. The agent answers and republishes.

It also explains a codebase. A **code explainer** is the same document over a
different unit: one pinned commit instead of a range, so a reader can see the
architecture well enough to spot design problems themselves. It has no diff and
nothing to approve, it surfaces structure rather than grading it, and it states
what it did not examine.

It does not review the code for you. It helps you understand it fast enough
to review it yourself.

Expand Down Expand Up @@ -133,6 +139,12 @@ and open it.
Click an identifier to see where it is defined at that commit; Ctrl-click
jumps there.
- **Commits**: the commits between base and head.
- **Coverage** (explainers): every file in scope at the pinned commit, in one
of three states - anchored in the document, placed on the map only, or not
examined - with the parts of the system they belong to, the references that
cross between those parts, and the names defined in more than one of them.
Derived at publish, so what the explainer skipped is a stated fact rather
than something the reader has to infer.
- **Map**: systems, containers, components and code, with what the change
added, removed or touched, linked to files and code.
- **Threads**: _Ask now_ sends a question to the agent immediately and the
Expand All @@ -153,18 +165,19 @@ bar.

## CLI

| Command | Purpose |
| --------------------------------------------------------------------- | ------------------------------------------------------------ |
| `thurview scaffold [--pr N \| --base R --head R]` | Create a review pinned to exact commits (`--update` re-pins) |
| `thurview info [--all]` | Reviews bound to this worktree |
| `thurview publish --review ID [--view T] [--open]` | Validate the document and map, seal a revision |
| `thurview open --review ID [--view T]` | Start the server if needed and open the browser |
| `thurview wait --review ID [--timeout S]` | Block until the reader needs the agent |
| `thurview threads list\|get\|reply\|resolve` | Read and answer threads |
| `thurview graph interfaces\|impact\|callers\|tests-for\|architecture` | Ask the code graph at the pinned commits |
| `thurview serve` / `thurview stop` | Run the server in the foreground / stop the background one |
| `thurview setup hooks\|skill\|status` | Session hooks, agent skill, install state |
| `thurview update` | Self-update from npm |
| Command | Purpose |
| --------------------------------------------------------------------- | ---------------------------------------------------------------- |
| `thurview scaffold [--pr N \| --base R --head R]` | Create a review pinned to exact commits (`--update` re-pins) |
| `thurview explain [<path>] [--commit R]` | Create a code explainer of a codebase or subsystem at one commit |
| `thurview info [--all]` | Reviews bound to this worktree |
| `thurview publish --review ID [--view T] [--open]` | Validate the document and map, seal a revision |
| `thurview open --review ID [--view T]` | Start the server if needed and open the browser |
| `thurview wait --review ID [--timeout S]` | Block until the reader needs the agent |
| `thurview threads list\|get\|reply\|resolve` | Read and answer threads |
| `thurview graph interfaces\|impact\|callers\|tests-for\|architecture` | Ask the code graph at the pinned commits |
| `thurview serve` / `thurview stop` | Run the server in the foreground / stop the background one |
| `thurview setup hooks\|skill\|status` | Session hooks, agent skill, install state |
| `thurview update` | Self-update from npm |

thurview is an [AXI](https://axi.md): built for agents that drive it through a
shell. Output is [TOON](https://toonformat.dev) on stdout, errors are
Expand All @@ -186,16 +199,22 @@ The agent writes three files in `~/.thurview/reviews/<id>/`:
- `data.yaml`: typed inputs: `actors`, `anchors` (file, from, to, graph),
`stores`, `interfaces` (a capability line per derived entry, plus the
interfaces the graph cannot see).
- `map.yaml`: the software map at head, optionally at base.
- `map.yaml`: the software map at head, optionally at base. In an explainer it
carries the breadth the prose has no room for, and a node's `files` globs are
what let a file count as placed rather than not examined.
- `theme.yaml`: the look, derived from the reviewed project's own design
system (tokens, fonts, shape, code palette). Empty means the default skin.

An explainer writes the same files, minus `interfaces`: there is no change to
derive a delta from, and `graph: base` on an anchor is an error because there
is one commit.

`thurview publish` rejects an anchor whose file or lines do not exist at the
pinned commit, a call stack frame that claims an added or removed call the
diff does not show, a storage operation on an unknown field, a map edge
to an unknown node, an interface annotation for a symbol the change did not
move, and a declared interface whose anchor holds no added or deleted line.
The full format is in
move, a declared interface whose anchor holds no added or deleted line, and an
explainer that anchors nothing at all. The full format is in
[skills/thurview/references](skills/thurview/references).

Optional guidance for the agent: `~/.thurview/THURVIEW.md` for you,
Expand Down
42 changes: 31 additions & 11 deletions skills/thurview/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
---
name: thurview
description: Author and publish a thurview review - a guided, evidence-anchored explanation of a branch, pull request or commit range that the reader opens in the browser, annotates, asks questions about, and approves or sends back. Use when the user asks to review a branch or PR, to explain or walk through a change, "review my branch against main", to explain how a codebase or subsystem works, or invokes /thurview. Not for a pass/fail bug hunt.
description: Author and publish a thurview document - a guided, evidence-anchored explanation the reader opens in the browser, annotates, asks questions about, and approves or sends back. Two kinds: a review of a branch, pull request or commit range, and a code explainer of a whole codebase or one subsystem at a pinned commit. Use when the user asks to review a branch or PR, to explain or walk through a change, "review my branch against main", to explain how a codebase or subsystem works or where its design problems might be, or invokes /thurview. Not for a pass/fail bug hunt.
user-invocable: true
argument-hint: "[<pr-number|pr-url> | --base <ref> --head <ref> | <architecture topic>]"
argument-hint: "[<pr-number|pr-url> | --base <ref> --head <ref> | explain [<path>]]"
---

# thurview

There are two kinds of document, and the first decision is which one the
request asks for.

- A **review** explains a CHANGE: a branch, a pull request, a commit range. It
has a diff, commits and an interface delta, and the reader approves it or
sends it back. Everything below describes it.
- A **code explainer** explains a CODEBASE, or one subsystem, at a single
pinned commit, so the reader can see the architecture well enough to spot
design problems themselves. It has no diff and nothing to approve, and it
states what it did not examine. Read
[Code explainer](references/code-explainer.md) and follow that instead.

The agent studies the change and writes a short document in which every claim
about code is anchored to an exact file and line range at a pinned commit.
thurview validates those anchors, seals a revision, and serves it in the
Expand Down Expand Up @@ -41,9 +53,11 @@ directory; `thurview <command> --help` shows flags and examples.

$ARGUMENTS

Empty: the current branch against its up-to-date trunk. A PR number or URL:
that pull request. `--base`/`--head`: that range. Anything else: an
architecture review of that topic in the current repository.
Empty: a review of the current branch against its up-to-date trunk. A PR
number or URL: that pull request. `--base`/`--head`: that range. `explain`, or
a request to explain the codebase, a subsystem or its architecture rather than
a change: a code explainer, per
[Code explainer](references/code-explainer.md).

## Before authoring

Expand All @@ -60,7 +74,8 @@ Read [Components](references/components.md) before you edit `data.yaml` or add
a fenced component. Read [Lifecycle](references/lifecycle.md) for statuses,
storage and thread rules. Read [Software map](references/software-map.md)
before you author `map.yaml`. Read [Theme](references/theme.md) before you
write `theme.yaml`.
write `theme.yaml`. Read [Code explainer](references/code-explainer.md) when
the request is a codebase rather than a change.

## Workflow

Expand Down Expand Up @@ -281,12 +296,17 @@ Then publish again (step 7), tell the user what changed since the previous
revision in a line or two, and wait again (step 9). A republish requires zero
open submitted comment threads; questions do not block.

## Architecture reviews
## Explaining a codebase rather than a change

Do not pin the same commit as base and head to fake it. That leaves a review
whose Files, Commits and interface-delta surfaces all describe a change that
does not exist, which is a claim, not a gap.

Pin the same commit as base and head: `thurview scaffold --base HEAD --head
HEAD`. Choose sections that describe the system (data flows, state, storage,
module boundaries) and skip diff-specific ones. Scope to one subsystem. All
other steps are the same; the Files tab shows any file at head on request.
Run `thurview explain [<path>]` instead and follow
[Code explainer](references/code-explainer.md). It is the same loop - pin,
author, publish, wait, answer - over a document kind whose unit is a codebase:
no diff, no commits, no interface delta, and a Coverage tab stating what the
document reached and what it did not.

## Completion criteria

Expand Down
166 changes: 166 additions & 0 deletions skills/thurview/references/code-explainer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
# Code explainer

A **review** explains a change. An **explainer** explains a codebase, or one
subsystem of it, at a single pinned commit, so the reader can see the
architecture well enough to spot design problems themselves.

Same engine, different unit. It shares anchors, peeks, the map, threads,
revisions and the publish → wait → answer loop. It has no diff, no commits and
no interface delta, because those are claims about a change and there is no
change. Where a review shows the interface delta, an explainer shows
**coverage**: what it examined at that commit, and what it did not.

| Tab | Review | Explainer |
| ------------- | ---------------------------------- | --------------------------------------------- |
| Review | the walkthrough, with the delta | **Explainer**: the document, with coverage |
| Files | split diff of the changed files | absent |
| Commits | base..head | absent |
| Map | parts, marked added/changed/removed | parts at the pinned commit |
| Coverage | absent | **what the document reached, and what it did not** |
| Threads | ask, comment, decide | same, and the decision reads *Done reading* / *Send it back* |

## When to write one

Write an explainer when the request is about the code as it stands: "explain
this codebase", "how does the server work", "walk me through `src/graph`",
"I want to see the architecture". Write a review when the request is about a
change: a branch, a pull request, a range.

If the request is a change, do not reach for an explainer because the change is
large. A large change is still a change.

## The document kind, in one command

```sh
thurview explain # the whole repository at HEAD
thurview explain src/server # one subsystem
thurview explain --commit v1.2.0 # a released commit rather than HEAD
```

The positional argument is a path or a glob; a bare path means that directory
and everything under it. It is the **scope**, and everything else obeys it:
`graph architecture` reports the clusters inside it, and coverage accounts for
every file inside it. A scope that matches no file at that commit is refused.

Record `explainer.id`, `explainer.dir`, `explainer.commit`, `explainer.scope`
and `scale.filesInScope` from the output. Everywhere else the id is passed as
`--review <id>`; that flag names a document, whichever kind it is.

## Keeping it short without lying about it

A review is bounded by its diff. A codebase is not, and this is the hard part:
evidence-anchored prose over a whole repository either runs unreadably long or
quietly leaves most of the system out. Prose that leaves things out silently is
misleading about architecture, which is the one thing an explainer must not be.

So work in three layers, and let each carry what it is good at.

1. **System — the map carries breadth.** Author `map.yaml` first, seeded from
`thurview graph architecture --review <id>`: communities become nodes, their
files become the node's `files` globs, and the edges between communities
become edges. Every part of the scope should appear here, including the parts
the prose will not reach. See [Software map](software-map.md) for the shape.
2. **Subsystem — the prose carries depth.** Pick the parts that carry the most
structure and the most traffic, and explain those. Three to six sections.
Everything else stays on the map.
3. **File and symbol — anchors carry the proof.** Every claim gets an anchor.
The reader opens code where they want it and nowhere else.

**Select by structure, not by taste, and say what you selected on.** The graph
gives you the basis: cluster size in files and symbols, the hub symbols of each
cluster (most referenced), and the reference counts on the edges between
clusters. Say in the document which parts you took and why they were the ones -
"the two clusters with the most traffic between them" is a reason a reader can
check. "The interesting bits" is not.

## Coverage is derived, not claimed

`thurview publish` accounts for every file in scope at the pinned commit and
puts one of three states on it:

- **explained** - an anchor in the document points into the file.
- **placed** - a map node's `files` globs match it, and no anchor does. The
reader is told where it sits, not what it does.
- **not examined** - neither.

The counts go above the document and onto the Coverage tab, and `publish`
prints them with the files it did not examine. You cannot forget to state
coverage, and you cannot overstate it: to move a file out of *not examined* you
have to actually anchor it or actually place it on the map.

Two consequences worth planning for:

- **An explainer without a map counts everything the prose does not anchor as
not examined.** `publish` warns when there is no map. That is a true
statement, and usually not the one you want to make: author the map.
- **A broad glob is visible.** The Coverage tab lists each map node with the
globs it owns and how many files they match, so `**/*` on one node inflates
nothing quietly.

Coverage also states what the code graph could not read: files in languages it
does not parse (`thurview graph` covers TypeScript, JavaScript, Python, Go,
Rust and Java), and whether its file list was capped. Those files are absent
from the structure, not empty. If a large part of the scope is outside the
graph, say so in the document rather than letting the map imply the system is
smaller than it is.

## Surface structure; do not grade it

thurview's thesis holds here: *it does not review the code for you; it helps
you understand it fast enough to review it yourself.* An explainer exists so
the reader can **detect** design problems. That is only consistent with the
thesis if you surface structure and leave the conclusion to them.

The test: **every fact in an explainer is a count, or a list of named things,
at the pinned commit, that the reader could re-derive with `thurview graph`.**

Observation - write these:

- "`src/server` is referenced from four other parts; it references one."
- "`Store` is defined in `src/db.ts` and `src/cache.ts`."
- "The API layer reaches the database layer in 14 places and the model layer in
2; the model layer reaches the API layer in 6."
- "Nothing in the scope references `legacy/` at this commit."
- "No test file reaches this cluster." (a count of zero, stated as one)

Judgement - never write these:

- "This violates separation of concerns."
- "The god object here should be split."
- severities, scores, "issues found", "critical", "smell", a ranked list of
problems, or a recommendation section.

The difference is not tone. "A module with 14 inbound dependencies" is
something the reader acts on; "an over-coupled module" is a verdict they cannot
check. When you are unsure, write the count and stop. If a structure genuinely
worries you, the honest move is a question in the document - "the two stores
both define `Session`; whether that is one concept or two is not visible from
the code" - not a finding.

## Workflow

1. `thurview explain [<scope>]`. Note the id, the commit and the scope.
2. `thurview graph architecture --review <id>`. This is the structure at the
pinned commit; do not re-derive it by reading directories.
`thurview graph callers <name>` and `tests-for <name>` answer the follow-ups.
`graph interfaces` and `graph impact` compare two commits and are refused.
3. Author `map.yaml` from the architecture output, covering the whole scope.
Dispatch a sub-agent for it if you have one, exactly as a review does.
4. Author `review.md` and `data.yaml` per [Document authoring](document-authoring.md),
minus the interface-delta section: an explainer has none, and declaring
`interfaces` in `data.yaml` is an error. So is `graph: base` on an anchor -
there is one commit.
5. `theme.yaml` as usual - see [Theme](theme.md).
6. `thurview publish --review <id>`. Read `coverage` and `notExamined`. If the
split is not the one you meant, anchor or place more and publish again.
7. `thurview open --review <id>`, then `thurview wait --review <id>`. The loop,
the statuses and the thread rules are identical to a review; see
[Lifecycle](lifecycle.md).

## Hand over

In a few lines: the url, the scope and the commit, the coverage line in its own
words (including how many files were not examined), which parts you chose to
explain and on what basis, and that you are waiting for their questions. Do not
list the design problems you think you saw. The document is built so the reader
finds them.
Loading