@nurix/etna 0.19.54 → 0.19.56
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.
- package/data/harness-index.json +1 -1
- package/data/harnesses/apollo/CLAUDE.md +29 -30
- package/data/harnesses/apollo/harness.json +1 -1
- package/data/harnesses/apollo/hooks/approved-packages.md +42 -0
- package/data/harnesses/apollo/hooks/compliance.mjs +11 -6
- package/data/harnesses/apollo/hooks/lib/ownership.mjs +11 -1
- package/data/harnesses/apollo/rules/changelog.md +7 -1
- package/data/harnesses/apollo/rules/cloudflare.md +167 -0
- package/data/harnesses/apollo/rules/database.md +1 -125
- package/data/harnesses/apollo/rules/frontend.md +2 -4
- package/data/harnesses/apollo/rules/general.md +20 -42
- package/data/harnesses/apollo/rules/nomenclature.md +2 -6
- package/data/harnesses/apollo/rules/pnpm.md +2 -2
- package/data/harnesses/apollo/rules/testing.md +44 -3
- package/data/harnesses/apollo/skills/documentation/references/instruction-style.md +1 -0
- package/data/harnesses/apollo/skills/documentation/templates/plan.md +4 -4
- package/data/harnesses/apollo/skills/schema-design/SKILL.md +171 -0
- package/data/harnesses/apollo/skills/test/SKILL.md +104 -0
- package/data/harnesses/apollo/skills/testing/SKILL.md +100 -29
- package/data/harnesses/code/CLAUDE.md +29 -30
- package/data/harnesses/code/harness.json +1 -1
- package/data/harnesses/code/hooks/approved-packages.md +42 -0
- package/data/harnesses/code/hooks/compliance.mjs +11 -6
- package/data/harnesses/code/hooks/lib/ownership.mjs +11 -1
- package/data/harnesses/code/rules/changelog.md +7 -1
- package/data/harnesses/code/rules/cloudflare.md +167 -0
- package/data/harnesses/code/rules/database.md +1 -125
- package/data/harnesses/code/rules/frontend.md +2 -4
- package/data/harnesses/code/rules/general.md +20 -42
- package/data/harnesses/code/rules/nomenclature.md +2 -6
- package/data/harnesses/code/rules/pnpm.md +2 -2
- package/data/harnesses/code/rules/testing.md +44 -3
- package/data/harnesses/code/skills/documentation/references/instruction-style.md +1 -0
- package/data/harnesses/code/skills/documentation/templates/plan.md +4 -4
- package/data/harnesses/code/skills/schema-design/SKILL.md +171 -0
- package/data/harnesses/code/skills/test/SKILL.md +104 -0
- package/data/harnesses/code/skills/testing/SKILL.md +100 -29
- package/data/harnesses/delivery/CLAUDE.md +13 -1
- package/data/harnesses/delivery/harness.json +1 -1
- package/data/harnesses/delivery/hooks/generate-ownership-index.mjs +39 -4
- package/data/harnesses/delivery/rules/changelog.md +7 -1
- package/data/harnesses/delivery/rules/nomenclature.md +2 -6
- package/data/harnesses/delivery/skills/documentation/references/instruction-style.md +1 -0
- package/data/harnesses/delivery/skills/documentation/templates/plan.md +4 -4
- package/data/harnesses/discover/CLAUDE.md +14 -1
- package/data/harnesses/discover/harness.json +1 -1
- package/data/harnesses/discussion/CLAUDE.md +4 -2
- package/data/harnesses/discussion/harness.json +1 -1
- package/data/harnesses/etna/CLAUDE.md +14 -2
- package/data/harnesses/etna/harness.json +1 -1
- package/data/harnesses/etna/hooks/generate-ownership-index.mjs +39 -4
- package/data/harnesses/etna/rules/changelog.md +7 -1
- package/data/harnesses/etna/rules/general.md +20 -42
- package/data/harnesses/etna/rules/nomenclature.md +2 -6
- package/data/harnesses/etna/rules/testing.md +44 -3
- package/data/harnesses/etna/skills/documentation/references/instruction-style.md +1 -0
- package/data/harnesses/etna/skills/documentation/templates/plan.md +4 -4
- package/data/harnesses/hr/CLAUDE.md +8 -3
- package/data/harnesses/hr/harness.json +1 -1
- package/data/harnesses/kb-agi/CLAUDE.md +8 -2
- package/data/harnesses/kb-agi/harness.json +1 -1
- package/package.json +2 -2
- package/data/harnesses/apollo/rules/express.md +0 -33
- package/data/harnesses/apollo/rules/verification.md +0 -67
- package/data/harnesses/apollo/skills/test-plan/SKILL.md +0 -85
- package/data/harnesses/code/rules/express.md +0 -33
- package/data/harnesses/code/rules/verification.md +0 -67
- package/data/harnesses/code/skills/test-plan/SKILL.md +0 -85
|
@@ -8,7 +8,9 @@ Every unit of work leaves one record — `docs/history/changelog/YYYY-MM-DD-{thr
|
|
|
8
8
|
| --- | --- |
|
|
9
9
|
| A plan reaches `Status: Complete` | A draft entry for that plan, linked to it — written now, while the session still holds the context |
|
|
10
10
|
| The user asks for a changelog | The entry for the work in hand. No commit required |
|
|
11
|
-
| A commit is made | Every non-exempt commit is covered by an entry — the `commit` skill writes or completes it |
|
|
11
|
+
| A commit is made | Every non-exempt commit is covered by an entry — the `commit` skill writes or completes it (no `commit` skill in the runtime ⇒ write the entry from the `documentation` skill's `templates/changelog-entry.md` and stage it with the commit) |
|
|
12
|
+
|
|
13
|
+
An entry is owed only by work that changes promised behavior or takes a design decision; mechanical and cosmetic commits — a typo, a copy tweak, a config value, a log line — take only their `docs/history/CHANGELOG.md` row, no entry file. The failure fields (`Ask:`, `Skills:`, `Pin:`) are required only when non-none.
|
|
12
14
|
|
|
13
15
|
## Lifecycle
|
|
14
16
|
|
|
@@ -17,3 +19,7 @@ Draft (created before its commit exists) → complete (missing fields filled fro
|
|
|
17
19
|
## Granularity
|
|
18
20
|
|
|
19
21
|
A commit is the smallest unit an entry may describe; above that the mapping is judgment — four commits may be four entries or one, whichever reads better as history. An entry spanning several commits rides in the **last** of them, naming the predecessors in `Commits:`. When work exceeds what a draft describes, write a second entry rather than stretching the draft — the first stays an honest account of the plan.
|
|
22
|
+
|
|
23
|
+
## Migrations are a different genre
|
|
24
|
+
|
|
25
|
+
**One-shot migrations are a different genre.** Work that runs **once** against a live system — a data backfill, a schema cutover, a dependency or harness upgrade rolled across repos — is a **migration runbook** at `docs/history/migrations/YYYY-MM-DD-{slug}.md` (template: the `documentation` skill's `templates/migration-runbook.md`), authored **before** execution and outcome-stamped after. A changelog entry says what changed in the repo; a runbook says what was executed against the world and how to verify or undo it. A repeatable procedure is neither — that is `docs/operations/`. When a runbook defers targets, it records **why** and the **trigger to re-evaluate them**, so the next run re-checks rather than inheriting the skip.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Nomenclature
|
|
2
2
|
|
|
3
|
-
Naming and casing for code — identifiers, files, folders. The rationale throughout is consistency: one concept, one name, one casing shape, in every repo that loads this rule.
|
|
3
|
+
Naming and casing for code — identifiers, files, folders. The rationale throughout is consistency: one concept, one name, one casing shape, in every repo that loads this rule.
|
|
4
4
|
|
|
5
5
|
Names state intent in full words — clarity over brevity; no abbreviations unless universally understood (`id`, `url` ✅ · `cfg`, `btn`, `idx` ❌).
|
|
6
6
|
|
|
@@ -12,7 +12,7 @@ Names state intent in full words — clarity over brevity; no abbreviations unle
|
|
|
12
12
|
| `PascalCase` | classes, type definitions, components; the file exporting one | `PaymentProcessor`, `AppsListPage.tsx` |
|
|
13
13
|
| `UPPER_SNAKE_CASE` | constants, environment variables | `MAX_RETRY_COUNT` |
|
|
14
14
|
| `kebab-case` | URLs, CSS class names, HTML IDs, multi-word folders | `user-profile`, `workspace-provisioning/` |
|
|
15
|
-
| `snake_case` | database tables, columns, indexes
|
|
15
|
+
| `snake_case` | database tables, columns, indexes | `created_at` |
|
|
16
16
|
|
|
17
17
|
**A file exporting one component carries that component's name exactly**, so an import names the file it came from; a single-word folder is plain lowercase (`lib`, `surfaces`). ❌ Never `snake_case` a file or folder — that casing belongs to the database.
|
|
18
18
|
|
|
@@ -28,7 +28,3 @@ Names state intent in full words — clarity over brevity; no abbreviations unle
|
|
|
28
28
|
| Event handler | `handle` or `on` prefix | `handleSubmit`, `onPageLoad` |
|
|
29
29
|
| Interface | `I` prefix acceptable; type aliases stay plain | `IConfigOptions`, `AuthResponse` |
|
|
30
30
|
| Async function | verb phrase; `Async` suffix acceptable | `loadConfigAsync` |
|
|
31
|
-
|
|
32
|
-
## Database
|
|
33
|
-
|
|
34
|
-
Table, column, index, and key naming for relational schemas — the `id` / `slug` / `label` vocabulary, junction `_map` tables, and Drizzle mirrors — lives in [`database.md`](database.md), which routes general code naming back here.
|
|
@@ -24,6 +24,7 @@ Policy files (`CLAUDE.md`, rules) are declarative — assertion bullets and tabl
|
|
|
24
24
|
## Routing
|
|
25
25
|
|
|
26
26
|
- **Link, don't copy — one canonical source per topic.** `CLAUDE.md` is a **router, not a manual**: per workflow, when to enter, what to dispatch, where the output lands — mechanics live in the agent or skill file, which loads only when it runs.
|
|
27
|
+
- **A rule never references a sibling rule.** Rules co-load, so pointing at one from another routes a reader to text already in front of them — noise that also drifts the moment either file moves. State what the rule owns, self-contained; the only outward links a rule carries are to skills and agents, whose bodies do *not* co-load. Routing downward from `CLAUDE.md` to a rule is fine — that is the router doing its job.
|
|
27
28
|
- **Cut generic engineering advice.** Agents already know how to code; keep only what is true of *this* stack and not derivable by looking at it.
|
|
28
29
|
- **Keep load-bearing rules even when project-specific.** Genericizing is for reference material, not guardrails — deleting a hard rule removes a constraint the agent will otherwise violate.
|
|
29
30
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Plan (docs/history/plans/YYYY-MM-DD-feature-name.md)
|
|
2
2
|
|
|
3
|
-
Record. Use for: every implementation plan. Plans are created here directly with `Status: Draft`; after approval the plan gates (`boundary`, then `
|
|
3
|
+
Record. Use for: every implementation plan. Plans are created here directly with `Status: Draft`; after approval the plan gates (`boundary`, then `testing` plan-gate mode) run against the still-`Draft` file, the status flips to `Status: In Progress` at the first implementation step, and the file freezes at `Status: Complete` or `Status: Abandoned`. Once frozen, never edit — write a new dated plan if scope changes. The plan records the journey; the truth it implemented lives on in the feature doc and any AD it touched.
|
|
4
4
|
|
|
5
|
-
The `boundary` skill parses the **Proposed Changes** sections to check boundary impact before execution, and the `
|
|
5
|
+
The `boundary` skill parses the **Proposed Changes** sections to check boundary impact before execution, and the `testing` skill (plan-gate mode) writes a **Test Obligations** section into the plan at the same gate. Keep that structure stable — section headings and bullet shape are load-bearing for the parsers, and the Test Obligations table is the ledger the verification gate discharges before the plan may reach `Status: Complete`.
|
|
6
6
|
|
|
7
|
-
The **`Gates:`** line is machine-read: the compliance hook greps exactly the forms below, and implementation edits are blocked while a segment reads `pending`. Each gate skill rewrites only its own segment when it runs — `boundary` to `Boundary: passed YYYY-MM-DD` or `Boundary: blocked YYYY-MM-DD`; `
|
|
7
|
+
The **`Gates:`** line is machine-read: the compliance hook greps exactly the forms below, and implementation edits are blocked while a segment reads `pending`. Each gate skill rewrites only its own segment when it runs — `boundary` to `Boundary: passed YYYY-MM-DD` or `Boundary: blocked YYYY-MM-DD`; `testing` (plan-gate mode) to `Test-plan: written YYYY-MM-DD (N rows)` — the segment label stays `Test-plan`, greppable. Never hand-edit the line to skip a gate.
|
|
8
8
|
|
|
9
9
|
```
|
|
10
10
|
# {Feature Name}
|
|
@@ -52,7 +52,7 @@ Why this work is happening *now*. Link to the spec for *what* we're building; th
|
|
|
52
52
|
|
|
53
53
|
## Test Obligations
|
|
54
54
|
|
|
55
|
-
<!-- Written by the `
|
|
55
|
+
<!-- Written by the `testing` skill (plan-gate mode) at the plan gate (after `boundary`). One row per
|
|
56
56
|
promised behavior: layer · target file · oracle · fixtures. Amendable while the
|
|
57
57
|
plan is open; discharged at the verification gate. Do not hand-author. -->
|
|
58
58
|
|
|
@@ -4,7 +4,20 @@ This is the **policy** half of the `discover` harness. The plugin ships the capa
|
|
|
4
4
|
|
|
5
5
|
A run is five modes, in order: **Discovery → Ingestion → Evaluation → Cartography → Self-correction.** The main session drives all five — Ingestion and Evaluation fan out parallel sub-agents (dispatch each via the Agent/Task tool with `model: opus`); Cartography re-enters the live product (the browser singleton) to walk + screenshot it and may fan out doc-drafting sub-agents; a sub-agent cannot spawn further sub-agents.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Delegation
|
|
10
|
+
|
|
11
|
+
The policy for sub-agent dispatch across all five modes — when to fan out, at what tier, and how far to trust the result.
|
|
12
|
+
|
|
13
|
+
- **Delegation keeps bulk tool output out of the main context.** Wide reads, sweeps, broad research, and audits default to a sub-agent: a sub-agent's raw output dies with it, while the same output read inline is re-read and re-billed on every later turn. The hand-off is self-contained (the sub-agent sees none of the conversation), so it must still cost less than the work; independent delegations run in parallel.
|
|
14
|
+
- **Small or judgment work stays inline.** A task finishable in a handful of tool calls is faster done than briefed. Judgment is never delegated by reflex — a second opinion is for a high-stakes call or an explicit request.
|
|
15
|
+
- **A delegated result is a report, not verifiable ground truth.**
|
|
16
|
+
- **Tiers**: mechanical fan-out runs on the cheapest capable tier; judgment-heavy delegation runs on the standard tier; the strongest tier only on explicit user request.
|
|
17
|
+
- **An explicit user directive about tier, cost, or delegation overrides this section.**
|
|
18
|
+
- **Ingestion is the sanctioned mechanical case** — each of the eleven dimensions is large and independent, so its collectors are fanned out deliberately as the default, never by reflex.
|
|
19
|
+
|
|
20
|
+
No dispatch mechanism ⇒ inline.
|
|
8
21
|
|
|
9
22
|
---
|
|
10
23
|
|
|
@@ -20,6 +20,8 @@ Strictly separated — never mix them:
|
|
|
20
20
|
|
|
21
21
|
The rules are the method — portable, abstract, generic examples; nothing depends on any local topic. Live exemplars are reached through `metadata/TOPICS.md`. Workspace-local method notes go to `metadata/method-changelog.md`; the harness itself is versioned by `.claude/harness.json` and documented in the etna forge (`docs/architecture/harness/discussion/`).
|
|
22
22
|
|
|
23
|
-
##
|
|
23
|
+
## Delegation
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
- **Delegation keeps bulk tool output out of the main session's context** — a sub-agent's raw output dies with it, while output read inline is re-read and re-billed on every later turn. Wide reads, sweeps, broad research, and audits default to a sub-agent, run in parallel when independent; no dispatch mechanism, work stays inline.
|
|
26
|
+
- **Small or judgment work stays inline** — a task finishable in a handful of tool calls is faster done than briefed, and judgment is never delegated by reflex; a delegated result is a report, not verifiable ground truth, so anything load-bearing is verified directly.
|
|
27
|
+
- **Tiers**: mechanical fan-out runs on the cheapest capable tier, judgment-heavy delegation on the session's standard tier, the strongest tier only on explicit user request — an explicit user directive about tier, cost, or delegation overrides this section.
|
|
@@ -148,6 +148,18 @@ When a plan's implementation surfaces work that is important but outside the pla
|
|
|
148
148
|
|
|
149
149
|
---
|
|
150
150
|
|
|
151
|
+
## Delegation
|
|
152
|
+
|
|
153
|
+
The single policy for sub-agent dispatch — when to fan out, at what tier, and how far to trust the result. Component-internal dispatch mechanics (the foreman loop, the brainstorm twin, batch classification) stay in their components and defer here for anything this section covers. No dispatch mechanism ⇒ inline.
|
|
154
|
+
|
|
155
|
+
- **Delegate to keep bulk out of the main context.** Wide file reads, sweeps, broad research, audits, fixture prep — work whose raw tool output the main session doesn't need — defaults to a sub-agent: output a sub-agent reads dies with it, while output read inline is re-read and re-billed on every later turn. The hand-off is self-contained (the sub-agent sees none of the conversation), so it must still cost less than the work; run independent delegations in parallel.
|
|
156
|
+
- **Small or judgment work stays inline.** A task finishable in a handful of tool calls is faster done than briefed. **Never delegate judgment by reflex** — a second opinion is for a high-stakes call or an explicit request.
|
|
157
|
+
- **A delegated result is a report, not verifiable ground truth** — verify load-bearing results directly.
|
|
158
|
+
- **Tiers**: mechanical fan-out → the cheapest capable tier; judgment-heavy delegation → the session's standard tier; the strongest tier **only** on explicit user request. The session itself defaults to the standard tier, entering the strongest only by explicit user switch. Model names live in Runtime Notes.
|
|
159
|
+
- **An explicit user directive about tier, cost, or delegation overrides this section.**
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
151
163
|
## Guardrails & Defaults
|
|
152
164
|
|
|
153
165
|
❌ prohibitions hold unless the user explicitly asks otherwise; ✅ and ⚠️ items are standing policy:
|
|
@@ -158,7 +170,7 @@ When a plan's implementation surfaces work that is important but outside the pla
|
|
|
158
170
|
- ❌ **Branches & Worktrees [override]** — never self-create git branches or worktrees; commit straight to the checked-out branch. This replaces any built-in "branch first on the default branch" default. Exception: when the user asks for a pull request, create the branch the PR requires before committing its changes.
|
|
159
171
|
- ❌ **Protected Files** — before editing, if `docs/operations/protected-files.md` exists, read it and never modify any path it lists; never modify `AGENTS.md` or that file itself.
|
|
160
172
|
- ✅ **Browser Automation** — Claude in Chrome / CDP browser tools: use freely when useful, no need to ask first.
|
|
161
|
-
- ✅ **
|
|
173
|
+
- ✅ **Delegation** — when to fan out, tiers, and trust are § Delegation.
|
|
162
174
|
- ⚠️ **Plans** — created directly in `docs/history/plans/` (see Workflows). Once `Status: Complete` or `Abandoned`, frozen — never edited. If scope changes after completion, write a new dated plan linking back.
|
|
163
175
|
- ⚠️ **Tool Issues** — if any CLI tool, shell alias, or MCP tool behaves unexpectedly (syntax errors, silent failures, wrong defaults), report the exact tool, command, and error to the user so they can fix the underlying library.
|
|
164
176
|
|
|
@@ -179,4 +191,4 @@ For real code (the CLI under `packages/`, hook scripts):
|
|
|
179
191
|
|
|
180
192
|
## Runtime Notes
|
|
181
193
|
|
|
182
|
-
etna runs in Claude Code. Sub-agent dispatch is the Agent tool; sub-agents can run skills and spawn their own sub-agents (probe-verified; re-verify on runtime updates), but cannot hold the browser connection (browser work is Claude in Chrome, main session only). The user-level memory store is `~/.claude/` (auto-memory under `~/.claude/projects/...`). The ownership index and skill/agent descriptions are injected at session start; skills are invoked as slash commands (e.g. `/brainstorm start`). Dispatch tiers: mechanical fan-out runs on the cheapest capable tier;
|
|
194
|
+
etna runs in Claude Code. Sub-agent dispatch is the Agent tool; sub-agents can run skills and spawn their own sub-agents (probe-verified; re-verify on runtime updates), but cannot hold the browser connection (browser work is Claude in Chrome, main session only). The user-level memory store is `~/.claude/` (auto-memory under `~/.claude/projects/...`). The ownership index and skill/agent descriptions are injected at session start; skills are invoked as slash commands (e.g. `/brainstorm start`). Dispatch tiers (§ Delegation): the standard tier is the session default; mechanical fan-out runs on the cheapest capable tier; the strongest tier only on explicit user switch or request — pick by capability at dispatch, since model names go stale.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// harness/etna/hooks/generate-ownership-index.mjs — SessionStart hook: scan docs/features/**/*.md,
|
|
2
2
|
// extract the focal frontmatter (owns / module / keywords / status), and inject a compact
|
|
3
3
|
// code-path → owning-doc index via additionalContext. Fires on startup/resume/clear/compact so the
|
|
4
4
|
// map survives /clear and /compact and is regenerated fresh every time. Writes no file.
|
|
@@ -50,6 +50,26 @@ function unquote(s) {
|
|
|
50
50
|
|
|
51
51
|
// Read one frontmatter key: scalar (`k: v`), inline array (`k: [a, b]`), or a following `- item` block.
|
|
52
52
|
// Returns a string for scalars, an array for lists, or undefined when the key is absent.
|
|
53
|
+
// One YAML list/array item -> clean value: a quoted item ends at its closing quote
|
|
54
|
+
// (anything after - trailing comments - drops); an unquoted item ends at ` #`.
|
|
55
|
+
function cleanItem(s) {
|
|
56
|
+
const t = String(s).trim();
|
|
57
|
+
const q = t[0];
|
|
58
|
+
if (q === '"' || q === "'") {
|
|
59
|
+
const end = t.indexOf(q, 1);
|
|
60
|
+
if (end > 0) return t.slice(1, end).trim();
|
|
61
|
+
}
|
|
62
|
+
const hash = t.search(/\s#/);
|
|
63
|
+
return unquote(hash >= 0 ? t.slice(0, hash) : t);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// `[a, b] # comment` -> items; content ends at the closing bracket, not the line end.
|
|
67
|
+
function parseInlineArray(raw) {
|
|
68
|
+
const end = raw.indexOf("]");
|
|
69
|
+
const body = (end >= 0 ? raw.slice(0, end) : raw).replace(/^\[/, "");
|
|
70
|
+
return body.split(",").map((s) => cleanItem(s)).filter(Boolean);
|
|
71
|
+
}
|
|
72
|
+
|
|
53
73
|
function field(block, key) {
|
|
54
74
|
const lines = block.split(/\r?\n/);
|
|
55
75
|
const head = new RegExp(`^${key}\\s*:\\s*(.*)$`);
|
|
@@ -58,16 +78,21 @@ function field(block, key) {
|
|
|
58
78
|
if (!m) continue;
|
|
59
79
|
const raw = m[1].trim();
|
|
60
80
|
if (raw === "") {
|
|
81
|
+
// A bare key may continue as an indented inline array on the next line, or a `- item` block.
|
|
82
|
+
const next = (lines[i + 1] || "").trim();
|
|
83
|
+
if (next.startsWith("[")) {
|
|
84
|
+
return parseInlineArray(next);
|
|
85
|
+
}
|
|
61
86
|
const items = [];
|
|
62
87
|
for (let j = i + 1; j < lines.length; j++) {
|
|
63
88
|
const li = /^\s*-\s+(.*)$/.exec(lines[j]);
|
|
64
89
|
if (!li) break;
|
|
65
|
-
items.push(
|
|
90
|
+
items.push(cleanItem(li[1]));
|
|
66
91
|
}
|
|
67
92
|
return items;
|
|
68
93
|
}
|
|
69
94
|
if (raw.startsWith("[")) {
|
|
70
|
-
return raw
|
|
95
|
+
return parseInlineArray(raw);
|
|
71
96
|
}
|
|
72
97
|
return unquote(raw);
|
|
73
98
|
}
|
|
@@ -86,6 +111,7 @@ function buildIndex(projectDir) {
|
|
|
86
111
|
const files = listMarkdown(featuresDir);
|
|
87
112
|
const lines = [];
|
|
88
113
|
let deprecated = 0;
|
|
114
|
+
let indexed = 0;
|
|
89
115
|
for (const file of files) {
|
|
90
116
|
let text;
|
|
91
117
|
try {
|
|
@@ -104,6 +130,7 @@ function buildIndex(projectDir) {
|
|
|
104
130
|
}
|
|
105
131
|
const moduleLabel = (field(block, "module") || "—").toString();
|
|
106
132
|
const keywords = asList(field(block, "keywords"));
|
|
133
|
+
indexed += 1;
|
|
107
134
|
const doc = path.relative(projectDir, file).split(path.sep).join("/");
|
|
108
135
|
const kw = keywords.length ? `[${keywords.join(", ")}]` : "[]";
|
|
109
136
|
for (const glob of owns) {
|
|
@@ -115,7 +142,15 @@ function buildIndex(projectDir) {
|
|
|
115
142
|
const header =
|
|
116
143
|
"# Ownership index (generated) — code-path glob → owning feature doc · module · keywords · status\n" +
|
|
117
144
|
"# Match the file or topic you're about to touch, then read the owning doc before changing it.\n";
|
|
118
|
-
|
|
145
|
+
// A doc dropped by a parse failure is indistinguishable from one that owns nothing,
|
|
146
|
+
// so report the tally: seen vs indexed is the only signal a silent skip leaves.
|
|
147
|
+
const skipped = files.length - indexed - deprecated;
|
|
148
|
+
const notes = [];
|
|
149
|
+
if (deprecated > 0) notes.push(`${deprecated} deprecated`);
|
|
150
|
+
if (skipped > 0) notes.push(`${skipped} with no owns:`);
|
|
151
|
+
const footer = notes.length
|
|
152
|
+
? `\n# (${indexed}/${files.length} feature doc(s) indexed - ${notes.join(", ")})`
|
|
153
|
+
: "";
|
|
119
154
|
return header + lines.join("\n") + footer;
|
|
120
155
|
}
|
|
121
156
|
|
|
@@ -8,7 +8,9 @@ Every unit of work leaves one record — `docs/history/changelog/YYYY-MM-DD-{thr
|
|
|
8
8
|
| --- | --- |
|
|
9
9
|
| A plan reaches `Status: Complete` | A draft entry for that plan, linked to it — written now, while the session still holds the context |
|
|
10
10
|
| The user asks for a changelog | The entry for the work in hand. No commit required |
|
|
11
|
-
| A commit is made | Every non-exempt commit is covered by an entry — the `commit` skill writes or completes it |
|
|
11
|
+
| A commit is made | Every non-exempt commit is covered by an entry — the `commit` skill writes or completes it (no `commit` skill in the runtime ⇒ write the entry from the `documentation` skill's `templates/changelog-entry.md` and stage it with the commit) |
|
|
12
|
+
|
|
13
|
+
An entry is owed only by work that changes promised behavior or takes a design decision; mechanical and cosmetic commits — a typo, a copy tweak, a config value, a log line — take only their `docs/history/CHANGELOG.md` row, no entry file. The failure fields (`Ask:`, `Skills:`, `Pin:`) are required only when non-none.
|
|
12
14
|
|
|
13
15
|
## Lifecycle
|
|
14
16
|
|
|
@@ -17,3 +19,7 @@ Draft (created before its commit exists) → complete (missing fields filled fro
|
|
|
17
19
|
## Granularity
|
|
18
20
|
|
|
19
21
|
A commit is the smallest unit an entry may describe; above that the mapping is judgment — four commits may be four entries or one, whichever reads better as history. An entry spanning several commits rides in the **last** of them, naming the predecessors in `Commits:`. When work exceeds what a draft describes, write a second entry rather than stretching the draft — the first stays an honest account of the plan.
|
|
22
|
+
|
|
23
|
+
## Migrations are a different genre
|
|
24
|
+
|
|
25
|
+
**One-shot migrations are a different genre.** Work that runs **once** against a live system — a data backfill, a schema cutover, a dependency or harness upgrade rolled across repos — is a **migration runbook** at `docs/history/migrations/YYYY-MM-DD-{slug}.md` (template: the `documentation` skill's `templates/migration-runbook.md`), authored **before** execution and outcome-stamped after. A changelog entry says what changed in the repo; a runbook says what was executed against the world and how to verify or undo it. A repeatable procedure is neither — that is `docs/operations/`. When a runbook defers targets, it records **why** and the **trigger to re-evaluate them**, so the next run re-checks rather than inheriting the skip.
|
|
@@ -1,54 +1,32 @@
|
|
|
1
1
|
# General Standards
|
|
2
2
|
|
|
3
|
-
Runtime versions, the
|
|
3
|
+
Runtime versions, package policy, the API response envelope, and GitHub Actions pins — the workspace baseline.
|
|
4
4
|
|
|
5
5
|
## Runtime Versions
|
|
6
6
|
|
|
7
|
-
- **Node.js:**
|
|
7
|
+
- **Node.js:** the version pinned in `.nvmrc` / `package.json` `engines` — **never** a hardcoded number, **never** the runner's default. Workflows use `node-version-file: .nvmrc`.
|
|
8
8
|
- **Package manager:** detect from the lockfile — **never** hardcode one.
|
|
9
9
|
- **PostgreSQL:** 17 · **Redis:** 7.x (latest)
|
|
10
10
|
|
|
11
11
|
## Packages
|
|
12
12
|
|
|
13
|
-
**Only**
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
| `sonner` | ^2.0.7 | Toast notifications | `react-toastify` |
|
|
31
|
-
| `react-window` | ^2.2.3 | List virtualization | `react-virtualized` |
|
|
32
|
-
| `nanoid` | ^6.0.0 | ID generation | `uuid` |
|
|
33
|
-
| `express` | ^5.2.1 | HTTP server | `fastify`, `koa` |
|
|
34
|
-
| `drizzle-orm` | ^0.45.2 | Database ORM | `prisma`, `sequelize`, `typeorm` |
|
|
35
|
-
| `drizzle-kit` | ^0.31.10 | Schema tooling | — |
|
|
36
|
-
| `zod` | ^4.2.1 | Schema validation | `yup`, `joi` |
|
|
37
|
-
| `jose` | ^6.1.3 | JWT handling | `jsonwebtoken` |
|
|
38
|
-
| `microdiff` | ^1.5.0 | JSON object diffing | `deep-diff`, `just-diff` |
|
|
39
|
-
| `react18-json-view` | ^0.2.9 | JSON tree view | `react-json-view` |
|
|
40
|
-
| `@tiptap/react` | ^3.11.1 | Rich text editor | `slate`, `quill`, `draft-js` |
|
|
41
|
-
| `shiki` | ^4.3.1 | Syntax highlighting | `prism`, `highlight.js` |
|
|
42
|
-
| `lucide-react` | ^1.26.0 | Icons | `react-icons`, `heroicons` |
|
|
43
|
-
| `@pdfme/generator` | ^6.1.12 | PDF generation | `jspdf`, `pdfkit` |
|
|
44
|
-
| `cmdk` | ^1.1.1 | Command palette | `kbar`, `ninja-keys` |
|
|
45
|
-
| `@monaco-editor/react` | ^4.7.0 | Code editor | `codemirror`, `ace` |
|
|
46
|
-
| `localforage` | ^1.10.0 | Client-side storage | `idb`, `dexie` |
|
|
47
|
-
| `react-markdown` | ^10.1.0 | Markdown rendering | `marked`, `markdown-it` |
|
|
48
|
-
| `remark-gfm` | ^4.0.1 | GFM (tables, tasklists) | `remark-github`, custom |
|
|
49
|
-
| `fast-deep-equal` | ^3.1.3 | Deep equality checks | `lodash.isEqual` |
|
|
50
|
-
| `@ngneat/falso` | latest | Fake data generation | `@faker-js/faker`, `chance` |
|
|
51
|
-
| `pino` | ^10.1.0 | Logging | `winston` |
|
|
13
|
+
**Only packages in the approved table** — `.claude/hooks/approved-packages.md`, enforced by the PreToolUse install gate, which names the file on a block. The table changes only by explicit user decision. Test packages install at `latest`; fake data comes from `@ngneat/falso` — **never** `@faker-js/faker` / `chance`.
|
|
14
|
+
|
|
15
|
+
## API Response Envelope
|
|
16
|
+
|
|
17
|
+
Success and error share **one** envelope — a cross-service contract clients branch on, so a per-service "improvement" (`success: true`, a boolean `status`, a bare payload) breaks every consumer:
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"status": 1,
|
|
22
|
+
"message": "Message sent successfully",
|
|
23
|
+
"data": { "delivered": [{ "user@example.com": 2 }] }
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Error: `{ "status": 0, "message": "Error description", "data": null }`
|
|
28
|
+
|
|
29
|
+
HTTP codes, default list: `200`, `201` (created), `400`, `401` (not authenticated), `403` (not authorized), `404`, `500` — plus `204`/`304` (null-body responses), `409` (conflicting write), `429` (rate limit), `503` (unhealthy dependency) where the semantics call for them. Middleware- and protocol-emitted codes are exempt from the envelope.
|
|
52
30
|
|
|
53
31
|
## GitHub Actions
|
|
54
32
|
|
|
@@ -59,4 +37,4 @@ Pin the major, and check it against the action's releases — a major behind sti
|
|
|
59
37
|
| `actions/checkout` | v7 | Repo checkout |
|
|
60
38
|
| `actions/setup-node` | v7 | Node toolchain + npm cache |
|
|
61
39
|
|
|
62
|
-
Set `node-version`
|
|
40
|
+
Set `node-version` via `node-version-file: .nvmrc`, **never** a hardcoded number and **never** the runner's default.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Nomenclature
|
|
2
2
|
|
|
3
|
-
Naming and casing for code — identifiers, files, folders. The rationale throughout is consistency: one concept, one name, one casing shape, in every repo that loads this rule.
|
|
3
|
+
Naming and casing for code — identifiers, files, folders. The rationale throughout is consistency: one concept, one name, one casing shape, in every repo that loads this rule.
|
|
4
4
|
|
|
5
5
|
Names state intent in full words — clarity over brevity; no abbreviations unless universally understood (`id`, `url` ✅ · `cfg`, `btn`, `idx` ❌).
|
|
6
6
|
|
|
@@ -12,7 +12,7 @@ Names state intent in full words — clarity over brevity; no abbreviations unle
|
|
|
12
12
|
| `PascalCase` | classes, type definitions, components; the file exporting one | `PaymentProcessor`, `AppsListPage.tsx` |
|
|
13
13
|
| `UPPER_SNAKE_CASE` | constants, environment variables | `MAX_RETRY_COUNT` |
|
|
14
14
|
| `kebab-case` | URLs, CSS class names, HTML IDs, multi-word folders | `user-profile`, `workspace-provisioning/` |
|
|
15
|
-
| `snake_case` | database tables, columns, indexes
|
|
15
|
+
| `snake_case` | database tables, columns, indexes | `created_at` |
|
|
16
16
|
|
|
17
17
|
**A file exporting one component carries that component's name exactly**, so an import names the file it came from; a single-word folder is plain lowercase (`lib`, `surfaces`). ❌ Never `snake_case` a file or folder — that casing belongs to the database.
|
|
18
18
|
|
|
@@ -28,7 +28,3 @@ Names state intent in full words — clarity over brevity; no abbreviations unle
|
|
|
28
28
|
| Event handler | `handle` or `on` prefix | `handleSubmit`, `onPageLoad` |
|
|
29
29
|
| Interface | `I` prefix acceptable; type aliases stay plain | `IConfigOptions`, `AuthResponse` |
|
|
30
30
|
| Async function | verb phrase; `Async` suffix acceptable | `loadConfigAsync` |
|
|
31
|
-
|
|
32
|
-
## Database
|
|
33
|
-
|
|
34
|
-
Table, column, index, and key naming for relational schemas — the `id` / `slug` / `label` vocabulary, junction `_map` tables, and Drizzle mirrors — lives in [`database.md`](database.md), which routes general code naming back here.
|
|
@@ -1,9 +1,44 @@
|
|
|
1
|
-
# Testing
|
|
1
|
+
# Testing & Verification
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**When** work is proven and **which technology** proves it — the standing constraints that bind on every turn. The full lifecycle procedure — deriving a plan's Test Obligations, placing tests in strata, executing the verification gate — is the `testing` skill, invoked at those moments; this rule never restates it.
|
|
4
|
+
|
|
5
|
+
## Two regimes
|
|
6
|
+
|
|
7
|
+
**Deferral is a property of plans, not of code.** A plan carries a Test Obligations ledger and a gate that discharges it; nothing else does, so nothing else may defer.
|
|
8
|
+
|
|
9
|
+
| Regime | During the work | Proven |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| **Plan-driven build** | No new test files. Code only — the loop stays fast | At the verification gate, before `Status: Complete` |
|
|
12
|
+
| **Bug fix** — a defect in shipped behavior | The regression test ships with the fix | Immediately — it fails before the change, passes after |
|
|
13
|
+
| **Ad-hoc / non-plan change** | The test ships with the change **when it alters promised behavior** — layout, copy, and config tweaks owe none | Immediately, same discipline as a bug fix |
|
|
14
|
+
|
|
15
|
+
- **A bug fix cannot defer** — "fails before, passes after" is provable afterward only by reverting to the pre-fix ref, a cost nobody pays; capture the property at fix time or lose it.
|
|
16
|
+
- **Ad-hoc work cannot defer — there is no ledger to defer into.** A non-plan change that alters no promised behavior — a pure refactor, a rename — owes no test.
|
|
17
|
+
|
|
18
|
+
## During the loop
|
|
19
|
+
|
|
20
|
+
Rules for the plan regime between the plan gate and the verification gate:
|
|
21
|
+
|
|
22
|
+
- **No new test files** — obligations wait in the plan's ledger (written at the plan gate by the `testing` skill).
|
|
23
|
+
- **Existing tests broken by the plan's intended behavior change are updated to the new contract before any mid-plan commit** — the shared branch never carries a red suite, and an update is never a weakening (§ Discipline).
|
|
24
|
+
- **A defect in the plan's own in-flux code is the loop iterating** — no test, no ledger row. **A pre-existing bug in shipped behavior is the bug-fix regime even mid-plan**: fix it with its regression test now — deferring it to the gate loses "fails before" — or send it to the backlog via Out-of-Scope Discovery. Never fix silently.
|
|
25
|
+
- **The ledger is amendable while the plan is open** — the gate discharges whatever it holds at gate time.
|
|
26
|
+
- **A mid-plan commit is a checkpoint, not a verification claim.**
|
|
27
|
+
|
|
28
|
+
## The gate
|
|
29
|
+
|
|
30
|
+
**A discrete, user-triggered step.** When implementation is complete, report it and offer the gate — never run it unbidden, and never flip `Status: Complete` without it. An explicit user acceptance of finished plan work — "ship it", "commit", "looks good" — counts as the trigger; open the gate without asking again. A plan with outstanding obligations stays open, whatever the code does. The procedure — checklist, drive-then-pin ladder, row discharge, what earns a durable test — is the `testing` skill (gate mode).
|
|
31
|
+
|
|
32
|
+
- **Precondition: the ledger exists.** A plan with no Test Obligations section is blocked at the gate — run the `testing` skill (plan-gate mode) on it first; an empty ledger passes vacuously and the gap surfaces only after the file is frozen.
|
|
33
|
+
- **The verdict is never delegated** (the root policy file § Delegation), and where browser work is main-session-only (its § Runtime Notes), the driving is too. Fan-out may prepare fixtures or draft test bodies; the driving and the verdict stay inline.
|
|
34
|
+
- **The gate needs no stronger tier than the session default** — a standard-tier session suffices whatever tier built the plan; the plan and its ledger carry all the state the gate needs, so gating in a fresh session loses nothing.
|
|
35
|
+
- **Report what happened, including failures.** A gate that reports green while a suite is red is worse than no gate; state the failing test and its output.
|
|
36
|
+
- **Abandonment does not erase debt.** Before `Status: Abandoned` freezes a plan whose code was committed, convert its undischarged rows into backlog items; uncommitted code owes nothing.
|
|
4
37
|
|
|
5
38
|
## Frameworks by stack
|
|
6
39
|
|
|
40
|
+
Framework choice is **never** ad hoc and never the user's problem mid-task: detect the stack, use its row; if the repo already has a runner, that runner wins — **never** introduce a second framework beside it.
|
|
41
|
+
|
|
7
42
|
| Stack | Unit / integration | Component | E2E | HTTP mocking | Don't use |
|
|
8
43
|
| --- | --- | --- | --- | --- | --- |
|
|
9
44
|
| Node + Vite / React (web) | `vitest` | `@testing-library/react` (+ `@testing-library/user-event`, `happy-dom`) | `@playwright/test` | `msw` | `jest`, `mocha`, `jasmine`, `cypress`, `enzyme` |
|
|
@@ -12,7 +47,7 @@ Test technology and placement — framework per stack, suite layout, mocking pol
|
|
|
12
47
|
| Cloudflare Workers | `vitest` + `@cloudflare/vitest-pool-workers` | — | `@playwright/test` against `wrangler dev` | `msw` | `jest` |
|
|
13
48
|
| Rust | `cargo test` (built-in) | — | — | — | — |
|
|
14
49
|
|
|
15
|
-
Test packages install at `latest` —
|
|
50
|
+
Test packages install at `latest` — outside the approved-packages pin set. Fake data comes from `@ngneat/falso` — **never** `@faker-js/faker` / `chance`.
|
|
16
51
|
|
|
17
52
|
## Conventions
|
|
18
53
|
|
|
@@ -21,3 +56,9 @@ Test packages install at `latest` — they sit outside [`general.md`](general.md
|
|
|
21
56
|
- **Unit and E2E trees stay separate.** Vitest/Jest suites in `tests/`; Playwright/Maestro suites in `e2e/` with their own config — **never** mixed into the unit runner's glob.
|
|
22
57
|
- **No test doubles for what you own.** Prefer real instances — in-memory SQLite for drizzle, the actual Express app via `supertest` — over mocks; mock **only** true externals (network via `msw`, time via the runner's fake timers).
|
|
23
58
|
- **Determinism.** No real network, no real time, no shared mutable state between tests; every test **must** pass alone and in any order.
|
|
59
|
+
|
|
60
|
+
## Discipline
|
|
61
|
+
|
|
62
|
+
- **Never weaken, skip, or delete a test to mask an unexplained failure.** When a plan or LLD intentionally changes behavior, updating the affected tests to the new contract is part of that change.
|
|
63
|
+
- **A behavior that is compiler-guarded owes no test** — if it cannot ship green-but-broken, a test adds cost and no safety.
|
|
64
|
+
- **Throwaway checks are not tests.** Temporary scripts written to drive a change live in scratch space and are deleted — never committed into the test tree.
|
|
@@ -24,6 +24,7 @@ Policy files (`CLAUDE.md`, rules) are declarative — assertion bullets and tabl
|
|
|
24
24
|
## Routing
|
|
25
25
|
|
|
26
26
|
- **Link, don't copy — one canonical source per topic.** `CLAUDE.md` is a **router, not a manual**: per workflow, when to enter, what to dispatch, where the output lands — mechanics live in the agent or skill file, which loads only when it runs.
|
|
27
|
+
- **A rule never references a sibling rule.** Rules co-load, so pointing at one from another routes a reader to text already in front of them — noise that also drifts the moment either file moves. State what the rule owns, self-contained; the only outward links a rule carries are to skills and agents, whose bodies do *not* co-load. Routing downward from `CLAUDE.md` to a rule is fine — that is the router doing its job.
|
|
27
28
|
- **Cut generic engineering advice.** Agents already know how to code; keep only what is true of *this* stack and not derivable by looking at it.
|
|
28
29
|
- **Keep load-bearing rules even when project-specific.** Genericizing is for reference material, not guardrails — deleting a hard rule removes a constraint the agent will otherwise violate.
|
|
29
30
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Plan (docs/history/plans/YYYY-MM-DD-feature-name.md)
|
|
2
2
|
|
|
3
|
-
Record. Use for: every implementation plan. Plans are created here directly with `Status: Draft`; after approval the plan gates (`boundary`, then `
|
|
3
|
+
Record. Use for: every implementation plan. Plans are created here directly with `Status: Draft`; after approval the plan gates (`boundary`, then `testing` plan-gate mode) run against the still-`Draft` file, the status flips to `Status: In Progress` at the first implementation step, and the file freezes at `Status: Complete` or `Status: Abandoned`. Once frozen, never edit — write a new dated plan if scope changes. The plan records the journey; the truth it implemented lives on in the feature doc and any AD it touched.
|
|
4
4
|
|
|
5
|
-
The `boundary` skill parses the **Proposed Changes** sections to check boundary impact before execution, and the `
|
|
5
|
+
The `boundary` skill parses the **Proposed Changes** sections to check boundary impact before execution, and the `testing` skill (plan-gate mode) writes a **Test Obligations** section into the plan at the same gate. Keep that structure stable — section headings and bullet shape are load-bearing for the parsers, and the Test Obligations table is the ledger the verification gate discharges before the plan may reach `Status: Complete`.
|
|
6
6
|
|
|
7
|
-
The **`Gates:`** line is machine-read: the compliance hook greps exactly the forms below, and implementation edits are blocked while a segment reads `pending`. Each gate skill rewrites only its own segment when it runs — `boundary` to `Boundary: passed YYYY-MM-DD` or `Boundary: blocked YYYY-MM-DD`; `
|
|
7
|
+
The **`Gates:`** line is machine-read: the compliance hook greps exactly the forms below, and implementation edits are blocked while a segment reads `pending`. Each gate skill rewrites only its own segment when it runs — `boundary` to `Boundary: passed YYYY-MM-DD` or `Boundary: blocked YYYY-MM-DD`; `testing` (plan-gate mode) to `Test-plan: written YYYY-MM-DD (N rows)` — the segment label stays `Test-plan`, greppable. Never hand-edit the line to skip a gate.
|
|
8
8
|
|
|
9
9
|
```
|
|
10
10
|
# {Feature Name}
|
|
@@ -52,7 +52,7 @@ Why this work is happening *now*. Link to the spec for *what* we're building; th
|
|
|
52
52
|
|
|
53
53
|
## Test Obligations
|
|
54
54
|
|
|
55
|
-
<!-- Written by the `
|
|
55
|
+
<!-- Written by the `testing` skill (plan-gate mode) at the plan gate (after `boundary`). One row per
|
|
56
56
|
promised behavior: layer · target file · oracle · fixtures. Amendable while the
|
|
57
57
|
plan is open; discharged at the verification gate. Do not hand-author. -->
|
|
58
58
|
|
|
@@ -63,6 +63,11 @@ After the rollup, **always produce a one-page candidate brief** (verdict + level
|
|
|
63
63
|
|
|
64
64
|
Every output lands under `out_dir` and is plain markdown/YAML — reviewable, quotable, and reversible.
|
|
65
65
|
|
|
66
|
-
##
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
## Delegation
|
|
67
|
+
|
|
68
|
+
- **Delegate to keep bulk tool output out of the main context.** A sub-agent's raw output dies with it; the same output read inline is re-read and re-billed on every later turn.
|
|
69
|
+
- **Batch code-project scoring is the canonical fan-out here** — the `code-eval-batcher` rule dispatches the `evaluator` skill across projects in parallel, one project per sub-agent. That per-project scoring is exactly the independent, repetitive work this section exists to push out of the main context; nothing here narrows it.
|
|
70
|
+
- **Session-steering scoring stays inline.** Reading a full transcript for evidence and banding it against `rubric.md` is judgment work, not mechanical fan-out — never delegate a scoring pass by reflex; a second opinion is for a high-stakes call or an explicit request.
|
|
71
|
+
- **A delegated result is a report, not verifiable ground truth** — a returned scorecard or rollup still needs its own validation (`validate_scorecard.py`) before it's trusted.
|
|
72
|
+
- **Tiers**: mechanical fan-out (batch per-project dispatch) runs on the cheapest capable tier; judgment-heavy delegation runs on the standard tier; the strongest tier fires only on explicit user request.
|
|
73
|
+
- **An explicit user directive about tier, cost, or delegation overrides this section.** No dispatch mechanism ⇒ inline.
|
|
@@ -60,6 +60,12 @@ The user is adding knowledge. Drafting and placement happen here; the human deci
|
|
|
60
60
|
|
|
61
61
|
Everything is git-checked-in: any write is reviewable and reversible. When anything here seems to conflict with `meta/contract.md`, the contract wins.
|
|
62
62
|
|
|
63
|
-
##
|
|
63
|
+
## Delegation
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
Governs sub-agent dispatch — when to fan out, at what tier, how far to trust the result. No dispatch mechanism ⇒ inline.
|
|
66
|
+
|
|
67
|
+
- **Delegate bulk vault work.** Whole-vault greps, multi-note traversals, corpus sweeps, and audits (`kb-audit`, `kb-init`) are self-contained hand-offs that cost less than doing them in the main session — a sub-agent's raw output dies with it, while the same output read inline is re-read and re-billed on every later turn. Independent sweeps run in parallel.
|
|
68
|
+
- **Small or judgment work stays inline** — a handful of tool calls, a single note's placement call (extend / supersede / background). Judgment is never delegated by reflex: a second opinion is for a high-stakes call or an explicit request.
|
|
69
|
+
- **A delegated result is a report, not verifiable ground truth** — a citation or claim drawn from a sub-agent's findings still resolves to the actual note before it reaches the user.
|
|
70
|
+
- **Tiers**: mechanical fan-out (sweeps, grep passes, batch classification) runs on the cheapest capable tier; judgment-heavy delegation (audit synthesis, proposal drafting) runs on the standard tier; the strongest tier only on explicit user request.
|
|
71
|
+
- **An explicit user directive about tier, cost, or delegation overrides this section.**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nurix/etna",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.56",
|
|
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": "
|
|
45
|
+
"etnaFingerprint": "e7493c40d358"
|
|
46
46
|
}
|