@nurix/etna 0.20.18 → 0.20.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  {
2
- "fingerprint": "993a4863fa1f",
2
+ "fingerprint": "55061d9eaae9",
3
3
  "harnesses": {
4
4
  "code": {
5
5
  "plugin": "code",
@@ -10,7 +10,7 @@ model: sonnet
10
10
  You are the execution shell for bulk tracker work. Your FIRST action: read the `issue-bridge` skill in `.claude/skills/issue-bridge/SKILL.md` — it is the method — then the connector pack for the tracker(s) in play under its `references/trackers/`. This file adds only what a batch needs beyond the skill:
11
11
 
12
12
  - **Batching.** Many items → triage each independently through the skill's method; one dossier per item, never a merged mega-dossier. Order by tractability (concrete symptoms first); if the batch is larger than the session can honestly cover, cover fewer items *fully* and name what you dropped — announced omission over silent thinning.
13
- - **Shared context once.** Load the ownership index, the owning-doc map, and the codegraph tier once at the start; reuse across items instead of re-deriving per issue.
13
+ - **Shared context once.** Load the ownership index, the owning-doc map, and the `apollo` tool tier once at the start; reuse across items instead of re-deriving per issue.
14
14
  - **Approval aggregation.** Anything that would write to the tracker accumulates into one approval list presented at the end — never one ask per item, never a write without the ask.
15
15
  - **Report contract** (machine-read): per item — id · classification · verdict (one line) · confidence · dossier path; then the batch tail — items dropped (with reason), tracker writes awaiting approval, defects found in the skill or connector packs (a field run is always also a test of the method).
16
16
  - All the skill's boundaries bind you unchanged; a standing repo ruling (e.g. "never post to this upstream") overrides any approval you're offered.
@@ -237,9 +237,9 @@ Apply the **§ Strategy memory** retirement procedure to `docs/memory/maintenanc
237
237
  - **Enforce the memory cap on every run** (§ Strategy memory) — you are its only writer, so no one else can do it.
238
238
  - **A clean report is valid** — do not invent issues.
239
239
  - **Declarative, idempotent.** Re-running baseline mode on a current repo reshapes nothing — a second pass is just the audit plus the module proposal. Converge to the current shape; never replay a version ladder; never reconstruct a past shape.
240
- - **Brownfield extraction (operator-ruled 2026-08-19).** When baseline mode meets a repo with a real source tree and few or no feature docs, the module *proposal* is not enough — run the extraction pass: produce feature docs for the recognized modules (docs/features/, full frontmatter: `owns:` · `module:` · `keywords:` · `status:` · `last-reviewed:` · `type: feature` · `derivation: "extracted (baseline YYYY-MM-DD, codegraph + source read)"`), plus the architecture, tests, and operations layers. Use the `codegraph` skill where installed — localize through the index before reading; the docs record intent, the index answers facts. **Every extracted feature doc carries a `## History & Ownership` section** — top contributors with recency, churn posture, and bus-factor notes, dated "as of YYYY-MM-DD" (operator ruling: this section is mandatory in extraction output even though doc-lint flags dated narrative in truth docs; the findings are accepted for now, and a future harness version may retire the section in favor of live index pointers). `status:` is evidence-graded: `deprecated` only when history shows the area dead, never by guess. Scale by fan-out (one extraction lane per module, a completeness critic over the result) rather than one long cold read.
240
+ - **Brownfield extraction (operator-ruled 2026-08-19).** When baseline mode meets a repo with a real source tree and few or no feature docs, the module *proposal* is not enough — run the extraction pass: produce feature docs for the recognized modules (docs/features/, full frontmatter: `owns:` · `module:` · `keywords:` · `status:` · `last-reviewed:` · `type: feature` · `derivation: "extracted (baseline YYYY-MM-DD, apollo graph + source read)"`), plus the architecture, tests, and operations layers. Use the `apollo-graph` skill where installed — localize through the index before reading; the docs record intent, the index answers facts. **Every extracted feature doc carries a `## History & Ownership` section** — top contributors with recency, churn posture, and bus-factor notes, dated "as of YYYY-MM-DD" (operator ruling: this section is mandatory in extraction output even though doc-lint flags dated narrative in truth docs; the findings are accepted for now, and a future harness version may retire the section in favor of live index pointers). `status:` is evidence-graded: `deprecated` only when history shows the area dead, never by guess. Scale by fan-out (one extraction lane per module, a completeness critic over the result) rather than one long cold read.
241
241
  - **Diagrams ride the baseline (operator-ruled 2026-08-24).** Whenever baseline mode produces or converges the architecture layer, draw two ASCII diagrams from the real source, each in its own fenced code block: (1) an **architecture diagram** in the system-design/architecture doc — the actual processes, entry points, and wire surfaces as boxes, the calls/queues/files between them as labelled arrows; (2) a **DB ER diagram** wherever the repo declares a relational schema (DDL, migrations, an ORM schema) — one box per table listing its key columns, FK edges drawn to the table they reference, cardinality on the edge; it lands in the domain-model doc, or `docs/architecture/data-model.md` when none exists. Box-drawing characters (`┌─┐│└┘├┤`), width ≤ 100 columns. Derived only from what the code declares — a diagram never invents a component the source does not show, and a repo with no relational schema gets **no** ER diagram rather than an imagined one. Diagrams are truth-document sections: later baselines and audits converge them in place like any other section.
242
- - **Tool tiers.** The SessionStart context names each manifest-declared tool with its tier; calibrate the run to it, never stall on it. **Present-fresh** (`Tool: codegraph 0.2.0`): use it — check `codegraph projects` for staleness, re-run `codegraph index` if HEAD has moved, then localize every question through the index before reading source. **Present-stale** (below the catalog minimum): still use it, but note the version gap and the upgrade command in the run report — a stale contract may lack answer shapes the skill assumes. **Absent** (`Tool: codegraph MISSING`): fall back to the cold method (Glob/Grep/read), state in the run report that the tool was absent and give the install command — degraded output is acceptable, silent degradation is not.
242
+ - **Tool tiers.** The SessionStart context names each manifest-declared tool with its tier; calibrate the run to it, never stall on it. **Present-fresh** (`Tool: apollo 0.9.0`): use it — localize every question through `apollo graph` before reading source, and never run an index step first: the family re-indexes a stale store before it answers, so the only freshness decision left is the deliberate `--no-refresh`. **Present-stale** (below the catalog minimum): still use it, but note the version gap and the upgrade command in the run report — a stale contract may lack answer shapes the skill assumes. **Absent** (`Tool: apollo MISSING`): fall back to the cold method (Glob/Grep/read), state in the run report that the tool was absent and give the install command — degraded output is acceptable, silent degradation is not.
243
243
  - **One sentinel.** `docs/structure.md` `harness-version` is the only baseline/version marker.
244
244
  - **Modules are labels, layout-blind.** Seed from the code's bounded contexts; never from `pnpm-workspace.yaml`/workspace walls. Propose, don't force; acting is a `module:` tag, never a folder.
245
245
  - **You orchestrate docs; the `documentation` skill supplies templates.** It is a library — never expect it to baseline.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "harness": "code",
3
3
  "name": "code",
4
- "version": "3.16.6",
4
+ "version": "3.17.1",
5
5
  "files": [
6
6
  ".prettierignore",
7
7
  ".prettierrc.json",
@@ -17,13 +17,13 @@
17
17
  ],
18
18
  "tools": [
19
19
  {
20
- "name": "codegraph",
21
- "probe": "codegraph --version",
22
- "min": "0.2.1",
23
- "install": "npm install -g @nurix/codegraph",
24
- "skill": "codegraph"
20
+ "name": "apollo",
21
+ "probe": "apollo --version",
22
+ "min": "0.9.0",
23
+ "install": "npm install -g @nurix/apollo",
24
+ "skill": "apollo-graph"
25
25
  }
26
26
  ],
27
27
  "docsRoot": "docs",
28
- "digest": "79daa8edeb53"
28
+ "digest": "133da6603311"
29
29
  }
@@ -73,7 +73,7 @@ function detectPackageManager(projectDir) {
73
73
  // .claude/harness.json at install): probed at SessionStart, never assumed, never required.
74
74
  //
75
75
  // TWO TIERS, deliberately — `present` and `absent`. An earlier draft reported `present-fresh`,
76
- // which the probe cannot actually know: `codegraph --version` proves a binary exists and says
76
+ // which the probe cannot actually know: `apollo --version` proves a binary exists and says
77
77
  // nothing about whether THIS repo is indexed. A 22k-commit repo indexed at 23% once reported
78
78
  // present-fresh, and a probe that over-claims is worse than an absent tool, because absence
79
79
  // degrades honestly. Index freshness is established by the skill on its first query, where the
@@ -106,7 +106,15 @@ function toolsLines(projectDir) {
106
106
  if (v && v.localeCompare(tool.min, undefined, { numeric: true }) < 0)
107
107
  extra = ` — BELOW min ${tool.min}; update: ${tool.install || "see etna/tools/" + tool.name + ".md"}`;
108
108
  }
109
- out.push(`Tool: ${version}${extra}`);
109
+ // The present line NAMES the tool, because the probe's own output cannot be relied on to.
110
+ // Binaries disagree: `codegraph --version` printed "codegraph 0.2.1", `apollo --version`
111
+ // prints a bare "0.9.0" — which rendered as `Tool: 0.9.0`, a line that tells a session
112
+ // nothing about WHICH tool is present while the absent line right below has always said so.
113
+ // The prefix is skipped when the binary already named itself, so neither shape doubles up.
114
+ const named = version.toLowerCase().startsWith(String(tool.name).toLowerCase())
115
+ ? version
116
+ : `${tool.name} ${version}`;
117
+ out.push(`Tool: ${named}${extra}`);
110
118
  } else {
111
119
  out.push(
112
120
  `Tool: ${tool.name} MISSING — agents fall back to cold reads; install: ${tool.install || "see etna/tools/" + tool.name + ".md"}`,
@@ -0,0 +1,64 @@
1
+ ---
2
+ name: apollo-graph
3
+ requires-tool: apollo
4
+ description: Query the code graph before reading source. An LLM-first codebase index (symbols, call and data references, git history, co-change coupling, ownership) answering whole questions in one call, through `apollo graph`. Use it to localize, scope, and assess blast radius on this repository; use grep/read for string literals, mechanism, and data flow — the skill states which is which. Applies to any task that starts with "where is", "who calls", "what changed", "who owns", "what breaks", or "is this tested".
5
+ ---
6
+
7
+ # apollo graph — the index-first method
8
+
9
+ **If the tool is absent** (`apollo --version` fails): do not stall. Read `.claude/state/decisions.tsv` for `tool.apollo`.
10
+
11
+ - **`declined`** — fall back to the cold method (grep, targeted reads, `git log`) **silently**. Do not mention the tool, do not re-offer. The user has answered.
12
+ - **undecided** (no file, no key, or anything unrecognised) — fall back to the cold method *and* make the offer **once**: this repository would answer "where is / who calls / what changed / who owns" from an index instead of a grep sweep. `npx @nurix/apollo graph overview` runs it without installing anything; `npm install -g @nurix/apollo` puts it on `PATH`. **Ask, never act** — a global npm install modifies the machine, and indexing writes to `~/.codegraph`. Record the answer with `recordDecision` either way, so the question is asked at most once per repo per machine.
13
+ - **`accepted` but the binary is gone** — treat as undecided; a failed or removed install is not a standing yes.
14
+
15
+ **A failed install is `absent`, not an error to retry.** Global installs fail on machines without permission; say so once, fall back, and move on. `npx @nurix/apollo` needs no install at all and is the shorter ladder when one command is all you want.
16
+
17
+ **An explicit invocation overrides a stored decline.** If the user asks for this skill by name, honour it and re-offer — "stop asking" must never become "never usable".
18
+
19
+ **A repository that has never been indexed** answers with the tool saying so rather than with a wrong answer. That is the tool degrading correctly, not a failure: `apollo graph index` builds it, under the same ask-first rule.
20
+
21
+ **Freshness is not your problem.** `apollo graph` re-indexes a stale store before it answers, so a query after a commit reports the new HEAD without anyone running an index first. Pass `--no-refresh` when you deliberately want the index as it stands — answering from a known-old index is a choice you can make, never one you make by accident. This is the one thing that changed when the code graph moved behind `apollo`: there is no staleness ritual left to perform.
22
+
23
+ Everything below assumes the tool is present.
24
+
25
+ `apollo graph` defaults to the git root of the working directory — inside this repository, no flags are needed; `--repo <pathOrId>` asks about another one. Every answer states its own confidence per section (`CERTAIN` / `INFERRED` / `UNRESOLVED`), announces anything the token budget dropped, and says what an empty section means. Trust those labels.
26
+
27
+ ## The method order
28
+
29
+ Localize through the index **before** opening any file, in this order; then read only the files it points at.
30
+
31
+ 1. **`apollo graph find <fragment>`** — symbols and file paths by name fragment. The entry point when you only have issue vocabulary. Symbol names only — it will never match string literals, dict keys, or SQL fragments (grep for those, without shame).
32
+ 2. **`apollo graph where-defined <symbol>`** / **`apollo graph outline <file>`** — pin the definition; map a big file. `outline` turns a 100+ declaration file into a navigable, line-numbered list — use it instead of reading god files blind. On a large file add `--budget 0` (see traps).
33
+ 3. **`apollo graph who-calls <symbol>`** / **`apollo graph impact <target>`** — callers, and blast radius (static reach + historical co-change reach, reported separately on purpose: they disagree, and the disagreement is information).
34
+ 4. **`apollo graph churn --days N --path <dir>`** · **`coupling --path <file>`** · **`owners <path>`** · **`tests-covering <file>`** — the history layer: what's hot, what changes together (including *hidden coupling* — co-change with no static reference, the one fact reading code cannot reveal), who knows this area and how recently, which test file historically guards this file.
35
+ 5. **`apollo graph god-objects --minSymbols 30`** / **`hotspots`** / **`overview`** — repo-scale orientation and risk.
36
+
37
+ Then read, with `sed -n` ranges at the lines the index gave you. The index does discovery; reading does diagnosis. Add `--json` when a wrapper needs structure — the answer arrives inside the CLI's machine envelope, `{ apolloJsonVersion, command, ok, data }`.
38
+
39
+ There is also **`apollo graph blame <file> [--line N]`** — the commits behind a file or one specific line, answered by git at query time; **`apollo graph refs <name>`** — the data-reference layer: where a name is used as a dict/object key, attribute/field, import, or type annotation, with read/write direction, and a cross-language flag when the same name spans Python and TypeScript files (this answers "who reads `x_axis_sort`" / "who writes `chart.query_context`" in one call — the questions that used to need grep); and **`apollo graph drift`** — near-duplicate function bodies crossed with co-change history: similar code whose files never change together is an unfinished refactor waiting to disagree. `who-calls` additionally tabulates which keyword arguments each call site passes, so "which call sites omit this option" is one query.
40
+
41
+ **`apollo graph status`** reports what the index holds for this repository — indexed HEAD, file and symbol counts, whether it is stale — and **`apollo graph index [--commits N]`** rebuilds it explicitly. Reach for `status` when an answer surprises you and you want to know what it was computed from; you should never need `index` to make a query correct.
42
+
43
+ ## The boundary — what the index cannot answer (fall back immediately, don't retry)
44
+
45
+ - **Free-text string literals** (SQL templates, prose, format strings) — grep. Identifier-shaped keys and fields ARE indexed (`refs <name>`); anything longer or with spaces is not.
46
+ - **Framework reflection** (Marshmallow `@post_load`, signal handlers, `appbuilder.add_api(Cls)` registration) — invisible to call edges. Bare decorator *application* (`@has_access_api`) IS indexed as a reference; what the decorator does and when it runs is not.
47
+ - **Data flow and mechanism** ("does this value reach that function", "what order do these run in") — always reading work.
48
+
49
+ Indexed symbol forms include statement declarations, `const X = () => {}`, named function expressions inside wrapper calls (`typedMemo(function DataTable() {})`), TS/JS class fields, and Python class-body fields (`is_dttm = Column(...)`); nested members render as `Parent › member` in `outline`.
50
+
51
+ ## Traps (each cost a prior agent real time)
52
+
53
+ - **Bare-name collision.** Call references match by name, not resolved binding. When a name has several definitions, `who-calls` lists every candidate and says so in its subject line — read that section before trusting the call sites, and pass `--scope <path-fragment>` (also on `find`, `where-defined`, `impact`) to narrow to a package.
54
+ - **`apollo graph functions` lists the graph's own verbs**, not the repository's functions. For repo functions use `find`. An explicit `--limit` lifts the default token budget, so a full `outline` needs no `--budget 0` incantation (an explicit `--budget` still wins).
55
+ - **Churn windows.** `churn --days 180` returning nothing does not mean quiet history — widen the window. Directory-scope churn ranks by raw commit count and buries small-but-critical files; for specific files use `owners`/`coupling` per file.
56
+ - **`tests-covering` is co-change evidence, not executed coverage** — it names the right test file to open; it cannot say the specific scenario is tested.
57
+ - **Coupling on a busy file has a noise tail** — partners at <15% shared commits are usually PR-cohabitation, not real coupling. Verify a partner with a read before adding it to a touch-list.
58
+ - **The history layer sees one window, and the refresh keeps resetting it to 5000 commits.** `churn`, `owners`, `coupling`, `blame` and `tests-covering` answer over the ingested commits, and an index — the automatic one included — takes the most recent 5000 unless `index --commits N` says otherwise. On a deeper repository those answers are true of the window, not of the repository, and the next refresh silently narrows a wider window back. Say "over the last N commits" when you report them, and re-ask for the depth you need.
59
+ - **`owners` is authorship weight, not a file-touch tally** — an author is counted once per commit touching the path, however many of the path's files that commit changed. Do not transcribe its numbers as "files changed".
60
+ - **The first query after a long gap pays for the re-index.** Absorption is not free: on a large repository the refresh takes tens of seconds before the answer appears. That is one wait, not a per-query cost — and `--no-refresh` skips it when you would rather have the old answer now.
61
+
62
+ ## Division of truth in this repository
63
+
64
+ `docs/` is the source of truth for **intent** — what a feature is for, its invariants, decisions, vocabulary. The code graph is the source of truth for **facts** — where things are, who calls what, what changed together, who owns what. Never copy live facts (caller counts, churn numbers) into docs as if permanent; never ask the index for intent.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: issue-bridge
3
- description: The bridge between a traditional issue tracker (GitHub Issues, Jira, Linear, …) and the AI-first SDLC. Two modes — **triage** (inbound — a tracker item is routed through the ownership index to its owning feature docs, localized with codegraph, and lands as a confidence-graded triage dossier ready for a fix plan) and **file** (outbound — a verified harness finding becomes a tracker-native issue with checkable evidence, and the created ID is written back into the originating row). Tracker access goes through a connector (see the per-tracker packs under references/trackers/); tracker writes are always approval-gated per run. Use on "triage issue #N / PROJ-123 / ENG-123", "triage the new issues", "file this finding as a ticket", "/issue-bridge".
3
+ description: The bridge between a traditional issue tracker (GitHub Issues, Jira, Linear, …) and the AI-first SDLC. Two modes — **triage** (inbound — a tracker item is routed through the ownership index to its owning feature docs, localized with `apollo graph`, and lands as a confidence-graded triage dossier ready for a fix plan) and **file** (outbound — a verified harness finding becomes a tracker-native issue with checkable evidence, and the created ID is written back into the originating row). Tracker access goes through a connector (see the per-tracker packs under references/trackers/); tracker writes are always approval-gated per run. Use on "triage issue #N / PROJ-123 / ENG-123", "triage the new issues", "file this finding as a ticket", "/issue-bridge".
4
4
  ---
5
5
 
6
6
  # issue-bridge — the tracker bridge method
@@ -10,7 +10,7 @@ description: The bridge between a traditional issue tracker (GitHub Issues, Jira
10
10
  You bridge two systems of record. Neither is asked to change:
11
11
 
12
12
  - **The tracker owns** intake, priority, assignment, status, discussion. You never relocate those.
13
- - **The AI layer owns** intent (feature docs say *why* — invariants, vocabulary, scope), location (the ownership index and codegraph say *what and where*), and history (git-derived).
13
+ - **The AI layer owns** intent (feature docs say *why* — invariants, vocabulary, scope), location (the ownership index and `apollo graph` say *what and where*), and history (git-derived).
14
14
  - **The bridge rule: inbound enrich, outbound evidence.** An inbound item gains location, owning docs, and blast radius. An outbound item carries citations a human can verify without trusting you.
15
15
 
16
16
  ## Connectors
@@ -19,7 +19,7 @@ Tracker access is **this skill's own knowledge**, not a harness-declared tool. I
19
19
 
20
20
  ## Tool tier
21
21
 
22
- Read the codegraph status from the session context (`Tool:` line). **Present-fresh** → localize every question through the index (`find`, `where-defined`, `who-calls`, `refs`, `impact`, `blame`, `tests-covering`) before reading source. **Present-stale** → use it, note the gap. **Absent** → Glob/Grep/read, announced. Never run `codegraph index` unless you verify HEAD moved. One carve-out: **syntax-level detail — decorator lists and their order, full function bodies, statement sequence — is not in the index's query surface**; go straight to source for that class, whatever the tier. (The 0.2.0 decorator mis-attribution defect is fixed in 0.2.1 — `who-calls` and `impact` now attribute decorator references to the decorated declaration; the catalog pins `min-version: 0.2.1` accordingly.)
22
+ Read the `apollo` status from the session context (`Tool:` line). **Present-fresh** → localize every question through `apollo graph` (`find`, `where-defined`, `who-calls`, `refs`, `impact`, `blame`, `tests-covering`) before reading source. **Present-stale** → use it, note the gap. **Absent** → Glob/Grep/read, announced. Never run an index step first — the family re-indexes a stale store before it answers. One carve-out: **syntax-level detail — decorator lists and their order, full function bodies, statement sequence — is not in the index's query surface**; go straight to source for that class, whatever the tier. Decorator *application* is indexed as a reference, attributed to the decorated declaration; what the decorator does is not.
23
23
 
24
24
  ## Mode selection
25
25
 
@@ -30,9 +30,9 @@ Read the codegraph status from the session context (`Tool:` line). **Present-fre
30
30
  1. **Fetch** through the connector (per the pack). No access → pasted-text mode, missing fields named.
31
31
  2. **Classify.** Bug / feature request / question / docs-gap. Questions get owning-doc pointers and a direct answer, not a dossier.
32
32
  3. **Route.** Match the issue's vocabulary against the ownership index and feature docs' `keywords:`. Read the owning doc(s) **fully** — intent and invariants first, code second. No owning doc → say so; the absence is itself a finding.
33
- 4. **Localize.** Names from the issue go through codegraph; every location claim carries `file:line`.
33
+ 4. **Localize.** Names from the issue go through `apollo graph`; every location claim carries `file:line`.
34
34
  5. **Diagnose.** Root-cause hypothesis, confidence-graded — `certain` / `inferred` / `unresolved` — and never present inferred as certain. Blast radius via `impact`/`coupling`; test surface via `tests-covering`.
35
- 6. **Dedup.** Search the tracker for siblings and priors (per the pack); check codegraph `drift` for the same-bug-in-a-clone class.
35
+ 6. **Dedup.** Search the tracker for siblings and priors (per the pack); check `apollo graph drift` for the same-bug-in-a-clone class.
36
36
  7. **Write the dossier** to `docs/operations/triage/YYYY-MM-DD-<tracker>-<id>-<slug>.md` and return the verdict summary.
37
37
  8. **Posting back** (comment, label, assign, transition) is **approval-gated per run**: show exactly what would be posted, post only on an explicit yes in this session. A standing repo ruling (e.g. "never post to this upstream") overrides any approval.
38
38
 
@@ -237,9 +237,9 @@ Apply the **§ Strategy memory** retirement procedure to `docs/memory/maintenanc
237
237
  - **Enforce the memory cap on every run** (§ Strategy memory) — you are its only writer, so no one else can do it.
238
238
  - **A clean report is valid** — do not invent issues.
239
239
  - **Declarative, idempotent.** Re-running baseline mode on a current repo reshapes nothing — a second pass is just the audit plus the module proposal. Converge to the current shape; never replay a version ladder; never reconstruct a past shape.
240
- - **Brownfield extraction (operator-ruled 2026-08-19).** When baseline mode meets a repo with a real source tree and few or no feature docs, the module *proposal* is not enough — run the extraction pass: produce feature docs for the recognized modules (docs/features/, full frontmatter: `owns:` · `module:` · `keywords:` · `status:` · `last-reviewed:` · `type: feature` · `derivation: "extracted (baseline YYYY-MM-DD, codegraph + source read)"`), plus the architecture, tests, and operations layers. Use the `codegraph` skill where installed — localize through the index before reading; the docs record intent, the index answers facts. **Every extracted feature doc carries a `## History & Ownership` section** — top contributors with recency, churn posture, and bus-factor notes, dated "as of YYYY-MM-DD" (operator ruling: this section is mandatory in extraction output even though doc-lint flags dated narrative in truth docs; the findings are accepted for now, and a future harness version may retire the section in favor of live index pointers). `status:` is evidence-graded: `deprecated` only when history shows the area dead, never by guess. Scale by fan-out (one extraction lane per module, a completeness critic over the result) rather than one long cold read.
240
+ - **Brownfield extraction (operator-ruled 2026-08-19).** When baseline mode meets a repo with a real source tree and few or no feature docs, the module *proposal* is not enough — run the extraction pass: produce feature docs for the recognized modules (docs/features/, full frontmatter: `owns:` · `module:` · `keywords:` · `status:` · `last-reviewed:` · `type: feature` · `derivation: "extracted (baseline YYYY-MM-DD, apollo graph + source read)"`), plus the architecture, tests, and operations layers. Use the `apollo-graph` skill where installed — localize through the index before reading; the docs record intent, the index answers facts. **Every extracted feature doc carries a `## History & Ownership` section** — top contributors with recency, churn posture, and bus-factor notes, dated "as of YYYY-MM-DD" (operator ruling: this section is mandatory in extraction output even though doc-lint flags dated narrative in truth docs; the findings are accepted for now, and a future harness version may retire the section in favor of live index pointers). `status:` is evidence-graded: `deprecated` only when history shows the area dead, never by guess. Scale by fan-out (one extraction lane per module, a completeness critic over the result) rather than one long cold read.
241
241
  - **Diagrams ride the baseline (operator-ruled 2026-08-24).** Whenever baseline mode produces or converges the architecture layer, draw two ASCII diagrams from the real source, each in its own fenced code block: (1) an **architecture diagram** in the system-design/architecture doc — the actual processes, entry points, and wire surfaces as boxes, the calls/queues/files between them as labelled arrows; (2) a **DB ER diagram** wherever the repo declares a relational schema (DDL, migrations, an ORM schema) — one box per table listing its key columns, FK edges drawn to the table they reference, cardinality on the edge; it lands in the domain-model doc, or `docs/architecture/data-model.md` when none exists. Box-drawing characters (`┌─┐│└┘├┤`), width ≤ 100 columns. Derived only from what the code declares — a diagram never invents a component the source does not show, and a repo with no relational schema gets **no** ER diagram rather than an imagined one. Diagrams are truth-document sections: later baselines and audits converge them in place like any other section.
242
- - **Tool tiers.** The SessionStart context names each manifest-declared tool with its tier; calibrate the run to it, never stall on it. **Present-fresh** (`Tool: codegraph 0.2.0`): use it — check `codegraph projects` for staleness, re-run `codegraph index` if HEAD has moved, then localize every question through the index before reading source. **Present-stale** (below the catalog minimum): still use it, but note the version gap and the upgrade command in the run report — a stale contract may lack answer shapes the skill assumes. **Absent** (`Tool: codegraph MISSING`): fall back to the cold method (Glob/Grep/read), state in the run report that the tool was absent and give the install command — degraded output is acceptable, silent degradation is not.
242
+ - **Tool tiers.** The SessionStart context names each manifest-declared tool with its tier; calibrate the run to it, never stall on it. **Present-fresh** (`Tool: apollo 0.9.0`): use it — localize every question through `apollo graph` before reading source, and never run an index step first: the family re-indexes a stale store before it answers, so the only freshness decision left is the deliberate `--no-refresh`. **Present-stale** (below the catalog minimum): still use it, but note the version gap and the upgrade command in the run report — a stale contract may lack answer shapes the skill assumes. **Absent** (`Tool: apollo MISSING`): fall back to the cold method (Glob/Grep/read), state in the run report that the tool was absent and give the install command — degraded output is acceptable, silent degradation is not.
243
243
  - **One sentinel.** `docs/structure.md` `harness-version` is the only baseline/version marker.
244
244
  - **Modules are labels, layout-blind.** Seed from the code's bounded contexts; never from `pnpm-workspace.yaml`/workspace walls. Propose, don't force; acting is a `module:` tag, never a folder.
245
245
  - **You orchestrate docs; the `documentation` skill supplies templates.** It is a library — never expect it to baseline.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "harness": "delivery",
3
3
  "name": "delivery",
4
- "version": "0.2.32",
4
+ "version": "0.2.33",
5
5
  "files": [
6
6
  ".prettierignore",
7
7
  ".prettierrc.json",
@@ -10,5 +10,5 @@
10
10
  "seeds": [],
11
11
  "tools": [],
12
12
  "docsRoot": "docs",
13
- "digest": "94b63ce8cf37"
13
+ "digest": "175efc0834e3"
14
14
  }
@@ -237,9 +237,9 @@ Apply the **§ Strategy memory** retirement procedure to `docs/memory/maintenanc
237
237
  - **Enforce the memory cap on every run** (§ Strategy memory) — you are its only writer, so no one else can do it.
238
238
  - **A clean report is valid** — do not invent issues.
239
239
  - **Declarative, idempotent.** Re-running baseline mode on a current repo reshapes nothing — a second pass is just the audit plus the module proposal. Converge to the current shape; never replay a version ladder; never reconstruct a past shape.
240
- - **Brownfield extraction (operator-ruled 2026-08-19).** When baseline mode meets a repo with a real source tree and few or no feature docs, the module *proposal* is not enough — run the extraction pass: produce feature docs for the recognized modules (docs/features/, full frontmatter: `owns:` · `module:` · `keywords:` · `status:` · `last-reviewed:` · `type: feature` · `derivation: "extracted (baseline YYYY-MM-DD, codegraph + source read)"`), plus the architecture, tests, and operations layers. Use the `codegraph` skill where installed — localize through the index before reading; the docs record intent, the index answers facts. **Every extracted feature doc carries a `## History & Ownership` section** — top contributors with recency, churn posture, and bus-factor notes, dated "as of YYYY-MM-DD" (operator ruling: this section is mandatory in extraction output even though doc-lint flags dated narrative in truth docs; the findings are accepted for now, and a future harness version may retire the section in favor of live index pointers). `status:` is evidence-graded: `deprecated` only when history shows the area dead, never by guess. Scale by fan-out (one extraction lane per module, a completeness critic over the result) rather than one long cold read.
240
+ - **Brownfield extraction (operator-ruled 2026-08-19).** When baseline mode meets a repo with a real source tree and few or no feature docs, the module *proposal* is not enough — run the extraction pass: produce feature docs for the recognized modules (docs/features/, full frontmatter: `owns:` · `module:` · `keywords:` · `status:` · `last-reviewed:` · `type: feature` · `derivation: "extracted (baseline YYYY-MM-DD, apollo graph + source read)"`), plus the architecture, tests, and operations layers. Use the `apollo-graph` skill where installed — localize through the index before reading; the docs record intent, the index answers facts. **Every extracted feature doc carries a `## History & Ownership` section** — top contributors with recency, churn posture, and bus-factor notes, dated "as of YYYY-MM-DD" (operator ruling: this section is mandatory in extraction output even though doc-lint flags dated narrative in truth docs; the findings are accepted for now, and a future harness version may retire the section in favor of live index pointers). `status:` is evidence-graded: `deprecated` only when history shows the area dead, never by guess. Scale by fan-out (one extraction lane per module, a completeness critic over the result) rather than one long cold read.
241
241
  - **Diagrams ride the baseline (operator-ruled 2026-08-24).** Whenever baseline mode produces or converges the architecture layer, draw two ASCII diagrams from the real source, each in its own fenced code block: (1) an **architecture diagram** in the system-design/architecture doc — the actual processes, entry points, and wire surfaces as boxes, the calls/queues/files between them as labelled arrows; (2) a **DB ER diagram** wherever the repo declares a relational schema (DDL, migrations, an ORM schema) — one box per table listing its key columns, FK edges drawn to the table they reference, cardinality on the edge; it lands in the domain-model doc, or `docs/architecture/data-model.md` when none exists. Box-drawing characters (`┌─┐│└┘├┤`), width ≤ 100 columns. Derived only from what the code declares — a diagram never invents a component the source does not show, and a repo with no relational schema gets **no** ER diagram rather than an imagined one. Diagrams are truth-document sections: later baselines and audits converge them in place like any other section.
242
- - **Tool tiers.** The SessionStart context names each manifest-declared tool with its tier; calibrate the run to it, never stall on it. **Present-fresh** (`Tool: codegraph 0.2.0`): use it — check `codegraph projects` for staleness, re-run `codegraph index` if HEAD has moved, then localize every question through the index before reading source. **Present-stale** (below the catalog minimum): still use it, but note the version gap and the upgrade command in the run report — a stale contract may lack answer shapes the skill assumes. **Absent** (`Tool: codegraph MISSING`): fall back to the cold method (Glob/Grep/read), state in the run report that the tool was absent and give the install command — degraded output is acceptable, silent degradation is not.
242
+ - **Tool tiers.** The SessionStart context names each manifest-declared tool with its tier; calibrate the run to it, never stall on it. **Present-fresh** (`Tool: apollo 0.9.0`): use it — localize every question through `apollo graph` before reading source, and never run an index step first: the family re-indexes a stale store before it answers, so the only freshness decision left is the deliberate `--no-refresh`. **Present-stale** (below the catalog minimum): still use it, but note the version gap and the upgrade command in the run report — a stale contract may lack answer shapes the skill assumes. **Absent** (`Tool: apollo MISSING`): fall back to the cold method (Glob/Grep/read), state in the run report that the tool was absent and give the install command — degraded output is acceptable, silent degradation is not.
243
243
  - **One sentinel.** `docs/structure.md` `harness-version` is the only baseline/version marker.
244
244
  - **Modules are labels, layout-blind.** Seed from the code's bounded contexts; never from `pnpm-workspace.yaml`/workspace walls. Propose, don't force; acting is a `module:` tag, never a folder.
245
245
  - **You orchestrate docs; the `documentation` skill supplies templates.** It is a library — never expect it to baseline.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "harness": "etna",
3
3
  "name": "etna",
4
- "version": "1.5.22",
4
+ "version": "1.5.23",
5
5
  "files": [
6
6
  ".prettierignore",
7
7
  ".prettierrc.json",
@@ -10,5 +10,5 @@
10
10
  "seeds": [],
11
11
  "tools": [],
12
12
  "docsRoot": "docs",
13
- "digest": "1fcc2f8a0d2a"
13
+ "digest": "2319413501b5"
14
14
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nurix/etna",
3
- "version": "0.20.18",
3
+ "version": "0.20.19",
4
4
  "description": "Bootstrap a project with a Nurix harness — copies the harness's CLAUDE.md, skills, agents, rules, and hooks directly into the project from a bundled payload (no marketplace fetch, no network).",
5
5
  "type": "module",
6
6
  "bin": {
@@ -42,5 +42,5 @@
42
42
  "agent",
43
43
  "plugin"
44
44
  ],
45
- "etnaFingerprint": "993a4863fa1f"
45
+ "etnaFingerprint": "55061d9eaae9"
46
46
  }
@@ -1,57 +0,0 @@
1
- ---
2
- name: codegraph
3
- requires-tool: codegraph
4
- description: Query the codegraph index before reading source. An LLM-first codebase index (symbols, call references, git history, co-change coupling, ownership) answering whole questions in one call. Use it to localize, scope, and assess blast radius on this repository; use grep/read for string literals, mechanism, and data flow — the skill states which is which. Applies to any task that starts with "where is", "who calls", "what changed", "who owns", "what breaks", or "is this tested".
5
- ---
6
-
7
- # codegraph — the index-first method
8
-
9
- **If the tool is absent** (`codegraph --version` fails): do not stall. Read `.claude/state/decisions.tsv` for `tool.codegraph`.
10
-
11
- - **`declined`** — fall back to the cold method (grep, targeted reads, `git log`) **silently**. Do not mention the tool, do not re-offer. The user has answered.
12
- - **undecided** (no file, no key, or anything unrecognised) — fall back to the cold method *and* make the offer **once**: this repository would answer "where is / who calls / what changed / who owns" from an index instead of a grep sweep; install with `npm install -g @nurix/codegraph`, then `codegraph index`. **Ask, never act** — a global npm install modifies the machine, and indexing writes to `~/.codegraph`. Record the answer with `recordDecision` either way, so the question is asked at most once per repo per machine.
13
- - **`accepted` but the binary is gone** — treat as undecided; a failed or removed install is not a standing yes.
14
-
15
- **A failed install is `absent`, not an error to retry.** Global installs fail on machines without permission; say so once, fall back, and move on.
16
-
17
- **An explicit invocation overrides a stored decline.** If the user asks for this skill by name, honour it and re-offer — "stop asking" must never become "never usable".
18
-
19
- **If the repository is not indexed** (a query answers `UNAVAILABLE: this repository has not been indexed yet`), that is the tool degrading correctly, not a failure: offer `codegraph index` under the same ask-first rule. The SessionStart probe deliberately does **not** claim index freshness — it can only see the binary — so this is where index state is actually established.
20
-
21
- Everything below assumes the tool is present and the repository indexed.
22
-
23
- The `codegraph` CLI is on PATH and defaults to the git root of the working directory — inside this repository, no flags are needed. The index is prebuilt; `codegraph projects` shows freshness (a `[STALE]` marker means HEAD moved since indexing — refresh with `codegraph index --commits 30000`, ~40s). Every answer states its own confidence per section (`CERTAIN` / `INFERRED` / `UNRESOLVED`), announces anything the token budget dropped, and says what an empty section means. Trust those labels.
24
-
25
- ## The method order
26
-
27
- Localize through the index **before** opening any file, in this order; then read only the files it points at.
28
-
29
- 1. **`codegraph find <fragment>`** — symbols and file paths by name fragment. The entry point when you only have issue vocabulary. Symbol names only — it will never match string literals, dict keys, or SQL fragments (grep for those, without shame).
30
- 2. **`codegraph where-defined <symbol>`** / **`codegraph outline <file>`** — pin the definition; map a big file. `outline` turns a 100+ declaration file into a navigable, line-numbered list — use it instead of reading god files blind. On a large file add `--budget 0` (see traps).
31
- 3. **`codegraph who-calls <symbol>`** / **`codegraph impact <target>`** — callers, and blast radius (static reach + historical co-change reach, reported separately on purpose: they disagree, and the disagreement is information).
32
- 4. **`codegraph churn --days N --path <dir>`** · **`coupling --path <file>`** · **`owners <path>`** · **`tests-covering <file>`** — the history layer: what's hot, what changes together (including *hidden coupling* — co-change with no static reference, the one fact reading code cannot reveal), who knows this area and how recently, which test file historically guards this file.
33
- 5. **`codegraph god-objects --minSymbols 30`** / **`hotspots`** / **`overview`** — repo-scale orientation and risk.
34
-
35
- Then read, with `sed -n` ranges at the lines the index gave you. The index does discovery; reading does diagnosis. Add `--json` when a wrapper needs structure.
36
-
37
- There is also **`codegraph blame <file> [--line N]`** — the commits behind a file or one specific line, answered by git at query time; **`codegraph refs <name>`** — the data-reference layer: where a name is used as a dict/object key, attribute/field, import, or type annotation, with read/write direction, and a cross-language flag when the same name spans Python and TypeScript files (this answers "who reads `x_axis_sort`" / "who writes `chart.query_context`" in one call — the questions that used to need grep); and **`codegraph drift`** — near-duplicate function bodies crossed with co-change history: similar code whose files never change together is an unfinished refactor waiting to disagree. `who-calls` additionally tabulates which keyword arguments each call site passes, so "which call sites omit this option" is one query.
38
-
39
- ## The boundary — what the index cannot answer (fall back immediately, don't retry)
40
-
41
- - **Free-text string literals** (SQL templates, prose, format strings) — grep. Identifier-shaped keys and fields ARE indexed (`refs <name>`); anything longer or with spaces is not.
42
- - **Framework reflection** (Marshmallow `@post_load`, signal handlers, `appbuilder.add_api(Cls)` registration) — invisible to call edges. Bare decorator *application* (`@has_access_api`) IS indexed as a reference; what the decorator does and when it runs is not.
43
- - **Data flow and mechanism** ("does this value reach that function", "what order do these run in") — always reading work.
44
-
45
- Indexed symbol forms include statement declarations, `const X = () => {}`, named function expressions inside wrapper calls (`typedMemo(function DataTable() {})`), TS/JS class fields, and Python class-body fields (`is_dttm = Column(...)`); nested members render as `Parent › member` in `outline`.
46
-
47
- ## Traps (each cost a prior agent real time)
48
-
49
- - **Bare-name collision.** Call references match by name, not resolved binding. When a name has several definitions, `who-calls` lists every candidate and says so in its subject line — read that section before trusting the call sites, and pass `--scope <path-fragment>` (also on `find`, `where-defined`, `impact`) to narrow to a package.
50
- - **`codegraph functions` lists the CLI's own functions**, not the repository's. For repo functions use `find`. An explicit `--limit` lifts the default token budget, so a full `outline` needs no `--budget 0` incantation (an explicit `--budget` still wins).
51
- - **Churn windows.** `churn --days 180` returning nothing does not mean quiet history — widen the window. Directory-scope churn ranks by raw commit count and buries small-but-critical files; for specific files use `owners`/`coupling` per file.
52
- - **`tests-covering` is co-change evidence, not executed coverage** — it names the right test file to open; it cannot say the specific scenario is tested.
53
- - **Coupling on a busy file has a noise tail** — partners at <15% shared commits are usually PR-cohabitation, not real coupling. Verify a partner with a read before adding it to a touch-list.
54
-
55
- ## Division of truth in this repository
56
-
57
- `docs/` is the source of truth for **intent** — what a feature is for, its invariants, decisions, vocabulary. codegraph is the source of truth for **facts** — where things are, who calls what, what changed together, who owns what. Never copy live facts (caller counts, churn numbers) into docs as if permanent; never ask the index for intent.