@nurix/etna 0.19.18 → 0.19.20

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": "4728361ccdf5",
2
+ "fingerprint": "2e71b9321651",
3
3
  "harnesses": {
4
4
  "code": {
5
5
  "plugin": "code",
@@ -110,7 +110,7 @@ Defaults — ❌ prohibitions hold unless the user explicitly asks otherwise;
110
110
  - ❌ **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.
111
111
  - ❌ **Protected Files** – Before editing, if `docs/operations/protected-files.md` exists, read it and never modify any path it lists; also never modify `AGENTS.md` or the `protected-files.md` file itself.
112
112
  - ✅ **Browser Automation** – If your runtime provides browser automation, use it freely; no need to ask first. If it doesn't — or you are an agent that can't hold the browser connection (see Runtime Notes) — return a browser-verification checklist (URLs, actions, expected outcomes) for the orchestrating session or the user to run.
113
- - ✅ **Delegate at scale** – If your runtime supports sub-agent dispatch: offload large, independent, or parallelizable work (broad research, audits, multi-file sweeps) to sub-agents with self-contained prompts (the sub-agent sees none of your conversation); parallelize independent dispatches; keep small, well-understood edits in the main session — a dispatch whose hand-off costs more than the work is waste. Mechanical fan-out **always** runs on the cheap tier. Judgment-heavy work stays in the main session — offload it **only when the user explicitly asks** (concrete tier names live only in Runtime Notes). No dispatch mechanism ⇒ do the work inline.
113
+ - ✅ **Fan-out is a tool, not a default** — the main session does the work and its own reasoning; a delegated result comes back as a summary, not verifiable ground truth. Delegate **only when** the work is large, independent, or repetitive enough that a self-contained hand-off (the sub-agent sees none of the conversation) costs less than the work — broad research, wide sweeps, audits — and run independent delegations in parallel. **Never delegate judgment by reflex**: a second opinion is for a high-stakes call or an explicit request. No dispatch mechanism ⇒ inline.
114
114
  - ⚠️ **Plans** – Plans are created directly in `docs/history/plans/` (see Workflows). Once `Status: Complete` or `Status: Abandoned`, the file is frozen — never edited. If scope changes after completion, write a new dated plan that links back to the old one.
115
115
  - ⚠️ **Tool Issues** – If any CLI tool, shell alias, or MCP tool behaves unexpectedly (syntax errors, silent failures, wrong defaults), report the exact tool name, command, and error to the user so they can fix or remove the underlying library.
116
116
 
@@ -127,5 +127,5 @@ Defaults — ❌ prohibitions hold unless the user explicitly asks otherwise;
127
127
 
128
128
  Everything above is runtime-neutral. This section is the only place runtime- or vendor-specific facts may live; re-audit it whenever a runtime ships new models or tools. Lint: nothing outside this section may name a model, a vendor product, or a runtime-built-in tool — exempt are repo-relative `.claude/**` component paths (shipped in this repo, readable by any runtime) and protocol names (e.g. MCP).
129
129
 
130
- - **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 reliably hold the browser connection (the "can't hold the browser connection" condition the Browser Automation guardrail refers to) — browser work is Chrome CDP ("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 pins the fast tier (sonnet-class); a user-requested judgment-heavy dispatch takes the strong tier (opus-class) — tier names go stale, re-check on model releases.
130
+ - **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 reliably hold the browser connection (the "can't hold the browser connection" condition the Browser Automation guardrail refers to) — browser work is Chrome CDP ("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; a user-requested second opinion takes the strongest — pick by capability at dispatch, since model names go stale.
131
131
  - **Runtimes without native component support** (AGENTS.md readers, etc.): read `.claude/agents/<name>.md` and each skill's `.claude/skills/<name>/SKILL.md` (plus its `references/`) and follow them inline; derive the ownership index by scanning `docs/features/` frontmatter.
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "harness": "code",
3
3
  "name": "code",
4
- "version": "3.1.12",
4
+ "version": "3.1.13",
5
5
  "files": [
6
6
  ".prettierignore",
7
7
  ".prettierrc.json",
8
8
  ".vscode/settings.json"
9
9
  ],
10
- "digest": "7a392f55e225"
10
+ "digest": "c1f024029b4d"
11
11
  }
@@ -4,6 +4,8 @@ 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
+ **Fan-out is a tool, not a default** — the main session does the work and its own reasoning; a delegated result comes back as a summary, not verifiable ground truth. Delegate **only when** the work is large, independent, or repetitive enough that a self-contained hand-off (the sub-agent sees none of the conversation) costs less than the work — broad research, wide sweeps, audits — and run independent delegations in parallel. **Never delegate judgment by reflex**: a second opinion is for a high-stakes call or an explicit request. No dispatch mechanism ⇒ inline. (Ingestion is the sanctioned application: each dimension is large and independent, so its collectors are fanned out deliberately, never by reflex.)
8
+
7
9
  ---
8
10
 
9
11
  ## Access is a capability vector (the front gate)
@@ -36,6 +38,24 @@ Agent name = dimension name. ⚠ = gated (needs user authorization before dispat
36
38
 
37
39
  ---
38
40
 
41
+ ## Step 0 — first run (tooling check)
42
+
43
+ **Once per folder, before Mode 1.** Capture depth depends on host tooling most machines lack (`gron`, `trafilatura`, `mitmproxy`, `chrome-remote-interface`, …). On the first run in a corpus folder, check the state file `.claude/discover-tooling.json`:
44
+
45
+ - **It exists** → tooling was already reviewed here — skip straight to Mode 1. **Never re-prompt in the same folder.**
46
+ - **It's absent** → run the one-time check:
47
+ 1. Read [`tooling-recommendations.md`](tooling-recommendations.md) (beside this file at the project root) — the Tier 1 (clean) and Tier 2 (gated) tool lists + the AVOID list.
48
+ 2. **Validate what's already installed before recommending anything** — `command -v <tool>` per recommended tool (`npm ls -g <pkg>` for the Node libraries that ship no binary, e.g. `chrome-remote-interface`). Detection only — install nothing yourself.
49
+ 3. **Recommend only the missing tools**, grouped **clean** (safe to install freely — offer the Tier-1 one-paste block) vs **gated** (first-party / user-owned / opt-in — surface the command but **never run it for the user**; these need the user in the loop). Never suggest anything on the AVOID list. If nothing is missing, say so in one line.
50
+ 4. **Write `.claude/discover-tooling.json`** so the harness never asks again in this folder:
51
+ ```json
52
+ { "checked": "<ISO date>", "present": ["gron", "pandoc"], "missing": ["mitmproxy"], "recommended": true }
53
+ ```
54
+
55
+ The state file is **host-local** (tools live on the machine, not the repo) — gitignore it in a shared folder; delete it to force a fresh check after installing a batch. This step never blocks a run: a user who declines proceeds to Mode 1 on whatever tooling is present, and a genuinely missing *preferred* capability is re-surfaced at the Mode 2 capability-gap checkpoint.
56
+
57
+ ---
58
+
39
59
  ## Mode 1 — Discovery
40
60
 
41
61
  Cheap, read-only. Scope the target, grade its access, detect which dimensions it exposes.
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "harness": "discover",
3
3
  "name": "discover",
4
- "version": "0.1.10",
4
+ "version": "0.1.11",
5
5
  "files": [
6
6
  ".prettierignore",
7
7
  ".prettierrc.json",
8
- ".vscode/settings.json"
8
+ ".vscode/settings.json",
9
+ "tooling-recommendations.md"
9
10
  ],
10
- "digest": "a672787b9962"
11
+ "digest": "3b981c0284cc"
11
12
  }
@@ -0,0 +1,119 @@
1
+ # Tooling recommendations — what to install to improve capture & synthesis
2
+
3
+ > The `discover` harness reads this file on **first run** (Step 0 in [`CLAUDE.md`](CLAUDE.md)): it detects which of these tools are already on the host, recommends only the **missing** ones (the gated ones only with you in the loop), and records the result in `.claude/discover-tooling.json` so it never re-prompts in this folder. Nothing here is installed automatically — the harness recommends, you decide.
4
+
5
+ The host almost always arrives strong on languages and package managers (node, pnpm, python, uv, cargo, gh, jq, ripgrep) but **bare on capture/analysis tooling** — the tools below are what turn a shallow capture into a deep one.
6
+
7
+ ## How to read this
8
+
9
+ - **clean** — passive / local-only; always in-bounds. Install freely.
10
+ - **gated** — fine, but only **first-party / user-owned / opt-in** (you install the CA, you route _your own_ client, you own the keys). mitmproxy, websocat, CDP, subfinder/tlsx, frida-on-your-own-device.
11
+ - **avoid** — crosses the harness bright line (active scanning / exploitation / third-party packet capture). Listed so they're _not_ added by reflex.
12
+
13
+ The harness is for **spec-writing / integration / competitive analysis** — passive or first-party only, respect TOS/robots. No tool below changes that; the gated ones just need the user in the loop.
14
+
15
+ ---
16
+
17
+ ## Tier 1 — install now (clean, broad leverage)
18
+
19
+ The highest-consensus, always-in-bounds tools. One paste:
20
+
21
+ ```bash
22
+ # Homebrew (CLI analysis + data-wrangling + web→text)
23
+ brew install gron pandoc ast-grep scc universal-ctags oasdiff fd yq dasel monolith tokei sevenzip
24
+ # Rust
25
+ cargo install htmlq
26
+ # Python (via uv — pipx is absent; uv tool install is the path)
27
+ uv tool install trafilatura && uv tool install griffe
28
+ # Node global (JS/TS surface + bundle de-obfuscation + spec lint)
29
+ npm i -g webcrack source-map-explorer @arethetypeswrong/cli publint @electron/asar typescript @stoplight/spectral-cli
30
+ # Headless browser for JS-rendered docs/marketing (clean — your own headless instance)
31
+ npm i -g playwright && npx playwright install chromium
32
+ ```
33
+
34
+ | Tool | Unlocks | Dimensions served |
35
+ | --- | --- | --- |
36
+ | **gron** | flatten any JSON → greppable/diffable `path = value` (specs, captures, manifests, HAR, configs) | **7** (codebase, api, session, bundle, infra, wire, cross-cutting) |
37
+ | **trafilatura** | boilerplate-stripped main-content + dates from HTML → clean markdown; feed/sitemap discovery | **4** (docs, website, community, infra) |
38
+ | **pandoc** | deterministic HTML→GFM (headings, tables, code fences) at scale | 3 (docs, website, community) |
39
+ | **ast-grep** | tree-sitter structural search/count across many files+langs (call sites, routes, exports) — catches what regex misses | 2 (codebase, bundle) |
40
+ | **oasdiff** | structured breaking-vs-non-breaking OpenAPI diff — makes the published-vs-app-own diff machine-checked | 2 (api, cross-cutting) |
41
+ | **webcrack** | un-minify / un-webpack / de-obfuscate SPA & Electron JS into readable modules | 2 (bundle, distribution) |
42
+ | **scc** | instant LOC-by-language + complexity census of a fresh clone (JSON) — the codebase opening move | 1 (codebase) |
43
+ | **universal-ctags** | real multi-lang JSON symbol index (the host's BSD ctags is broken for this) | 1 (codebase) |
44
+ | **htmlq** | surgical CSS-selector extraction (pricing cards, feature tables) instead of regex | 1 (website) |
45
+ | **source-map-explorer** | reassemble shipped `.map` → original `src/` tree (the `source-map-reassembly` method) | 1 (bundle) |
46
+ | **spectral** | validate/resolve an OpenAPI/AsyncAPI spec → structured endpoint/security/$ref catalog | 1 (api) |
47
+ | **griffe** | extract a PyPI package's full public API (the `.d.ts`-equivalent for Python) | 1 (packages) |
48
+ | **@arethetypeswrong/cli + typescript + publint** | parse the real `.d.ts`/exports type graph + grade the publish surface (verbatim, not string-mined) | 1 (packages) |
49
+ | **@electron/asar** | extract Electron `app.asar` → JS module tree (the distribution step the playbook names but can't run) | 1 (distribution) |
50
+ | **fd / yq / dasel / monolith / tokei / sevenzip** | gitignore-aware file discovery · YAML/XML/TOML query · RSS/XML→JSON · single-file page archive · LOC cross-check · multi-format extract | several |
51
+
52
+ ---
53
+
54
+ ## Tier 2 — install when a run needs them (gated: first-party / passive-care)
55
+
56
+ The capture lanes. In-bounds **only** for your own session / first-party clients / passive sources.
57
+
58
+ ```bash
59
+ brew install mitmproxy websocat grpcurl subfinder tlsx testssl jadx apktool
60
+ npm i -g chrome-remote-interface get-graphql-schema
61
+ # one-time, user-run: expose a CDP port on your own Chrome (closes the WS-frame blind spot)
62
+ # open -na "Google Chrome" --args --remote-debugging-port=9222
63
+ # mobile-only, your own device + opt-in: uv tool install frida-tools
64
+ ```
65
+
66
+ | Tool | Unlocks | Ethics note |
67
+ | --- | --- | --- |
68
+ | **mitmproxy** | decode full HTTPS + WebSocket flows of any **first-party** client (CLI/desktop/mobile/SDK) — wire-capture rung 3 keystone | user installs CA + routes _their own_ client only |
69
+ | **chrome-remote-interface** | raw CDP client → `Network.webSocketFrameReceived`/`Created`, SSE, full bodies — **captures the on-load WS frames the browser MCP's HTTP-only `read_network_requests` drops** | your own logged-in session |
70
+ | **websocat** | curl-for-WebSockets: connect/frame/replay/hexdump a realtime endpoint outside the browser | first-party endpoint |
71
+ | **grpcurl** | list services + invoke RPCs via gRPC server reflection → readable op/message catalog | first-party endpoint |
72
+ | **get-graphql-schema** | introspect a first-party GraphQL endpoint → full SDL | first-party endpoint |
73
+ | **subfinder / tlsx / testssl.sh** | passive CT/DNS subdomain breadth + structured TLS posture (vs hand-rolled crt.sh + openssl text) | passive aggregation; respect rate limits |
74
+ | **jadx / apktool** | decompile Android `.apk`/`.dex` → Java + decode `AndroidManifest`/resources (capability map) | public binary, read EULA |
75
+ | **frida-tools** | cert-pinning bypass to capture **your own** mobile client's wire | your own device + opt-in only |
76
+
77
+ **The single biggest unlock** for realtime targets: `chrome-remote-interface` + a Chrome `--remote-debugging-port` + `websocat` + `mitmproxy` together give `session`/`wire-capture` a real WebSocket/SSE capture path, instead of a client-side-remount workaround. The browser-MCP `read_network_requests` is HTTP-only — that's _why_ a realtime tap comes back empty until the remount trick.
78
+
79
+ ---
80
+
81
+ ## AVOID — do NOT install (crosses the harness bright line)
82
+
83
+ Out-of-bounds for a spec-writing/competitive-analysis harness — listed so they aren't added by reflex:
84
+
85
+ - **`nmap`, `masscan`, `naabu`** — active port sweeps / service-version probing of remote hosts.
86
+ - **`nuclei`** — template-based remote vuln scanning.
87
+ - **`sqlmap`** — injection/exploitation.
88
+ - **`amass` (active mode)** — active DNS brute-forcing (its _passive_ mode overlaps subfinder; prefer subfinder).
89
+ - **third-party `mitmproxy`, `frida` on devices you don't own, `socat` as a public relay** — third-party traffic interception is the line this harness will not cross.
90
+
91
+ These stay absent by design; the recon ethics depend on it.
92
+
93
+ ---
94
+
95
+ ## Per-dimension view (gap → top pick)
96
+
97
+ | Dimension | Biggest capability gap on a bare host | Top addition(s) |
98
+ | --- | --- | --- |
99
+ | **codebase** | no LOC census, no AST search; BSD ctags is broken | scc · ast-grep · universal-ctags (+ fd) |
100
+ | **docs** | no HTML/MDX→md, no JS-render → client-rendered docs come back empty | pandoc · trafilatura · playwright |
101
+ | **packages** | the real `.d.ts`/exports surface is string-mined, not parsed | typescript+attw+publint · griffe (Py) · yq |
102
+ | **api** | can fetch a spec but can't lint/diff/introspect/exercise it | spectral · oasdiff · get-graphql-schema · grpcurl · websocat |
103
+ | **website** | no JS-render, no clean table/text extraction → misses pricing/feature grids | trafilatura · htmlq · playwright |
104
+ | **community** | no clean changelog/blog→text, no RSS→JSON | trafilatura · pandoc · dasel |
105
+ | **session** | **structurally blind to WebSocket/SSE frames** (HTTP-only MCP, no CDP port) | chrome-remote-interface · mitmproxy · websocat |
106
+ | **deployed-client-bundle** | minified/obfuscated blob stays opaque; no source-map reassembly | webcrack · source-map-explorer · ast-grep · gron |
107
+ | **infra-backend-fingerprint** | shallow CT coverage, TLS posture by hand, sub-processor pages scraped raw | subfinder · tlsx · trafilatura (passive only) |
108
+ | **wire-capture** | keystone mitmproxy + all non-browser replay/decode clients absent | mitmproxy · websocat · grpcurl |
109
+ | **distribution-artifacts** | only CRX/Mach-O readable; no Electron/Android decoders | @electron/asar · jadx · apktool · webcrack · sevenzip |
110
+ | **cross-cutting (synthesis)** | no structured diff for the N-way seam reconciliation; no out-of-band WS capture | gron · oasdiff · chrome-remote-interface · yq |
111
+
112
+ ---
113
+
114
+ ## Known install caveats
115
+
116
+ - **`webcrack` needs Node 22.** Its hard dependency `isolated-vm` is a native (node-gyp) addon that fails to build against Node 26 (and `--omit=optional` doesn't help — the dep is non-optional). If it won't install, run it under a Node 22 LTS shim (`npx -y webcrack@latest …` in a Node-22 env), or lean on the already-clean `source-map-explorer` (the preferred `source-map-reassembly` path whenever the SPA ships `.map` files) + `ast-grep`. De-obfuscation of a _no-maps, minified_ bundle is the only gap this leaves.
117
+ - **`chrome-remote-interface` is a library, not a CLI** — it installs as a Node module and is invoked from a script, not a shell binary. Detect it with `npm ls -g chrome-remote-interface`, not `command -v`.
118
+ - **`pipx` is typically absent; use `uv tool install`** for Python CLIs (uv is present) — simpler than adding pipx.
119
+ - **`playwright` is clean** (your own headless instance) and unblocks JS-rendered docs/marketing for `docs`+`website` without contending for the gated `session` Chrome.
@@ -19,3 +19,7 @@ Strictly separated — never mix them:
19
19
  **The operator layer**: `metadata/lessons/` — read `DIGEST.md` at session start alongside the routing files; it is **prior, not canon** (its reading-protocol block governs). Everything else under `lessons/` (append-only `log/`, `forecasts.md`) loads on demand only. The `lessons-maintenance` agent (instruction set: `metadata/lessons/distillation.md`) runs **only during user sessions** — spawn it in the background when the `metadata/ops/` cursor falls a session behind.
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
+
23
+ ## Fan-out
24
+
25
+ **Fan-out is a tool, not a default** — the main session does the work and its own reasoning; a delegated result comes back as a summary, not verifiable ground truth. Delegate **only when** the work is large, independent, or repetitive enough that a self-contained hand-off (the sub-agent sees none of the conversation) costs less than the work — broad research, wide sweeps, audits — and run independent delegations in parallel. **Never delegate judgment by reflex**: a second opinion is for a high-stakes call or an explicit request. No dispatch mechanism ⇒ inline.
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "harness": "discussion",
3
3
  "name": "discussion",
4
- "version": "0.4.1",
4
+ "version": "0.4.2",
5
5
  "files": [
6
6
  ".prettierignore",
7
7
  ".prettierrc.json",
8
8
  ".vscode/settings.json"
9
9
  ],
10
- "digest": "51812973828b"
10
+ "digest": "f974d08469e5"
11
11
  }
@@ -8,7 +8,7 @@ etna governs itself with the **`etna`** harness — deliberately forked from the
8
8
 
9
9
  ## Maintenance
10
10
 
11
- Invoke the `maintenance` agent whenever you judge the docs need it — not just at first setup: a `harness-version` marker behind the installed version, docs contradicting the components they describe, unowned source paths, or drift you notice while working. Never reconcile these by hand — the agent auto-selects its mode (baseline when the marker is missing or behind, coherence audit otherwise) and hands back; if it returns a follow-up (typically the module proposal), re-invoke it to finish. Each component's internals live in the component, not here.
11
+ Invoke the `maintenance` agent whenever you judge the docs need it — not just at first setup: a missing `docs/structure.md` (the repo isn't reconciled — baseline before applying anything below), a `harness-version` marker behind the installed version, docs contradicting the components they describe, unowned source paths, or drift you notice while working. Never reconcile these by hand — the agent auto-selects its mode (baseline when the marker is missing or behind, coherence audit otherwise) and hands back; if it returns a follow-up (typically the module proposal), re-invoke it to finish. Each component's internals live in the component, not here.
12
12
 
13
13
  ---
14
14
 
@@ -64,7 +64,7 @@ These three mechanisms keep the repo self-updating: **ownership** routes you to
64
64
 
65
65
  ### Ownership — route before you edit
66
66
 
67
- Which doc is canonical for which paths is the **feature doc's own frontmatter**. A feature doc (flat in `docs/features/`) carries `owns:` (path globs — the only ownership key, pointing at `skills/**`, `harness/**`, `packages/cli/**`, …), an optional `module:` label, `keywords:`, and `status:`. Path → doc ownership is the union of every feature doc's `owns:` globs, surfaced as the generated ownership index at session start. Architecture docs describe cross-cutting patterns and own nothing; operations docs describe procedures.
67
+ Which doc is canonical for which paths is the **feature doc's own frontmatter**. A feature doc (flat in `docs/features/`) carries `owns:` (path globs — the only ownership key, pointing at `skills/**`, `harness/**`, `packages/cli/**`, …), an optional `module:` label, `keywords:`, and `status:`. Path → doc ownership is the union of every feature doc's `owns:` globs, surfaced as the generated ownership index at session start. A module is tied to its components by the `owns:` globs of the docs carrying its `module:` label — not a folder, not a separate map. Architecture docs describe cross-cutting patterns and own nothing; operations docs describe procedures.
68
68
 
69
69
  Before modifying a component in an unfamiliar area:
70
70
 
@@ -128,8 +128,8 @@ When implementing a plan, if you discover work that is important but outside the
128
128
  - ❌ **Compatibility** — never maintain backward compatibility unless specified.
129
129
  - ❌ **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.
130
130
  - ❌ **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.
131
- - ✅ **Browser Automation** — Claude in Chrome / CDP browser tools only when the user explicitly asks.
132
- - ✅ **Delegate at scale** — offload large, independent, or parallelizable work (broad research, audits, multi-file sweeps) to sub-agents with self-contained prompts; keep small, well-understood edits inline. Sub-agents can run skills and spawn their own sub-agents; keep work that needs the user's voice or the browser in the main session.
131
+ - ✅ **Browser Automation** — Claude in Chrome / CDP browser tools: use freely when useful, no need to ask first.
132
+ - ✅ **Fan-out is a tool, not a default** — the main session does the work and its own reasoning; a delegated result comes back as a summary, not verifiable ground truth. Delegate **only when** the work is large, independent, or repetitive enough that a self-contained hand-off (the sub-agent sees none of the conversation) costs less than the work — broad research, wide sweeps, audits — and run independent delegations in parallel. **Never delegate judgment by reflex**: a second opinion is for a high-stakes call or an explicit request. No dispatch mechanism ⇒ inline.
133
133
  - ⚠️ **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.
134
134
  - ⚠️ **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.
135
135
 
@@ -148,4 +148,4 @@ For real code (the CLI under `packages/`, hook scripts):
148
148
 
149
149
  ## Runtime Notes
150
150
 
151
- 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 pins the fast tier (sonnet-class); a user-requested judgment-heavy dispatch takes the strong tier (opus-class) — tier names go stale, re-check on model releases.
151
+ 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; a user-requested second opinion takes the strongest — pick by capability at dispatch, since model names go stale.
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "harness": "etna",
3
3
  "name": "etna",
4
- "version": "1.1.9",
4
+ "version": "1.1.10",
5
5
  "files": [
6
6
  ".prettierignore",
7
7
  ".prettierrc.json",
8
8
  ".vscode/settings.json"
9
9
  ],
10
- "digest": "dbc9b25ecc8f"
10
+ "digest": "3f4d8edde6db"
11
11
  }
@@ -66,3 +66,7 @@ After the rollup, **always produce a one-page candidate brief** (verdict + level
66
66
  - **You don't fabricate a score from thin evidence.** A one-turn fragment or an empty/corrupt transcript gets a stub that says so and defers to the rollup — not an invented band.
67
67
 
68
68
  Every output lands under `out_dir` and is plain markdown/YAML — reviewable, quotable, and reversible.
69
+
70
+ ## Fan-out
71
+
72
+ **Fan-out is a tool, not a default** — the main session does the work and its own reasoning; a delegated result comes back as a summary, not verifiable ground truth. Delegate **only when** the work is large, independent, or repetitive enough that a self-contained hand-off (the sub-agent sees none of the conversation) costs less than the work — broad research, wide sweeps, audits — and run independent delegations in parallel. **Never delegate judgment by reflex**: a second opinion is for a high-stakes call or an explicit request. No dispatch mechanism ⇒ inline.
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "harness": "hr",
3
3
  "name": "hr",
4
- "version": "0.1.6",
4
+ "version": "0.1.7",
5
5
  "files": [
6
6
  ".prettierignore",
7
7
  ".prettierrc.json",
8
8
  ".vscode/settings.json"
9
9
  ],
10
- "digest": "1d5cfc7eb67e"
10
+ "digest": "2fd45f5d45d3"
11
11
  }
@@ -59,3 +59,7 @@ The user is adding knowledge. You draft and place; they decide. Every write is t
59
59
  - The derived graph `meta/_derived/graph.json` is regenerated by `node .claude/scripts/kb-export.mjs` — never hand-edited, by you or anyone.
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
+
63
+ ## Fan-out
64
+
65
+ **Fan-out is a tool, not a default** — the main session does the work and its own reasoning; a delegated result comes back as a summary, not verifiable ground truth. Delegate **only when** the work is large, independent, or repetitive enough that a self-contained hand-off (the sub-agent sees none of the conversation) costs less than the work — broad research, wide sweeps, audits — and run independent delegations in parallel. **Never delegate judgment by reflex**: a second opinion is for a high-stakes call or an explicit request. No dispatch mechanism ⇒ inline.
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "harness": "kb-agi",
3
3
  "name": "kb-agi",
4
- "version": "1.0.1",
4
+ "version": "1.0.2",
5
5
  "files": [
6
6
  ".prettierignore",
7
7
  ".prettierrc.json",
8
8
  ".vscode/settings.json"
9
9
  ],
10
- "digest": "11b127dd4a61"
10
+ "digest": "2fa1ac5b576c"
11
11
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nurix/etna",
3
- "version": "0.19.18",
3
+ "version": "0.19.20",
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": {