@nurix/etna 0.19.16 → 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 CHANGED
@@ -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
- | Plugin name | Source in etna | What it ships |
67
+ | Harness | Source in etna | What it ships |
68
68
  | --- | --- | --- |
69
69
  | `code` | [`harness/code/`](../../harness/code/) | Governance + session agents, baseline workflow skills, the ownership-index hook (merged single-folder layout) |
70
- | `kb-agi` | [`plugins/kb-agi/`](../../plugins/kb-agi/) | Knowledge-vault scaffolding |
70
+ | `kb-agi` | [`harness/kb-agi/`](../../harness/kb-agi/) | Knowledge-vault scaffolding |
71
71
 
72
72
  ## How it works
73
73
 
74
- Each harness has two halves in the etna repo:
74
+ Each harness lives in a single folder in the etna repo — `harness/<name>/`:
75
75
 
76
- - `plugins/<name>/` — the **plugin** (what a Claude Code plugin natively bundles): `definition.md` (manifest — identity + `skills:`/`rules:`/`agents:` lists), `hooks/`, and any unlisted, harness-specific `agents/`.
77
- - `harness/<name>/` — the **policy**: `CLAUDE.md` (pure policy, no frontmatter — installed as a verbatim copy) plus `index.md`, whose `plugin:` key names the plugin this harness pairs with. All harness-folder frontmatter lives in `index.md` alone.
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 plugins. The manifest names the ones it pulls in:
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
- # plugins/code/definition.md
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 plugin (`plugins/<name>/{agents,hooks}/`). 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 plugin can still drop its own copy beside it to override one by name.
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 plugin-owned agents plus the plugin's `hooks/` 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 plugin folder, so both channels resolve identical membership — and both ship the plugin's hooks. The installer (`bin/etna.js`) reads from the bundle at install time; no GitHub fetch at runtime.
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
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "fingerprint": "12bdf20a3959",
2
+ "fingerprint": "a7791e9cf297",
3
3
  "harnesses": {
4
4
  "code": {
5
5
  "plugin": "code",
@@ -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 `plugins/*/` (composition) and `harness/*/` (harness definitions) | Edit here. Etna is the source of truth. |
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/**`, `plugins/**`, `packages/cli/**`, not `src/`.
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/**`, `plugins/**`, `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. 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 plugin `definition.md`'s `skills:` / `rules:` / `agents:` list ↔ the shared catalogs it resolves from (local-first);
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`.
@@ -7,5 +7,5 @@
7
7
  ".prettierrc.json",
8
8
  ".vscode/settings.json"
9
9
  ],
10
- "digest": "e4e80329bda9"
10
+ "digest": "b93279e6959d"
11
11
  }
@@ -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-plugins # + plugins/*/agents/*.md
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).
@@ -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 plugins/*/agents/*.md with --include-plugins) it runs
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-plugins # + plugins/*/agents/*.md
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 includePlugins = args.includes('--include-plugins');
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 plugin-owned agents on request.
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 (includePlugins) {
73
- const pluginsDir = join(repoRoot, 'plugins');
74
- if (existsSync(pluginsDir)) {
75
- for (const plugin of readdirSync(pluginsDir)) {
76
- const agentsDir = join(pluginsDir, plugin, 'agents');
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.16",
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": {