@nurix/etna 0.19.56 → 0.19.57
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/agents/bookkeeper.md +1 -1
- package/data/harnesses/apollo/agents/change-review.md +1 -1
- package/data/harnesses/apollo/agents/lld-mode.md +1 -1
- package/data/harnesses/apollo/agents/maintenance.md +1 -1
- package/data/harnesses/apollo/agents/performance-review.md +1 -1
- package/data/harnesses/apollo/agents/retro.md +1 -1
- package/data/harnesses/apollo/harness.json +2 -2
- package/data/harnesses/apollo/hooks/compliance.mjs +42 -0
- package/data/harnesses/apollo/rules/database.md +2 -2
- package/data/harnesses/apollo/skills/schema-design/SKILL.md +0 -30
- package/data/harnesses/code/agents/bookkeeper.md +1 -1
- package/data/harnesses/code/agents/change-review.md +1 -1
- package/data/harnesses/code/agents/lld-mode.md +1 -1
- package/data/harnesses/code/agents/maintenance.md +1 -1
- package/data/harnesses/code/agents/performance-review.md +1 -1
- package/data/harnesses/code/agents/retro.md +1 -1
- package/data/harnesses/code/harness.json +2 -2
- package/data/harnesses/code/hooks/compliance.mjs +42 -0
- package/data/harnesses/code/rules/database.md +2 -2
- package/data/harnesses/code/skills/schema-design/SKILL.md +0 -30
- package/data/harnesses/delivery/agents/lld-mode.md +1 -1
- package/data/harnesses/delivery/agents/maintenance.md +1 -1
- package/data/harnesses/delivery/agents/retro.md +1 -1
- package/data/harnesses/delivery/harness.json +2 -2
- package/data/harnesses/etna/agents/change-review.md +1 -1
- package/data/harnesses/etna/agents/lld-mode.md +1 -1
- package/data/harnesses/etna/agents/maintenance.md +1 -1
- package/data/harnesses/etna/agents/performance-review.md +1 -1
- package/data/harnesses/etna/agents/retro.md +1 -1
- package/data/harnesses/etna/harness.json +2 -2
- package/package.json +2 -2
package/data/harness-index.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: bookkeeper
|
|
3
3
|
description: Drains docs/operations/bookkeeping.md — performs mechanical fixes (owns: globs, header comments, doc-lint findings, index rows), expands note: rows into doc edits, marks rows resolved. Dispatched by the main session at turn end or commit time; never self-triggers. Triggers on "drain the bookkeeping queue", "dispatch the bookkeeper", "/bookkeeper".
|
|
4
4
|
tools: Read, Glob, Grep, Edit, Write, Bash, Skill
|
|
5
|
-
model:
|
|
5
|
+
model: sonnet
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Bookkeeper Agent
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: change-review
|
|
3
3
|
description: Velocity + change-risk analysis. First classifies recent commits into a pipe-delimited velocity/severity CSV by dispatching parallel low-cost subagents (module, feature, impact, severity, churn), then derives a commit heatmap, risk zones (high churn in contract-heavy code), stabilization signals, and team/bus-factor distribution. Self-contained — produces its own CSV, no separate git-history step. Use when planning where to invest in review focus or rules.
|
|
4
4
|
tools: Bash, Read, Write, Glob, Grep, Task
|
|
5
|
-
model:
|
|
5
|
+
model: sonnet
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Change-Review Agent
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: lld-mode
|
|
3
3
|
description: LLD researcher for Feature and Product workflows. Use to explore the codebase and gather the context needed for writing a feature LLD (low-level design — the feature doc in docs/features/). Returns research findings — does not write files.
|
|
4
4
|
tools: Read, Glob, Grep, WebSearch, WebFetch
|
|
5
|
-
model:
|
|
5
|
+
model: opus
|
|
6
6
|
skills:
|
|
7
7
|
- documentation
|
|
8
8
|
---
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: maintenance
|
|
3
3
|
description: The single docs steward. Default behavior is the docs-vs-code coherence audit — detects and fixes docs drifting from code (stale docs, broken ownership, unowned source paths, architecture/backlog drift). An additive **baseline mode** layers structural reconcile on top: when the repo's `harness-version` marker is missing or behind, it converges `docs/` to the installed harness shape (scaffold the standard tree, fold dissolved-shape artifacts forward, stamp the version, propose modules) before running the audit. Mode is auto-selected from the marker. Run weekly, after major changes, or to baseline/upgrade a repo. Cross-cutting contract analysis is the `boundary` skill (`check` for plans, `scan` for diffs) — it derives contracts dynamically from source; there are no persisted boundary docs to audit. Triggers on "run maintenance", "docs health", "baseline this repo", "reconcile the harness", "upgrade the harness", "is this repo on the current harness", "/maintenance".
|
|
4
4
|
tools: Read, Glob, Grep, Edit, Write, Bash
|
|
5
|
-
model:
|
|
5
|
+
model: opus
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Maintenance Agent
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: performance-review
|
|
3
3
|
description: Combined dependency + code health audit. Part A audits the dependency supply chain — security CVEs, outdated packages, license compliance, abandoned packages, unwanted transitive dependencies, install size. Part B audits code-level health — bundle size, tree-shaking issues, performance anti-patterns, code-quality flags. Run weekly or before releases. Merges the former `dep-health` and `review` agents so the package tree and the code that uses it are audited together.
|
|
4
4
|
tools: Read, Glob, Grep, Bash
|
|
5
|
-
model:
|
|
5
|
+
model: opus
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Performance-Review Agent
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: retro
|
|
3
3
|
description: Session-distillation agent for the changelog. Reads the per-unit-of-work entries under `docs/history/changelog/` accumulated since its last run and distills the refinement delta — what user-driven iteration added that the one-shot build lacked — into a typed punch list of doc-content gaps, doc-structure moves (missing doc / mothership split / merge), skill-evolution findings backed by survived-vs-overridden counts, unpinned discoveries needing an enforced artifact (test, token, guardrail, schema), and cross-project harness rules. Proposes only — actionable items land in the backlog, never applied directly. Run on demand: before a brainstorm or LLD session, before starting a new project, or after a refinement arc. Triggers on "run retro", "distill the changelog", "refinement retro", "/retro".
|
|
4
4
|
tools: Read, Glob, Grep, Bash, Write, Edit
|
|
5
|
-
model:
|
|
5
|
+
model: opus
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Retro — changelog distillation
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"harness": "apollo",
|
|
3
3
|
"name": "apollo",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.6",
|
|
5
5
|
"files": [
|
|
6
6
|
".prettierignore",
|
|
7
7
|
".prettierrc.json",
|
|
@@ -15,5 +15,5 @@
|
|
|
15
15
|
"docs/memory/main.md",
|
|
16
16
|
".mcp.json"
|
|
17
17
|
],
|
|
18
|
-
"digest": "
|
|
18
|
+
"digest": "8e61d4b9ddcf"
|
|
19
19
|
}
|
|
@@ -325,6 +325,43 @@ function planHasChangelogEntry(projectDir, planRel) {
|
|
|
325
325
|
return names.some((name) => name.endsWith(".md") && readSafe(path.join(dir, name)).includes(slug));
|
|
326
326
|
}
|
|
327
327
|
|
|
328
|
+
// Approximate the context the next turn will re-read, from the transcript's last recorded usage.
|
|
329
|
+
// Best-effort: an absent or unparseable transcript reports nothing.
|
|
330
|
+
function sessionContextTokens(transcriptPath) {
|
|
331
|
+
const text = readSafe(transcriptPath || "");
|
|
332
|
+
if (!text) return 0;
|
|
333
|
+
const lines = text.slice(-400000).split("\n");
|
|
334
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
335
|
+
if (!lines[i].includes('"usage"')) continue;
|
|
336
|
+
try {
|
|
337
|
+
const u = JSON.parse(lines[i]).message.usage;
|
|
338
|
+
return (
|
|
339
|
+
(u.input_tokens || 0) + (u.cache_read_input_tokens || 0) + (u.cache_creation_input_tokens || 0)
|
|
340
|
+
);
|
|
341
|
+
} catch (e) {
|
|
342
|
+
// the slice cut this line in half — keep scanning upward
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
return 0;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Context re-reads in full on every turn, so its size IS the standing per-turn floor — the one
|
|
349
|
+
// number that argues for ending a session rather than carrying it into unrelated work. The agent
|
|
350
|
+
// cannot act on this (it can neither end a session nor start one), so it is addressed to the user
|
|
351
|
+
// as a systemMessage and never blocks. Kept out of the model's context deliberately: a running
|
|
352
|
+
// token count in-context produces context anxiety, not shorter sessions.
|
|
353
|
+
const CONTEXT_ADVISORY_TOKENS = 250000;
|
|
354
|
+
|
|
355
|
+
function sessionSizeNote(payload) {
|
|
356
|
+
const tokens = sessionContextTokens(payload.transcript_path);
|
|
357
|
+
if (tokens < CONTEXT_ADVISORY_TOKENS) return null;
|
|
358
|
+
return (
|
|
359
|
+
`Session context is roughly ${Math.round(tokens / 1000)}K tokens, and every turn re-reads all of it — ` +
|
|
360
|
+
"that is the per-turn floor before anything new is produced. A fresh session starts near zero; " +
|
|
361
|
+
"worth ending this one if the next task is unrelated."
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
|
|
328
365
|
function stopGate(projectDir, payload) {
|
|
329
366
|
if (payload.stop_hook_active) return null; // the runtime's infinite-loop guard — never re-block
|
|
330
367
|
|
|
@@ -381,6 +418,11 @@ function main() {
|
|
|
381
418
|
}
|
|
382
419
|
} else if (event === "Stop") {
|
|
383
420
|
out = stopGate(projectDir, payload);
|
|
421
|
+
// Advisory rides alongside a block rather than replacing it — both are true at once.
|
|
422
|
+
if (!payload.stop_hook_active) {
|
|
423
|
+
const note = sessionSizeNote(payload);
|
|
424
|
+
if (note) out = { ...(out || {}), systemMessage: note };
|
|
425
|
+
}
|
|
384
426
|
}
|
|
385
427
|
|
|
386
428
|
if (out) process.stdout.write(JSON.stringify(out));
|
|
@@ -7,7 +7,7 @@ Naming and the fixed column vocabulary for relational schemas in **every** Nurix
|
|
|
7
7
|
Three column roles are fixed across every table and every project:
|
|
8
8
|
|
|
9
9
|
- **`id`** — the primary key, **always a UUID** (`TEXT PRIMARY KEY` on D1, `uuid` on Postgres), never a synthetic or natural key (❌ `type_page_button`, `human:default`). Runtime rows mint a UUIDv7; seed rows derive a deterministic UUIDv5 of the natural key so re-seeds stay stable. **Never** mix synthetic and UUID ids in one table. The single exemption is a log whose **composite key is its ordering** (`PRIMARY KEY (<entity>_id, sequence)`), declared at the table that uses it — everything else, logs included, takes a UUIDv7.
|
|
10
|
-
- **`slug`** — the **stable key rows in another scope reference**: `UNIQUE`, lowercase `snake_case`. A slug means the same thing in every scope, so a slug reference survives a copy with no remapping
|
|
10
|
+
- **`slug`** — the **stable key rows in another scope reference**: `UNIQUE`, lowercase `snake_case`. A slug means the same thing in every scope, so a slug reference survives a copy with no remapping — copying between scopes is the `schema-design` skill. ❌ Never rename this role `handle`, `key`, `code`, or `name` in another project.
|
|
11
11
|
- **`label`** — the **human display name** — ❌ never `name`, `title`, or `display_name`.
|
|
12
12
|
|
|
13
13
|
Reference columns name what they point at: `<entity>_id` for a UUID-PK reference (`user_id`, `app_id`), `<entity>_slug` for a slug reference (`source_slug`).
|
|
@@ -21,7 +21,7 @@ Reference columns name what they point at: `<entity>_id` for a UUID-PK reference
|
|
|
21
21
|
## Naming
|
|
22
22
|
|
|
23
23
|
- **Tables** — `snake_case`, plural noun for what they hold (`users`, `apps`, `devices`).
|
|
24
|
-
- **Junction (M:N) tables** — `<entityA>_<entityB>_map`, **always**, even when the join carries its own columns; singular stems, owning/anchor entity first (`app_user_map`, `app_device_map`). ❌ Never a "nice" noun (`members`, `installs`, `memberships`, `enrolments`) — the name must read as a join, and a reviewer should know both sides from it. The `_map` suffix is reserved for genuine M:N
|
|
24
|
+
- **Junction (M:N) tables** — `<entityA>_<entityB>_map`, **always**, even when the join carries its own columns; singular stems, owning/anchor entity first (`app_user_map`, `app_device_map`). ❌ Never a "nice" noun (`members`, `installs`, `memberships`, `enrolments`) — the name must read as a join, and a reviewer should know both sides from it. The `_map` suffix is reserved for genuine M:N — the cardinality test that decides junction vs. column is the `schema-design` skill.
|
|
25
25
|
- **Columns** — `snake_case`; booleans `is_*` / `has_*`; timestamps `created_at` / `updated_at`; foreign keys `<entity>_id`.
|
|
26
26
|
- **Indexes** — `<table>_<col(s)>_idx`; unique `<table>_<col(s)>_unique`; a junction's composite unique reads `<table>_<colA>_<colB>_unique` (`app_user_map_app_user_unique`).
|
|
27
27
|
- **Drizzle mirror** — the exported object is the camelCase table name (`app_user_map` → `appUserMap`); column props are the camelCase of the column (`created_at` → `createdAt`). The `sqliteTable("…")` string and every index name must match the DDL (`init.sql`) exactly — the schema-parity boundary.
|
|
@@ -85,22 +85,6 @@ One entity that exists at several scopes is **one table with a nullable scope co
|
|
|
85
85
|
- **Store the source's version at copy time** — `version` + `source_version` make "is an upgrade available" a comparison of two stored values, not a content diff.
|
|
86
86
|
- **A copy is a row, never a live read.** Nothing at the child scope reads the parent's row at runtime; propagation happens only through an explicit re-copy, so a local edit is never silently overwritten.
|
|
87
87
|
|
|
88
|
-
## Keys & the shared vocabulary
|
|
89
|
-
|
|
90
|
-
Three column roles are fixed across every table and every project:
|
|
91
|
-
|
|
92
|
-
- **`id`** — the primary key, **always a UUID** (`TEXT PRIMARY KEY` on D1, `uuid` on Postgres), never a synthetic or natural key (❌ `type_page_button`, `human:default`). Runtime rows mint a UUIDv7; seed rows derive a deterministic UUIDv5 of the natural key so re-seeds stay stable. **Never** mix synthetic and UUID ids in one table. The single exemption is a log whose **composite key is its ordering** (`PRIMARY KEY (<entity>_id, sequence)`), declared at the table that uses it — everything else, logs included, takes a UUIDv7.
|
|
93
|
-
- **`slug`** — the **stable key rows in another scope reference**: `UNIQUE`, lowercase `snake_case`. A slug means the same thing in every scope, so a slug reference survives a copy with no remapping (§ Copying rows between scopes). ❌ Never rename this role `handle`, `key`, `code`, or `name` in another project.
|
|
94
|
-
- **`label`** — the **human display name** — ❌ never `name`, `title`, or `display_name`.
|
|
95
|
-
|
|
96
|
-
Reference columns name what they point at: `<entity>_id` for a UUID-PK reference (`user_id`, `app_id`), `<entity>_slug` for a slug reference (`source_slug`).
|
|
97
|
-
|
|
98
|
-
- **Enforced, same scope** (the referenced row must exist) → a real `FOREIGN KEY (<x>_id) REFERENCES <table>(id)`.
|
|
99
|
-
- **Cross-scope** (the reference must survive being copied) → `<x>_slug` as a plain column, **no** FK — an FK would bind the row to one scope's copy of the target, which is the remapping the slug exists to avoid.
|
|
100
|
-
- **Drift-tolerant** (a controlled-vocabulary value that may fall off-list) → a plain value column, **no** FK, paired with an `is_*` boolean recording whether the value is in the canonical set.
|
|
101
|
-
|
|
102
|
-
**Every inbound FK to a hub table declares a deliberate `ON DELETE`.** A hub (`users`, `devices`, anything several modules point at) collects edges from teams that never meet, and a single `NO ACTION` among them turns deleting the parent into a constraint error naming neither table. Decide per edge: the child dies with the row (`CASCADE`) or survives it (`SET NULL`, which needs a nullable column) — `NO ACTION` on a hub is a deferred outage, not a default.
|
|
103
|
-
|
|
104
88
|
## A junction spells many-to-many — nothing else
|
|
105
89
|
|
|
106
90
|
**A `_map` table is the schema's notation for M:N. Using it for 1:M is a category error** — the junction's own uniqueness admits many parents per child, so the "one parent" rule stops being enforced the moment it is written this way. Cardinality decides between the only two shapes:
|
|
@@ -131,14 +115,6 @@ Reference columns name what they point at: `<entity>_id` for a UUID-PK reference
|
|
|
131
115
|
- **`CASCADE` from the append-only side's own parent is still fine** — a cascade is a DELETE, so a `BEFORE UPDATE` trigger never sees it: an App's log dying with the App is legitimate, distinct from erasing a log to delete a person.
|
|
132
116
|
- **State the exemption where it exists.** A catalog whose rows must not disappear under a referencing row (a service definition, a vocabulary) keeps `NO ACTION` deliberately — that guarantee is worth one line saying so.
|
|
133
117
|
|
|
134
|
-
## Naming
|
|
135
|
-
|
|
136
|
-
- **Tables** — `snake_case`, plural noun for what they hold (`users`, `apps`, `devices`).
|
|
137
|
-
- **Junction (M:N) tables** — `<entityA>_<entityB>_map`, **always**, even when the join carries its own columns; singular stems, owning/anchor entity first (`app_user_map`, `app_device_map`). ❌ Never a "nice" noun (`members`, `installs`, `memberships`, `enrolments`) — the name must read as a join, and a reviewer should know both sides from it. The `_map` suffix is reserved for genuine M:N (§ A junction spells many-to-many).
|
|
138
|
-
- **Columns** — `snake_case`; booleans `is_*` / `has_*`; timestamps `created_at` / `updated_at`; foreign keys `<entity>_id`.
|
|
139
|
-
- **Indexes** — `<table>_<col(s)>_idx`; unique `<table>_<col(s)>_unique`; a junction's composite unique reads `<table>_<colA>_<colB>_unique` (`app_user_map_app_user_unique`).
|
|
140
|
-
- **Drizzle mirror** — the exported object is the camelCase table name (`app_user_map` → `appUserMap`); column props are the camelCase of the column (`created_at` → `createdAt`). The `sqliteTable("…")` string and every index name must match the DDL (`init.sql`) exactly — the schema-parity boundary.
|
|
141
|
-
|
|
142
118
|
## Uniqueness with a nullable column
|
|
143
119
|
|
|
144
120
|
**`UNIQUE (a, b)` does not constrain rows where `b` is `NULL`** — SQL treats every `NULL` as distinct, so a composite unique over a nullable discriminator silently permits exactly the duplicates it was introduced to keep apart. Write one partial index per scope instead:
|
|
@@ -150,12 +126,6 @@ CREATE UNIQUE INDEX <t>_child_slug_unique ON <t> (child_id, slug) WHERE child_
|
|
|
150
126
|
|
|
151
127
|
**Prove a uniqueness claim by inserting the duplicate it forbids** — a schema review cannot tell a firing index from a silent one by reading.
|
|
152
128
|
|
|
153
|
-
## Column types (SQLite / D1)
|
|
154
|
-
|
|
155
|
-
- **Timestamps** — `created_at` + `updated_at`, both `TEXT NOT NULL DEFAULT (datetime('now'))`, on **every** table — except append-only logs, which carry only `created_at`.
|
|
156
|
-
- **Booleans** — `INTEGER` (Drizzle `integer(…, { mode: "boolean" })`); the `is_*` / `has_*` names are § Naming.
|
|
157
|
-
- **JSON** — `TEXT` (Drizzle `text(…, { mode: "json" })`).
|
|
158
|
-
|
|
159
129
|
## Vocabulary / lookup tables
|
|
160
130
|
|
|
161
131
|
A controlled vocabulary earns a **table** only when a user row FKs into it and reads its `label` / `description` at runtime — a service catalog rendered in a picker; static dev-authored config nobody references by FK stays **config** (§ What earns a table) — a `doc_type` value list. Enumerable is not tabular, and a `type`-style column validated against the constants file beats an FK to a seeded mirror. An earned table has a fixed shape: `id` (UUID) · `slug` (UNIQUE) · `label` · optional `description` · `status` · timestamps.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: bookkeeper
|
|
3
3
|
description: Drains docs/operations/bookkeeping.md — performs mechanical fixes (owns: globs, header comments, doc-lint findings, index rows), expands note: rows into doc edits, marks rows resolved. Dispatched by the main session at turn end or commit time; never self-triggers. Triggers on "drain the bookkeeping queue", "dispatch the bookkeeper", "/bookkeeper".
|
|
4
4
|
tools: Read, Glob, Grep, Edit, Write, Bash, Skill
|
|
5
|
-
model:
|
|
5
|
+
model: sonnet
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Bookkeeper Agent
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: change-review
|
|
3
3
|
description: Velocity + change-risk analysis. First classifies recent commits into a pipe-delimited velocity/severity CSV by dispatching parallel low-cost subagents (module, feature, impact, severity, churn), then derives a commit heatmap, risk zones (high churn in contract-heavy code), stabilization signals, and team/bus-factor distribution. Self-contained — produces its own CSV, no separate git-history step. Use when planning where to invest in review focus or rules.
|
|
4
4
|
tools: Bash, Read, Write, Glob, Grep, Task
|
|
5
|
-
model:
|
|
5
|
+
model: sonnet
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Change-Review Agent
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: lld-mode
|
|
3
3
|
description: LLD researcher for Feature and Product workflows. Use to explore the codebase and gather the context needed for writing a feature LLD (low-level design — the feature doc in docs/features/). Returns research findings — does not write files.
|
|
4
4
|
tools: Read, Glob, Grep, WebSearch, WebFetch
|
|
5
|
-
model:
|
|
5
|
+
model: opus
|
|
6
6
|
skills:
|
|
7
7
|
- documentation
|
|
8
8
|
---
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: maintenance
|
|
3
3
|
description: The single docs steward. Default behavior is the docs-vs-code coherence audit — detects and fixes docs drifting from code (stale docs, broken ownership, unowned source paths, architecture/backlog drift). An additive **baseline mode** layers structural reconcile on top: when the repo's `harness-version` marker is missing or behind, it converges `docs/` to the installed harness shape (scaffold the standard tree, fold dissolved-shape artifacts forward, stamp the version, propose modules) before running the audit. Mode is auto-selected from the marker. Run weekly, after major changes, or to baseline/upgrade a repo. Cross-cutting contract analysis is the `boundary` skill (`check` for plans, `scan` for diffs) — it derives contracts dynamically from source; there are no persisted boundary docs to audit. Triggers on "run maintenance", "docs health", "baseline this repo", "reconcile the harness", "upgrade the harness", "is this repo on the current harness", "/maintenance".
|
|
4
4
|
tools: Read, Glob, Grep, Edit, Write, Bash
|
|
5
|
-
model:
|
|
5
|
+
model: opus
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Maintenance Agent
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: performance-review
|
|
3
3
|
description: Combined dependency + code health audit. Part A audits the dependency supply chain — security CVEs, outdated packages, license compliance, abandoned packages, unwanted transitive dependencies, install size. Part B audits code-level health — bundle size, tree-shaking issues, performance anti-patterns, code-quality flags. Run weekly or before releases. Merges the former `dep-health` and `review` agents so the package tree and the code that uses it are audited together.
|
|
4
4
|
tools: Read, Glob, Grep, Bash
|
|
5
|
-
model:
|
|
5
|
+
model: opus
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Performance-Review Agent
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: retro
|
|
3
3
|
description: Session-distillation agent for the changelog. Reads the per-unit-of-work entries under `docs/history/changelog/` accumulated since its last run and distills the refinement delta — what user-driven iteration added that the one-shot build lacked — into a typed punch list of doc-content gaps, doc-structure moves (missing doc / mothership split / merge), skill-evolution findings backed by survived-vs-overridden counts, unpinned discoveries needing an enforced artifact (test, token, guardrail, schema), and cross-project harness rules. Proposes only — actionable items land in the backlog, never applied directly. Run on demand: before a brainstorm or LLD session, before starting a new project, or after a refinement arc. Triggers on "run retro", "distill the changelog", "refinement retro", "/retro".
|
|
4
4
|
tools: Read, Glob, Grep, Bash, Write, Edit
|
|
5
|
-
model:
|
|
5
|
+
model: opus
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Retro — changelog distillation
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"harness": "code",
|
|
3
3
|
"name": "code",
|
|
4
|
-
"version": "3.6.
|
|
4
|
+
"version": "3.6.6",
|
|
5
5
|
"files": [
|
|
6
6
|
".prettierignore",
|
|
7
7
|
".prettierrc.json",
|
|
@@ -10,5 +10,5 @@
|
|
|
10
10
|
"seeds": [
|
|
11
11
|
".mcp.json"
|
|
12
12
|
],
|
|
13
|
-
"digest": "
|
|
13
|
+
"digest": "47f4949ced4c"
|
|
14
14
|
}
|
|
@@ -325,6 +325,43 @@ function planHasChangelogEntry(projectDir, planRel) {
|
|
|
325
325
|
return names.some((name) => name.endsWith(".md") && readSafe(path.join(dir, name)).includes(slug));
|
|
326
326
|
}
|
|
327
327
|
|
|
328
|
+
// Approximate the context the next turn will re-read, from the transcript's last recorded usage.
|
|
329
|
+
// Best-effort: an absent or unparseable transcript reports nothing.
|
|
330
|
+
function sessionContextTokens(transcriptPath) {
|
|
331
|
+
const text = readSafe(transcriptPath || "");
|
|
332
|
+
if (!text) return 0;
|
|
333
|
+
const lines = text.slice(-400000).split("\n");
|
|
334
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
335
|
+
if (!lines[i].includes('"usage"')) continue;
|
|
336
|
+
try {
|
|
337
|
+
const u = JSON.parse(lines[i]).message.usage;
|
|
338
|
+
return (
|
|
339
|
+
(u.input_tokens || 0) + (u.cache_read_input_tokens || 0) + (u.cache_creation_input_tokens || 0)
|
|
340
|
+
);
|
|
341
|
+
} catch (e) {
|
|
342
|
+
// the slice cut this line in half — keep scanning upward
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
return 0;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Context re-reads in full on every turn, so its size IS the standing per-turn floor — the one
|
|
349
|
+
// number that argues for ending a session rather than carrying it into unrelated work. The agent
|
|
350
|
+
// cannot act on this (it can neither end a session nor start one), so it is addressed to the user
|
|
351
|
+
// as a systemMessage and never blocks. Kept out of the model's context deliberately: a running
|
|
352
|
+
// token count in-context produces context anxiety, not shorter sessions.
|
|
353
|
+
const CONTEXT_ADVISORY_TOKENS = 250000;
|
|
354
|
+
|
|
355
|
+
function sessionSizeNote(payload) {
|
|
356
|
+
const tokens = sessionContextTokens(payload.transcript_path);
|
|
357
|
+
if (tokens < CONTEXT_ADVISORY_TOKENS) return null;
|
|
358
|
+
return (
|
|
359
|
+
`Session context is roughly ${Math.round(tokens / 1000)}K tokens, and every turn re-reads all of it — ` +
|
|
360
|
+
"that is the per-turn floor before anything new is produced. A fresh session starts near zero; " +
|
|
361
|
+
"worth ending this one if the next task is unrelated."
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
|
|
328
365
|
function stopGate(projectDir, payload) {
|
|
329
366
|
if (payload.stop_hook_active) return null; // the runtime's infinite-loop guard — never re-block
|
|
330
367
|
|
|
@@ -381,6 +418,11 @@ function main() {
|
|
|
381
418
|
}
|
|
382
419
|
} else if (event === "Stop") {
|
|
383
420
|
out = stopGate(projectDir, payload);
|
|
421
|
+
// Advisory rides alongside a block rather than replacing it — both are true at once.
|
|
422
|
+
if (!payload.stop_hook_active) {
|
|
423
|
+
const note = sessionSizeNote(payload);
|
|
424
|
+
if (note) out = { ...(out || {}), systemMessage: note };
|
|
425
|
+
}
|
|
384
426
|
}
|
|
385
427
|
|
|
386
428
|
if (out) process.stdout.write(JSON.stringify(out));
|
|
@@ -7,7 +7,7 @@ Naming and the fixed column vocabulary for relational schemas in **every** Nurix
|
|
|
7
7
|
Three column roles are fixed across every table and every project:
|
|
8
8
|
|
|
9
9
|
- **`id`** — the primary key, **always a UUID** (`TEXT PRIMARY KEY` on D1, `uuid` on Postgres), never a synthetic or natural key (❌ `type_page_button`, `human:default`). Runtime rows mint a UUIDv7; seed rows derive a deterministic UUIDv5 of the natural key so re-seeds stay stable. **Never** mix synthetic and UUID ids in one table. The single exemption is a log whose **composite key is its ordering** (`PRIMARY KEY (<entity>_id, sequence)`), declared at the table that uses it — everything else, logs included, takes a UUIDv7.
|
|
10
|
-
- **`slug`** — the **stable key rows in another scope reference**: `UNIQUE`, lowercase `snake_case`. A slug means the same thing in every scope, so a slug reference survives a copy with no remapping
|
|
10
|
+
- **`slug`** — the **stable key rows in another scope reference**: `UNIQUE`, lowercase `snake_case`. A slug means the same thing in every scope, so a slug reference survives a copy with no remapping — copying between scopes is the `schema-design` skill. ❌ Never rename this role `handle`, `key`, `code`, or `name` in another project.
|
|
11
11
|
- **`label`** — the **human display name** — ❌ never `name`, `title`, or `display_name`.
|
|
12
12
|
|
|
13
13
|
Reference columns name what they point at: `<entity>_id` for a UUID-PK reference (`user_id`, `app_id`), `<entity>_slug` for a slug reference (`source_slug`).
|
|
@@ -21,7 +21,7 @@ Reference columns name what they point at: `<entity>_id` for a UUID-PK reference
|
|
|
21
21
|
## Naming
|
|
22
22
|
|
|
23
23
|
- **Tables** — `snake_case`, plural noun for what they hold (`users`, `apps`, `devices`).
|
|
24
|
-
- **Junction (M:N) tables** — `<entityA>_<entityB>_map`, **always**, even when the join carries its own columns; singular stems, owning/anchor entity first (`app_user_map`, `app_device_map`). ❌ Never a "nice" noun (`members`, `installs`, `memberships`, `enrolments`) — the name must read as a join, and a reviewer should know both sides from it. The `_map` suffix is reserved for genuine M:N
|
|
24
|
+
- **Junction (M:N) tables** — `<entityA>_<entityB>_map`, **always**, even when the join carries its own columns; singular stems, owning/anchor entity first (`app_user_map`, `app_device_map`). ❌ Never a "nice" noun (`members`, `installs`, `memberships`, `enrolments`) — the name must read as a join, and a reviewer should know both sides from it. The `_map` suffix is reserved for genuine M:N — the cardinality test that decides junction vs. column is the `schema-design` skill.
|
|
25
25
|
- **Columns** — `snake_case`; booleans `is_*` / `has_*`; timestamps `created_at` / `updated_at`; foreign keys `<entity>_id`.
|
|
26
26
|
- **Indexes** — `<table>_<col(s)>_idx`; unique `<table>_<col(s)>_unique`; a junction's composite unique reads `<table>_<colA>_<colB>_unique` (`app_user_map_app_user_unique`).
|
|
27
27
|
- **Drizzle mirror** — the exported object is the camelCase table name (`app_user_map` → `appUserMap`); column props are the camelCase of the column (`created_at` → `createdAt`). The `sqliteTable("…")` string and every index name must match the DDL (`init.sql`) exactly — the schema-parity boundary.
|
|
@@ -85,22 +85,6 @@ One entity that exists at several scopes is **one table with a nullable scope co
|
|
|
85
85
|
- **Store the source's version at copy time** — `version` + `source_version` make "is an upgrade available" a comparison of two stored values, not a content diff.
|
|
86
86
|
- **A copy is a row, never a live read.** Nothing at the child scope reads the parent's row at runtime; propagation happens only through an explicit re-copy, so a local edit is never silently overwritten.
|
|
87
87
|
|
|
88
|
-
## Keys & the shared vocabulary
|
|
89
|
-
|
|
90
|
-
Three column roles are fixed across every table and every project:
|
|
91
|
-
|
|
92
|
-
- **`id`** — the primary key, **always a UUID** (`TEXT PRIMARY KEY` on D1, `uuid` on Postgres), never a synthetic or natural key (❌ `type_page_button`, `human:default`). Runtime rows mint a UUIDv7; seed rows derive a deterministic UUIDv5 of the natural key so re-seeds stay stable. **Never** mix synthetic and UUID ids in one table. The single exemption is a log whose **composite key is its ordering** (`PRIMARY KEY (<entity>_id, sequence)`), declared at the table that uses it — everything else, logs included, takes a UUIDv7.
|
|
93
|
-
- **`slug`** — the **stable key rows in another scope reference**: `UNIQUE`, lowercase `snake_case`. A slug means the same thing in every scope, so a slug reference survives a copy with no remapping (§ Copying rows between scopes). ❌ Never rename this role `handle`, `key`, `code`, or `name` in another project.
|
|
94
|
-
- **`label`** — the **human display name** — ❌ never `name`, `title`, or `display_name`.
|
|
95
|
-
|
|
96
|
-
Reference columns name what they point at: `<entity>_id` for a UUID-PK reference (`user_id`, `app_id`), `<entity>_slug` for a slug reference (`source_slug`).
|
|
97
|
-
|
|
98
|
-
- **Enforced, same scope** (the referenced row must exist) → a real `FOREIGN KEY (<x>_id) REFERENCES <table>(id)`.
|
|
99
|
-
- **Cross-scope** (the reference must survive being copied) → `<x>_slug` as a plain column, **no** FK — an FK would bind the row to one scope's copy of the target, which is the remapping the slug exists to avoid.
|
|
100
|
-
- **Drift-tolerant** (a controlled-vocabulary value that may fall off-list) → a plain value column, **no** FK, paired with an `is_*` boolean recording whether the value is in the canonical set.
|
|
101
|
-
|
|
102
|
-
**Every inbound FK to a hub table declares a deliberate `ON DELETE`.** A hub (`users`, `devices`, anything several modules point at) collects edges from teams that never meet, and a single `NO ACTION` among them turns deleting the parent into a constraint error naming neither table. Decide per edge: the child dies with the row (`CASCADE`) or survives it (`SET NULL`, which needs a nullable column) — `NO ACTION` on a hub is a deferred outage, not a default.
|
|
103
|
-
|
|
104
88
|
## A junction spells many-to-many — nothing else
|
|
105
89
|
|
|
106
90
|
**A `_map` table is the schema's notation for M:N. Using it for 1:M is a category error** — the junction's own uniqueness admits many parents per child, so the "one parent" rule stops being enforced the moment it is written this way. Cardinality decides between the only two shapes:
|
|
@@ -131,14 +115,6 @@ Reference columns name what they point at: `<entity>_id` for a UUID-PK reference
|
|
|
131
115
|
- **`CASCADE` from the append-only side's own parent is still fine** — a cascade is a DELETE, so a `BEFORE UPDATE` trigger never sees it: an App's log dying with the App is legitimate, distinct from erasing a log to delete a person.
|
|
132
116
|
- **State the exemption where it exists.** A catalog whose rows must not disappear under a referencing row (a service definition, a vocabulary) keeps `NO ACTION` deliberately — that guarantee is worth one line saying so.
|
|
133
117
|
|
|
134
|
-
## Naming
|
|
135
|
-
|
|
136
|
-
- **Tables** — `snake_case`, plural noun for what they hold (`users`, `apps`, `devices`).
|
|
137
|
-
- **Junction (M:N) tables** — `<entityA>_<entityB>_map`, **always**, even when the join carries its own columns; singular stems, owning/anchor entity first (`app_user_map`, `app_device_map`). ❌ Never a "nice" noun (`members`, `installs`, `memberships`, `enrolments`) — the name must read as a join, and a reviewer should know both sides from it. The `_map` suffix is reserved for genuine M:N (§ A junction spells many-to-many).
|
|
138
|
-
- **Columns** — `snake_case`; booleans `is_*` / `has_*`; timestamps `created_at` / `updated_at`; foreign keys `<entity>_id`.
|
|
139
|
-
- **Indexes** — `<table>_<col(s)>_idx`; unique `<table>_<col(s)>_unique`; a junction's composite unique reads `<table>_<colA>_<colB>_unique` (`app_user_map_app_user_unique`).
|
|
140
|
-
- **Drizzle mirror** — the exported object is the camelCase table name (`app_user_map` → `appUserMap`); column props are the camelCase of the column (`created_at` → `createdAt`). The `sqliteTable("…")` string and every index name must match the DDL (`init.sql`) exactly — the schema-parity boundary.
|
|
141
|
-
|
|
142
118
|
## Uniqueness with a nullable column
|
|
143
119
|
|
|
144
120
|
**`UNIQUE (a, b)` does not constrain rows where `b` is `NULL`** — SQL treats every `NULL` as distinct, so a composite unique over a nullable discriminator silently permits exactly the duplicates it was introduced to keep apart. Write one partial index per scope instead:
|
|
@@ -150,12 +126,6 @@ CREATE UNIQUE INDEX <t>_child_slug_unique ON <t> (child_id, slug) WHERE child_
|
|
|
150
126
|
|
|
151
127
|
**Prove a uniqueness claim by inserting the duplicate it forbids** — a schema review cannot tell a firing index from a silent one by reading.
|
|
152
128
|
|
|
153
|
-
## Column types (SQLite / D1)
|
|
154
|
-
|
|
155
|
-
- **Timestamps** — `created_at` + `updated_at`, both `TEXT NOT NULL DEFAULT (datetime('now'))`, on **every** table — except append-only logs, which carry only `created_at`.
|
|
156
|
-
- **Booleans** — `INTEGER` (Drizzle `integer(…, { mode: "boolean" })`); the `is_*` / `has_*` names are § Naming.
|
|
157
|
-
- **JSON** — `TEXT` (Drizzle `text(…, { mode: "json" })`).
|
|
158
|
-
|
|
159
129
|
## Vocabulary / lookup tables
|
|
160
130
|
|
|
161
131
|
A controlled vocabulary earns a **table** only when a user row FKs into it and reads its `label` / `description` at runtime — a service catalog rendered in a picker; static dev-authored config nobody references by FK stays **config** (§ What earns a table) — a `doc_type` value list. Enumerable is not tabular, and a `type`-style column validated against the constants file beats an FK to a seeded mirror. An earned table has a fixed shape: `id` (UUID) · `slug` (UNIQUE) · `label` · optional `description` · `status` · timestamps.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: lld-mode
|
|
3
3
|
description: LLD researcher for Feature and Product workflows. Use to explore the codebase and gather the context needed for writing a feature LLD (low-level design — the feature doc in docs/features/). Returns research findings — does not write files.
|
|
4
4
|
tools: Read, Glob, Grep, WebSearch, WebFetch
|
|
5
|
-
model:
|
|
5
|
+
model: opus
|
|
6
6
|
skills:
|
|
7
7
|
- documentation
|
|
8
8
|
---
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: maintenance
|
|
3
3
|
description: The single docs steward. Default behavior is the docs-vs-code coherence audit — detects and fixes docs drifting from code (stale docs, broken ownership, unowned source paths, architecture/backlog drift). An additive **baseline mode** layers structural reconcile on top: when the repo's `harness-version` marker is missing or behind, it converges `docs/` to the installed harness shape (scaffold the standard tree, fold dissolved-shape artifacts forward, stamp the version, propose modules) before running the audit. Mode is auto-selected from the marker. Run weekly, after major changes, or to baseline/upgrade a repo. Cross-cutting contract analysis is the `boundary` skill (`check` for plans, `scan` for diffs) — it derives contracts dynamically from source; there are no persisted boundary docs to audit. Triggers on "run maintenance", "docs health", "baseline this repo", "reconcile the harness", "upgrade the harness", "is this repo on the current harness", "/maintenance".
|
|
4
4
|
tools: Read, Glob, Grep, Edit, Write, Bash
|
|
5
|
-
model:
|
|
5
|
+
model: opus
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Maintenance Agent
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: retro
|
|
3
3
|
description: Session-distillation agent for the changelog. Reads the per-unit-of-work entries under `docs/history/changelog/` accumulated since its last run and distills the refinement delta — what user-driven iteration added that the one-shot build lacked — into a typed punch list of doc-content gaps, doc-structure moves (missing doc / mothership split / merge), skill-evolution findings backed by survived-vs-overridden counts, unpinned discoveries needing an enforced artifact (test, token, guardrail, schema), and cross-project harness rules. Proposes only — actionable items land in the backlog, never applied directly. Run on demand: before a brainstorm or LLD session, before starting a new project, or after a refinement arc. Triggers on "run retro", "distill the changelog", "refinement retro", "/retro".
|
|
4
4
|
tools: Read, Glob, Grep, Bash, Write, Edit
|
|
5
|
-
model:
|
|
5
|
+
model: opus
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Retro — changelog distillation
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"harness": "delivery",
|
|
3
3
|
"name": "delivery",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.7",
|
|
5
5
|
"files": [
|
|
6
6
|
".prettierignore",
|
|
7
7
|
".prettierrc.json",
|
|
8
8
|
".vscode/settings.json"
|
|
9
9
|
],
|
|
10
10
|
"seeds": [],
|
|
11
|
-
"digest": "
|
|
11
|
+
"digest": "49197cb78351"
|
|
12
12
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: change-review
|
|
3
3
|
description: Velocity + change-risk analysis. First classifies recent commits into a pipe-delimited velocity/severity CSV by dispatching parallel low-cost subagents (module, feature, impact, severity, churn), then derives a commit heatmap, risk zones (high churn in contract-heavy code), stabilization signals, and team/bus-factor distribution. Self-contained — produces its own CSV, no separate git-history step. Use when planning where to invest in review focus or rules.
|
|
4
4
|
tools: Bash, Read, Write, Glob, Grep, Task
|
|
5
|
-
model:
|
|
5
|
+
model: sonnet
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Change-Review Agent
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: lld-mode
|
|
3
3
|
description: LLD researcher for Feature and Product workflows. Use to explore the codebase and gather the context needed for writing a feature LLD (low-level design — the feature doc in docs/features/). Returns research findings — does not write files.
|
|
4
4
|
tools: Read, Glob, Grep, WebSearch, WebFetch
|
|
5
|
-
model:
|
|
5
|
+
model: opus
|
|
6
6
|
skills:
|
|
7
7
|
- documentation
|
|
8
8
|
---
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: maintenance
|
|
3
3
|
description: The single docs steward. Default behavior is the docs-vs-code coherence audit — detects and fixes docs drifting from code (stale docs, broken ownership, unowned source paths, architecture/backlog drift). An additive **baseline mode** layers structural reconcile on top: when the repo's `harness-version` marker is missing or behind, it converges `docs/` to the installed harness shape (scaffold the standard tree, fold dissolved-shape artifacts forward, stamp the version, propose modules) before running the audit. Mode is auto-selected from the marker. Run weekly, after major changes, or to baseline/upgrade a repo. Cross-cutting contract analysis is the `boundary` skill (`check` for plans, `scan` for diffs) — it derives contracts dynamically from source; there are no persisted boundary docs to audit. Triggers on "run maintenance", "docs health", "baseline this repo", "reconcile the harness", "upgrade the harness", "is this repo on the current harness", "/maintenance".
|
|
4
4
|
tools: Read, Glob, Grep, Edit, Write, Bash
|
|
5
|
-
model:
|
|
5
|
+
model: opus
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Maintenance Agent
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: performance-review
|
|
3
3
|
description: Combined dependency + code health audit. Part A audits the dependency supply chain — security CVEs, outdated packages, license compliance, abandoned packages, unwanted transitive dependencies, install size. Part B audits code-level health — bundle size, tree-shaking issues, performance anti-patterns, code-quality flags. Run weekly or before releases. Merges the former `dep-health` and `review` agents so the package tree and the code that uses it are audited together.
|
|
4
4
|
tools: Read, Glob, Grep, Bash
|
|
5
|
-
model:
|
|
5
|
+
model: opus
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Performance-Review Agent
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: retro
|
|
3
3
|
description: Session-distillation agent for the changelog. Reads the per-unit-of-work entries under `docs/history/changelog/` accumulated since its last run and distills the refinement delta — what user-driven iteration added that the one-shot build lacked — into a typed punch list of doc-content gaps, doc-structure moves (missing doc / mothership split / merge), skill-evolution findings backed by survived-vs-overridden counts, unpinned discoveries needing an enforced artifact (test, token, guardrail, schema), and cross-project harness rules. Proposes only — actionable items land in the backlog, never applied directly. Run on demand: before a brainstorm or LLD session, before starting a new project, or after a refinement arc. Triggers on "run retro", "distill the changelog", "refinement retro", "/retro".
|
|
4
4
|
tools: Read, Glob, Grep, Bash, Write, Edit
|
|
5
|
-
model:
|
|
5
|
+
model: opus
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Retro — changelog distillation
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nurix/etna",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.57",
|
|
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": "73e48dd4eae4"
|
|
46
46
|
}
|