@nurix/etna
v0.20.6
Published
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).
Maintainers
Readme
@nurix/etna
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.
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 for the comparison.
Usage
From the root of the project you want to bootstrap, pick a harness from the interactive menu:
npx --yes @nurix/etna…or install one directly by name:
npx --yes @nurix/etna --name=codeThe --yes flag skips npx's install confirmation, so the command runs unattended. On startup the CLI also self-updates: it checks the registry and, if the copy npx resolved is behind the latest published version, re-execs the latest before installing — so npx --yes @nurix/etna always runs the newest harness, even when npx has an older copy cached. The check is quick but synchronous; set ETNA_NO_SELFUPDATE=1 to skip it (CI, offline, or a pinned local build).
After this completes (the code harness shown — the component folders differ per harness, and one a harness ships nothing for is simply absent):
your-project/
├── CLAUDE.md ← harness policy (non-git repo: existing file → CLAUDE.md.bak.<ISO>)
├── AGENTS.md ← Codex: CLAUDE.md byte-for-byte + a generated Codex runtime adapter
├── .prettierrc.json ← markdown formatting (proseWrap: never)
├── .prettierignore
├── .vscode/settings.json ← editor settings (markdown formatter on save)
└── .claude/
├── skills/ ← boundary, brainstorm, design, documentation, test-plan, workflow-mapper
├── agents/ ← brainstorm, change-review, lld-mode, maintenance, performance-review, retro
├── rules/ ← database.md, express.md, frontend.md, general.md, nomenclature.md, pnpm.md, testing.md
├── hooks/ ← generate-ownership-index (SessionStart) + hooks.json
├── settings.json ← the hook is deep-merged in here (your existing keys preserved)
└── harness.json ← {harness, name, version, files, digest, owned} — the installed-harness sentinelAlongside the Claude tree, the installer projects the Codex artifacts so the repo also works under OpenAI Codex: AGENTS.md (above), .agents/skills/ (a mirror of .claude/skills/, Codex's skill-scan path), and .codex/agents/*.toml + .codex/hooks.json (its subagents and SessionStart hook) — each surface written only when the harness ships that component kind. Nothing is written outside the project. No marketplace registration, no enabledPlugins entry, no global cache dependency — Claude Code picks up the project-scoped agents/skills/rules on its next session start (and Codex reads AGENTS.md + .agents/ + .codex/), and the hooks wire in through .claude/settings.json.
Re-run npx --yes @nurix/etna --name=code anytime to refresh the harness content with what the latest published package ships. Existing same-named files are overwritten, and a component the harness used to own but no longer ships is pruned; files you've added that aren't part of the harness are left alone. In a git repo the previous CLAUDE.md and .claude/ are overwritten and refreshed in place (recover them with git checkout); outside a git repo CLAUDE.md is backed up to CLAUDE.md.bak.<ISO-timestamp> and the whole .claude/ tree is snapshotted to .claude.bak.<ISO-timestamp> first. Because the new harness.json carries the installed {version, digest}, a re-run whose major version is ahead of your repo's stamped harness-version is what the reconcile (below) detects as a structural upgrade.
After install: bootstrap the harness
Installing only drops the files — the harness isn't active for your repo until you baseline it. Open Claude Code in the project and drive the reconcile chain once (the installed CLAUDE.md carries the same steps under its ## Maintenance heading, for the agent):
- "baseline this repo" (or "reconcile the harness") — runs the
maintenanceagent, which auto-selects baseline mode from the missing/behindharness-version. It builds thedocs/tree to the harness shape, stampsdocs/structure.mdwith the installedharness-version, proposes modules (asmodule:labels, derived from your code's bounded contexts), then hands back. - If it hands back with a follow-up (typically the module proposal), re-invoke it to finish.
Then work normally. Boundaries aren't generated as files — the boundary skill diagnoses cross-cutting contracts from source at plan time. This brownfield path reads your actual code, not a blank slate, so it's safe to run on an existing project with real history.
One thing worth knowing on an existing repo:
- Your root
CLAUDE.mdis replaced with the harness policy file (recoverable from git, or fromCLAUDE.md.bak.<ISO>outside a git repo). If it held project-specific instructions, fold them back in after install — the harness file is the policy skeleton; your domain specifics sit alongside it.
Migrating from 0.1.x
0.1.x registered the harness as a Claude Code plugin via the nurixlabs/skills marketplace. 0.2.0 switches to direct file installation. When you re-run etna on a project that has a 0.1.x install, the CLI removes the stale enabledPlugins["<plugin>@nurixlabs"] entry from <project>/.claude/settings.json so Claude Code doesn't double-load the same content from the global plugin cache.
The nurixlabs marketplace entry in ~/.claude/settings.json is harmless to leave (it doesn't load anything by itself) — remove it manually if you want.
Available harnesses
Listed by npx --yes @nurix/etna (no args) using the bundled data/harness-index.json.
| Harness | Source in etna | What it ships |
| --- | --- | --- |
| code | harness/code/ | The canonical Nurix code-project harness — 6 governance/session agents, 7 workflow skills, 7 stack rules, the ownership-index SessionStart hook |
| discover | harness/discover/ | The product-discovery harness — 11 owned dimension-collector agents and 9 owned method rules, plus a tooling-recommendations.md at the project root. No skills, no hooks |
| discussion | harness/discussion/ | The deliberation-workspace harness — 2 owned agents, 2 owned rules, and the update-topics hook that keeps the topic index current. No skills |
| etna | harness/etna/ | The forge's own governance harness — a deliberate fork of code reframed for authoring artifacts: 5 agents, 4 skills, 4 rules, the ownership-index hook |
| hr | harness/hr/ | The hiring / AI-steering evaluation harness — the interview-eval and evaluator skills plus one batching rule. No agents, no hooks |
| kb-agi | harness/kb-agi/ | The self-improving knowledge-base harness — 3 owned vault agents (kb-init, kb-audit, kb-apply) and the owned kb-export.mjs script. No skills, no rules |
How it works
Each harness lives in a single folder in the etna repo — harness/<name>/:
readme.md— the manifest: identity (name, description, version, keywords) plus the sharedskills:/rules:/agents:lists it pulls in from the top-level catalogs. Its body becomes the harness's published README.CLAUDE.md— the policy: pure policy, no frontmatter, installed as a verbatim copy at the consumer repo's root.- Any owned
agents/,rules/,hooks/,scripts/— purpose-built components that belong to this harness alone.
Shared root config common to every harness (.prettierrc.json, .prettierignore, .vscode/settings.json) lives once, in harness/common/, instead of duplicated per harness.
Two kinds of membership:
- 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:
# harness/code/readme.md
---
name: code
skills:
[boundary, test-plan, brainstorm, documentation, workflow-mapper, design]
rules: [general, frontend, express, nomenclature, database, testing, pnpm]
agents:
[brainstorm, change-review, lld-mode, maintenance, performance-review, retro]
---- 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 theagents/catalog, local-first; a harness can still drop its own copy beside it to override one by name.
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>/, adds the harness/common/ root files and each bundled agent's *.codex.toml twin, and writes the harness.json marker (version, files list, kit digest); 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 and resolves the listed skills/rules/agents the same local-first way — but the two channels' footprints differ: the marketplace plugin carries no root policy, and its Codex surface is skills + hooks only (Codex custom agents ship through this CLI). The installer (bin/etna.js) reads from the bundle at install time; no GitHub fetch at runtime.
Building / contributing
data/ is generated. Don't edit by hand. To regenerate after editing the etna catalogs or manifests:
cd packages/cli
npm run build:dataprepack runs build:data automatically before npm publish, so the bundled data always matches the published package's commit.
Publishing
CI auto-publishes on push to dev when packages/cli/** or harness/** change — see .github/workflows/publish-etna-to-npm.yml. The publishConfig.access is public, so npx @nurix/etna installs and self-updates without any npm token. Publishing still requires auth: the NPM_PUBLISH_TOKEN GitHub Actions secret must be a granular access token with Bypass 2FA enabled — classic automation tokens are rejected by the npmjs.com 2FA policy on the nurix-tools account.
