@nurix/etna 0.19.15 → 0.19.17
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/README.md +14 -11
- package/data/harness-index.json +2 -2
- package/data/harnesses/code/harness.json +3 -3
- package/data/harnesses/code/hooks/generate-ownership-index.mjs +1 -1
- package/data/harnesses/discover/CLAUDE.md +1 -1
- package/data/harnesses/discover/harness.json +3 -3
- package/data/harnesses/discover/rules/discovery.md +1 -1
- package/data/harnesses/discover/rules/evaluation.md +1 -1
- package/data/harnesses/discover/rules/tradecraft.md +1 -1
- package/data/harnesses/discussion/harness.json +2 -2
- package/data/harnesses/etna/CLAUDE.md +4 -4
- package/data/harnesses/etna/harness.json +3 -3
- package/data/harnesses/hr/harness.json +2 -2
- package/data/harnesses/kb-agi/harness.json +2 -2
- package/lib/codex/README.md +1 -1
- package/lib/codex/gen-agents.mjs +10 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
CLI to bootstrap a project with a Nurix harness. Copies the harness's `CLAUDE.md`, skills, agents, rules, and hooks (plus scripts, if the harness ships any) into the project so they live with the code — version-controllable, editable per project, and visible without leaving the repo.
|
|
4
4
|
|
|
5
|
-
A second install path also exists and is fully supported: `/plugin install <plugin>@nurixlabs` from inside Claude Code, which installs the harness as a plugin from the `nurixlabs/skills` marketplace. The two paths are first-class equals — pick the one that matches how you want to manage the harness. See [`docs/architecture/harness/
|
|
5
|
+
A second install path also exists and is fully supported: `/plugin install <plugin>@nurixlabs` from inside Claude Code, which installs the harness as a plugin from the `nurixlabs/skills` marketplace. The two paths are first-class equals — pick the one that matches how you want to manage the harness. See [`docs/architecture/harness/Readme.md`](../../docs/architecture/harness/Readme.md#the-install-model) for the comparison.
|
|
6
6
|
|
|
7
7
|
## Usage
|
|
8
8
|
|
|
@@ -64,24 +64,27 @@ The `nurixlabs` marketplace entry in `~/.claude/settings.json` is harmless to le
|
|
|
64
64
|
|
|
65
65
|
Listed by `npx --yes @nurix/etna` (no args) using the bundled `data/harness-index.json`.
|
|
66
66
|
|
|
67
|
-
|
|
|
67
|
+
| Harness | Source in etna | What it ships |
|
|
68
68
|
| --- | --- | --- |
|
|
69
|
-
| `code` | [`
|
|
70
|
-
| `kb-agi` | [`
|
|
69
|
+
| `code` | [`harness/code/`](../../harness/code/) | Governance + session agents, baseline workflow skills, the ownership-index hook (merged single-folder layout) |
|
|
70
|
+
| `kb-agi` | [`harness/kb-agi/`](../../harness/kb-agi/) | Knowledge-vault scaffolding |
|
|
71
71
|
|
|
72
72
|
## How it works
|
|
73
73
|
|
|
74
|
-
Each harness
|
|
74
|
+
Each harness lives in a single folder in the etna repo — `harness/<name>/`:
|
|
75
75
|
|
|
76
|
-
- `
|
|
77
|
-
- `
|
|
76
|
+
- `readme.md` — the **manifest**: identity (name, description, version, keywords) plus the shared `skills:`/`rules:`/`agents:` lists it pulls in from the top-level catalogs. Its body becomes the harness's published README.
|
|
77
|
+
- `CLAUDE.md` — the **policy**: pure policy, no frontmatter, installed as a verbatim copy at the consumer repo's root.
|
|
78
|
+
- Any owned `agents/`, `rules/`, `hooks/`, `scripts/` — purpose-built components that belong to this harness alone.
|
|
79
|
+
|
|
80
|
+
Shared root config common to every harness (`.prettierrc.json`, `.prettierignore`, `.vscode/settings.json`) lives once, in `harness/common/`, instead of duplicated per harness.
|
|
78
81
|
|
|
79
82
|
Two kinds of membership:
|
|
80
83
|
|
|
81
|
-
- **Shared, listed** — skills, rules, and agents live in the flat top-level `skills/`/`rules/`/`agents/` catalogs, reusable across
|
|
84
|
+
- **Shared, listed** — skills, rules, and agents live in the flat top-level `skills/`/`rules/`/`agents/` catalogs, reusable across harnesses. The manifest names the ones it pulls in:
|
|
82
85
|
|
|
83
86
|
```yaml
|
|
84
|
-
#
|
|
87
|
+
# harness/code/readme.md
|
|
85
88
|
---
|
|
86
89
|
name: code
|
|
87
90
|
skills: [boundary, brainstorm, documentation, workflow-mapper, design]
|
|
@@ -90,9 +93,9 @@ agents: [brainstorm, change-review, lld-mode, maintenance, performance-review]
|
|
|
90
93
|
---
|
|
91
94
|
```
|
|
92
95
|
|
|
93
|
-
- **Owned, by location** — hooks (and any unlisted, harness-specific agents) live inside the
|
|
96
|
+
- **Owned, by location** — hooks, scripts (and any unlisted, harness-specific agents) live inside the harness folder (`harness/<name>/{agents,hooks,scripts}/`). No list — membership is presence in the folder, exactly how a Claude Code plugin ships them. Shared governance agents are listed instead (above) and resolved from the `agents/` catalog, local-first; a harness can still drop its own copy beside it to override one by name.
|
|
94
97
|
|
|
95
|
-
`scripts/build-data.js` (run by `prepack`) resolves the listed skills/rules/agents from the catalogs (local-first), copies any unlisted
|
|
98
|
+
`scripts/build-data.js` (run by `prepack`) resolves the listed skills/rules/agents from the catalogs (local-first), copies any unlisted harness-owned agents plus the harness's `hooks/` and `scripts/` wholesale into `data/harnesses/<folder>/`; a listed skill/rule/agent that doesn't exist is a hard error. The marketplace channel (`.github/scripts/publish.mjs`) reads the same harness folder, so both channels resolve identical membership — and both ship the harness's hooks and scripts. The installer (`bin/etna.js`) reads from the bundle at install time; no GitHub fetch at runtime.
|
|
96
99
|
|
|
97
100
|
## Building / contributing
|
|
98
101
|
|
package/data/harness-index.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"fingerprint": "
|
|
2
|
+
"fingerprint": "a7791e9cf297",
|
|
3
3
|
"harnesses": {
|
|
4
4
|
"code": {
|
|
5
5
|
"plugin": "code",
|
|
6
|
-
"description": "Nurix
|
|
6
|
+
"description": "the foundation every Nurix project starts with"
|
|
7
7
|
},
|
|
8
8
|
"discover": {
|
|
9
9
|
"plugin": "discover",
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"harness": "code",
|
|
3
3
|
"name": "code",
|
|
4
|
-
"version": "3.1.
|
|
4
|
+
"version": "3.1.12",
|
|
5
5
|
"files": [
|
|
6
|
-
".prettierrc.json",
|
|
7
6
|
".prettierignore",
|
|
7
|
+
".prettierrc.json",
|
|
8
8
|
".vscode/settings.json"
|
|
9
9
|
],
|
|
10
|
-
"digest": "
|
|
10
|
+
"digest": "cc025f7950c3"
|
|
11
11
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// harness/code/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.
|
|
@@ -40,7 +40,7 @@ Agent name = dimension name. ⚠ = gated (needs user authorization before dispat
|
|
|
40
40
|
|
|
41
41
|
Cheap, read-only. Scope the target, grade its access, detect which dimensions it exposes.
|
|
42
42
|
|
|
43
|
-
**0. Resolve the corpus root** — the folder this run writes into. The harness chooses it _intelligently_ rather than hardcoding one: default `research/` at the repo root, but if the project already holds a discovery corpus (any folder with a prior run's `*/00-scope-verdict.md`) under another name (`
|
|
43
|
+
**0. Resolve the corpus root** — the folder this run writes into. The harness chooses it _intelligently_ rather than hardcoding one: default `research/` at the repo root, but if the project already holds a discovery corpus (any folder with a prior run's `*/00-scope-verdict.md`) under another name (`discovery/`, `analysis/`, …) **reuse it**, and honor a folder the user names. **Confirm the chosen root in one line** before writing. Every `research/<target>/` path in this harness is the _default form_ — read it as `<corpus>/<target>/`, relative to the resolved root.
|
|
44
44
|
|
|
45
45
|
1. **Scope-feasibility gate** — run the `.claude/rules/discovery.md` Part A (scope gate) algorithm: resolve identity → ambiguity → ethics → suite-size → primitive → reachability. If the verdict isn't `accept`, **halt** (present the narrowing/redirect prompt, or refuse). Write `research/<target>/00-scope-verdict.md`.
|
|
46
46
|
2. **Grade the access vector** (the four axes, with evidence) per `discovery` (Part B).
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"harness": "discover",
|
|
3
3
|
"name": "discover",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.10",
|
|
5
5
|
"files": [
|
|
6
|
-
".prettierrc.json",
|
|
7
6
|
".prettierignore",
|
|
7
|
+
".prettierrc.json",
|
|
8
8
|
".vscode/settings.json"
|
|
9
9
|
],
|
|
10
|
-
"digest": "
|
|
10
|
+
"digest": "a672787b9962"
|
|
11
11
|
}
|
|
@@ -14,7 +14,7 @@ The reference knowledge for **Discovery** (`discover` harness, Mode 1). It carri
|
|
|
14
14
|
|
|
15
15
|
Before Part A, decide **where this run writes** — the harness picks intelligently, it does not hardcode `research/`:
|
|
16
16
|
|
|
17
|
-
1. **Reuse an existing discovery corpus** if the project has one — search for any folder containing a prior run's `*/00-scope-verdict.md` (commonly `research/`, but also `
|
|
17
|
+
1. **Reuse an existing discovery corpus** if the project has one — search for any folder containing a prior run's `*/00-scope-verdict.md` (commonly `research/`, but also `discovery/`, `analysis/`, or a folder the user names).
|
|
18
18
|
2. If several exist, prefer the one the user points at, else the most recently written.
|
|
19
19
|
3. If none exists and the user hasn't named one, default to `research/` at the repo root.
|
|
20
20
|
4. **Confirm the chosen root in one line** before writing `00-scope-verdict.md`.
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
|
|
108
108
|
## Pricing & packaging (plans, what gates what, unit economics — website pricing + platform/limits)
|
|
109
109
|
|
|
110
|
-
## Differentiation (claimed moat vs the
|
|
110
|
+
## Differentiation (claimed moat vs the discovery's read of the real moat — often infra/data)
|
|
111
111
|
|
|
112
112
|
## Alternatives & comparison (named competitors + how it differs)
|
|
113
113
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Discover Harness — Session & Wire Tradecraft (keyboard-level reference)
|
|
2
2
|
|
|
3
|
-
The executable field layer the browser-driving dimensions (`session`, `wire-capture`) reach for at the keyboard. Everything here is **runnable verbatim** — taps, scrubbers, escape snippets — not prose to re-derive. It is the distilled tradecraft from real
|
|
3
|
+
The executable field layer the browser-driving dimensions (`session`, `wire-capture`) reach for at the keyboard. Everything here is **runnable verbatim** — taps, scrubbers, escape snippets — not prose to re-derive. It is the distilled tradecraft from real discovery runs; the `§1.x`/`§2.x` anchors are the origin tags from those runs.
|
|
4
4
|
|
|
5
5
|
**How the dimensions use this file:**
|
|
6
6
|
|
|
@@ -27,7 +27,7 @@ etna authors the components it also runs and ships, so **three copies of every c
|
|
|
27
27
|
|
|
28
28
|
| Copy | Where | Role |
|
|
29
29
|
| --- | --- | --- |
|
|
30
|
-
| **Source** (canonical) | the shared catalogs — `skills/`, `agents/`, `rules/`, plus `
|
|
30
|
+
| **Source** (canonical) | the shared catalogs — `skills/`, `agents/`, `rules/`, plus `harness/*/` (each harness — its `readme.md` manifest, `CLAUDE.md` policy, and owned trees in one folder) | Edit here. Etna is the source of truth. |
|
|
31
31
|
| **Dogfood** | `.claude/skills/`, `.claude/agents/`, `.claude/rules/`, `.claude/hooks/` (git-tracked) | The subset the `etna` harness installs on itself — the copy this repo actually runs this session. |
|
|
32
32
|
| **Shipped bundle** | `packages/cli/data/harnesses/*/` (git-tracked build artifact, regenerated by `packages/cli/scripts/build-data.js`) | Generated — never hand-edit. |
|
|
33
33
|
|
|
@@ -38,7 +38,7 @@ etna authors the components it also runs and ships, so **three copies of every c
|
|
|
38
38
|
|
|
39
39
|
## Workflows
|
|
40
40
|
|
|
41
|
-
Three peer modes plus a Completion step — enter wherever the user's thinking already is. Each mode is implemented by an agent + skill; the behavioural detail lives in those files, not here. "Code" below means **authoring artifacts** — a feature LLD owns `skills/**`, `
|
|
41
|
+
Three peer modes plus a Completion step — enter wherever the user's thinking already is. Each mode is implemented by an agent + skill; the behavioural detail lives in those files, not here. "Code" below means **authoring artifacts** — a feature LLD owns `skills/**`, `harness/**`, `packages/cli/**`, not `src/`.
|
|
42
42
|
|
|
43
43
|
| Mode | Enter when | Implemented by | Exits to |
|
|
44
44
|
| --- | --- | --- | --- |
|
|
@@ -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/**`, `
|
|
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.
|
|
68
68
|
|
|
69
69
|
Before modifying a component in an unfamiliar area:
|
|
70
70
|
|
|
@@ -77,7 +77,7 @@ The `lld-mode` agent checks for ownership conflicts during LLD research — feat
|
|
|
77
77
|
|
|
78
78
|
etna has no db schema, wire envelope, or auth of its own — the `boundary` skill's stack mechanisms describe the contracts of the **rules etna ships**, checked in the consumer's repo, not here. etna's **own** live contracts are authoring and distribution ones, each with no static link between the two sides:
|
|
79
79
|
|
|
80
|
-
- a
|
|
80
|
+
- a harness `readme.md` manifest's `skills:` / `rules:` / `agents:` list ↔ the shared catalogs it resolves from (local-first);
|
|
81
81
|
- a component's **source ↔ `.claude/` dogfood ↔ shipped bundle** (three-way parity, per Authoring & Distribution);
|
|
82
82
|
- a hook script ↔ its `hooks.json` registration;
|
|
83
83
|
- the CLI's managed-block edits ↔ a consumer's `settings.json` / `.env`.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"harness": "etna",
|
|
3
3
|
"name": "etna",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.9",
|
|
5
5
|
"files": [
|
|
6
|
-
".prettierrc.json",
|
|
7
6
|
".prettierignore",
|
|
7
|
+
".prettierrc.json",
|
|
8
8
|
".vscode/settings.json"
|
|
9
9
|
],
|
|
10
|
-
"digest": "
|
|
10
|
+
"digest": "b93279e6959d"
|
|
11
11
|
}
|
package/lib/codex/README.md
CHANGED
|
@@ -25,7 +25,7 @@ Owning doc: [`docs/features/codex-support.md`](../../../../docs/features/codex-s
|
|
|
25
25
|
```bash
|
|
26
26
|
node packages/cli/lib/codex/gen-agents.mjs # shared catalog (agents/*.md), stale/missing only
|
|
27
27
|
node packages/cli/lib/codex/gen-agents.mjs --force # regenerate all shared agents
|
|
28
|
-
node packages/cli/lib/codex/gen-agents.mjs --include-
|
|
28
|
+
node packages/cli/lib/codex/gen-agents.mjs --include-harness # + harness/*/agents/*.md
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
`gen-agents.mjs` runs `codex exec` per agent and writes a committed `agents/<name>.codex.toml` sibling. It runs **only on a laptop with `codex` installed + authenticated — never in CI**. `build-data.js` and `publish.mjs` then ship those committed TOML; the installer copies them, so **consumers need no Codex CLI**. Regenerate an agent's TOML in the same change that edits its `.md` (source↔generated parity).
|
package/lib/codex/gen-agents.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// packages/cli/lib/codex/gen-agents.mjs
|
|
2
2
|
// AUTHORING-TIME generator — runs ON A LAPTOP with the Codex CLI installed and
|
|
3
3
|
// authenticated, NEVER in CI. For each Claude subagent (agents/<name>.md in the
|
|
4
|
-
// shared catalog, plus
|
|
4
|
+
// shared catalog, plus harness/*/agents/*.md with --include-harness) it runs
|
|
5
5
|
// `codex exec` to translate the markdown into an OpenAI Codex subagent TOML and
|
|
6
6
|
// writes a committed sibling agents/<name>.codex.toml. The shippers (build-data.js,
|
|
7
7
|
// publish.mjs) then carry those committed files; the installer copies them into a
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// Usage:
|
|
11
11
|
// node packages/cli/lib/codex/gen-agents.mjs # shared catalog, only stale/missing
|
|
12
12
|
// node packages/cli/lib/codex/gen-agents.mjs --force # regenerate all shared agents
|
|
13
|
-
// node packages/cli/lib/codex/gen-agents.mjs --include-
|
|
13
|
+
// node packages/cli/lib/codex/gen-agents.mjs --include-harness # + harness/*/agents/*.md
|
|
14
14
|
|
|
15
15
|
import {
|
|
16
16
|
existsSync,
|
|
@@ -45,7 +45,7 @@ const CONVERSION_PROMPT = [
|
|
|
45
45
|
|
|
46
46
|
const args = process.argv.slice(2);
|
|
47
47
|
const force = args.includes('--force');
|
|
48
|
-
const
|
|
48
|
+
const includeHarness = args.includes('--include-harness');
|
|
49
49
|
|
|
50
50
|
function die(msg) {
|
|
51
51
|
console.error(`gen-codex-agents: ${msg}`);
|
|
@@ -60,7 +60,7 @@ function assertCodexReady() {
|
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
// Every agents/<name>.md to convert: the shared catalog, plus
|
|
63
|
+
// Every agents/<name>.md to convert: the shared catalog, plus harness-owned agents on request.
|
|
64
64
|
function collectAgentFiles() {
|
|
65
65
|
const files = [];
|
|
66
66
|
const shared = join(repoRoot, 'agents');
|
|
@@ -69,11 +69,12 @@ function collectAgentFiles() {
|
|
|
69
69
|
if (f.endsWith('.md')) files.push(join(shared, f));
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
|
-
if (
|
|
73
|
-
const
|
|
74
|
-
if (existsSync(
|
|
75
|
-
for (const
|
|
76
|
-
|
|
72
|
+
if (includeHarness) {
|
|
73
|
+
const harnessDir = join(repoRoot, 'harness');
|
|
74
|
+
if (existsSync(harnessDir)) {
|
|
75
|
+
for (const harness of readdirSync(harnessDir)) {
|
|
76
|
+
if (harness === 'common') continue; // not a harness — the shared root-files folder
|
|
77
|
+
const agentsDir = join(harnessDir, harness, 'agents');
|
|
77
78
|
if (!existsSync(agentsDir)) continue;
|
|
78
79
|
for (const f of readdirSync(agentsDir)) {
|
|
79
80
|
if (f.endsWith('.md')) files.push(join(agentsDir, f));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nurix/etna",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.17",
|
|
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": {
|