@dzhechkov/harness-cli 0.8.22 → 0.8.24
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/.dz-manifest.json +16 -16
- package/README.md +591 -138
- package/dist/boolean-flags.d.ts.map +1 -1
- package/dist/boolean-flags.js +4 -0
- package/dist/boolean-flags.js.map +1 -1
- package/dist/cli.d.ts +96 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1975 -332
- package/dist/cli.js.map +1 -1
- package/dist/known-flags.d.ts.map +1 -1
- package/dist/known-flags.js +22 -0
- package/dist/known-flags.js.map +1 -1
- package/package.json +28 -28
- package/sbom.json +15 -15
- package/src/boolean-flags.ts +4 -0
- package/src/cli.ts +2102 -366
- package/src/known-flags.ts +22 -0
package/README.md
CHANGED
|
@@ -2,13 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
The **`dz`** CLI — the main entry point to the DZ Harness Hub. Install AI skills for **Claude Code, Codex, OpenCode, Hermes, OpenClaude, GitHub Copilot** from a single command.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Install in 30 seconds
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @dzhechkov/harness-cli
|
|
9
|
+
dz setup --target claude-code --preset devops
|
|
10
|
+
dz doctor
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
You do NOT need to clone any repository to use dz. Source is for contributors — see
|
|
14
|
+
[From source (contributors only)](#from-source-contributors-only) at the end of this README.
|
|
12
15
|
|
|
13
16
|
## Why dz?
|
|
14
17
|
|
|
@@ -120,7 +123,7 @@ Re-running is safe (existing files are skipped unless `--force`). Targets: `clau
|
|
|
120
123
|
|
|
121
124
|
Don't see your tool below? Two fallbacks: if it reads `CLAUDE.md`/`.claude/` use `--target claude-code`;
|
|
122
125
|
otherwise `dz bundle --select <ids> --out <dir>` gives a portable tree of **raw `SKILL.md`** files you can
|
|
123
|
-
point any tool at (a skill is just Markdown). Dedicated targets are on the
|
|
126
|
+
point any tool at (a skill is just Markdown). Dedicated targets are on the roadmap (contributors — see `docs/target-expansion-research.md` in the source repo).
|
|
124
127
|
|
|
125
128
|
**✅ Shipped native targets** (each compiles to the tool's own layout):
|
|
126
129
|
|
|
@@ -287,7 +290,7 @@ you know exactly which file is at fault, and you know whose defect it is.
|
|
|
287
290
|
|
|
288
291
|
## User Journey — from install to mastery
|
|
289
292
|
|
|
290
|
-
All
|
|
293
|
+
All 92 commands (MEASURED — reproducer: `node --input-type=module -e "import('./dist/index.js').then(m=>console.log(m.DZ_COMMANDS.length))"` from this package; rendered help documents 93 unique top-level names — the 92 plus the built-in `help` — pinned NAME-FOR-NAME by `test/command-inventory-parity.test.ts`) mapped to a real workflow:
|
|
291
294
|
|
|
292
295
|
```
|
|
293
296
|
DISCOVER → INSTALL → USE → CREATE → MAINTAIN → SHARE
|
|
@@ -975,7 +978,13 @@ stated fact rather than an inference from an absent file. Records and reports ar
|
|
|
975
978
|
the state directory itself is contained the same way, before anything is created in it. The audit
|
|
976
979
|
trail is written BEFORE the report and corrected after it, so `reportWritten` can only ever
|
|
977
980
|
understate; if the trail cannot be written at all, the run FAILS (`audit-write-failed`) rather than
|
|
978
|
-
shipping a verdict nobody can re-derive.
|
|
981
|
+
shipping a verdict nobody can re-derive. The record also carries `writeSequence` — diagnostic
|
|
982
|
+
sequencing metadata: a self-reported, process-local trace of the `signoff-write-started` /
|
|
983
|
+
`report-written` / `record-update-prepared` steps with monotonic stamps taken at each named event
|
|
984
|
+
(the start of the first record write, the moment the report is on disk, and just before the atomic
|
|
985
|
+
record update). It replaces a file-mtime comparison in the tests (a race); the write ORDER itself is
|
|
986
|
+
proven by the report-failure test (record exists and says `false` when the report never lands) and
|
|
987
|
+
the failpoint test (`reportWritten:true` only after the report), not by this field.
|
|
979
988
|
|
|
980
989
|
**Exit codes:** `0` a signoff was parsed (ANY grade — a grade F still exits 0: the bridge reports, it
|
|
981
990
|
does not gate), `1` a named failure, `2` a usage error. **Honest limits:** it proves the call was
|
|
@@ -1021,17 +1030,15 @@ extracts you scope are what leaves the machine. RU: мост в обратную
|
|
|
1021
1030
|
### Пересмотр после аварийного само-ревью — `dz reqe`
|
|
1022
1031
|
|
|
1023
1032
|
The feature-adr pipeline's cross-model guard says *the model that writes code must not review it*.
|
|
1024
|
-
|
|
1025
|
-
Step-8 QE both
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
`
|
|
1029
|
-
freed-up limits, and settlement is FAIL-CLOSED.
|
|
1033
|
+
Historical usage-switched runs could suspend that guard under provider-limit pressure: coder AND
|
|
1034
|
+
Step-8 QE both ran on Codex. The rule used to say "re-review manually after limits reset" — an
|
|
1035
|
+
instruction nobody remembers. `dz reqe` turns it into a **debt with a lifecycle**: the run records
|
|
1036
|
+
`features/<slug>/.fa-state/reqe-due.json`, `dz usage --json` carries the outstanding count as
|
|
1037
|
+
`reqeDue`, and settlement is FAIL-CLOSED.
|
|
1030
1038
|
|
|
1031
1039
|
```bash
|
|
1032
|
-
$ dz usage
|
|
1033
|
-
|
|
1034
|
-
re-QE due: 1 usage-switched run(s) kept same-family QE — run `dz reqe` for the cross-family pass
|
|
1040
|
+
$ dz usage --json
|
|
1041
|
+
{"sessionPct":null,"weeklyPct":null,"routing":"disabled-by-design","spend":{"days":[...],"total7d":{...},"byModel":{...}},"reqeDue":1}
|
|
1035
1042
|
|
|
1036
1043
|
$ dz reqe # the ledger
|
|
1037
1044
|
dz reqe — 1 unsettled re-QE debt(s):
|
|
@@ -1042,8 +1049,8 @@ $ dz reqe --slug add-x --done --report features/add-x/08b_reqe_report.md
|
|
|
1042
1049
|
dz reqe: debt settled: re-QE grade C (report …) — settlement appended to features/add-x/08_qe_report.md
|
|
1043
1050
|
```
|
|
1044
1051
|
|
|
1045
|
-
**When to use:** any time `dz usage`
|
|
1046
|
-
`reqeDue: true`. **Fail-closed settlement:** the report must exist, be non-trivial, and name exactly
|
|
1052
|
+
**When to use:** any time `dz usage --json` reports a positive `reqeDue`, or a feature-adr result
|
|
1053
|
+
carried `reqeDue: true`. **Fail-closed settlement:** the report must exist, be non-trivial, and name exactly
|
|
1047
1054
|
one line-anchored `GRADE` (the boilerplate phrase `GRADE A-F` does not count); the run's own
|
|
1048
1055
|
`08_qe_report.md` can never settle its own debt (real-path AND inode compared — a hard link doesn't
|
|
1049
1056
|
fool it); the settlement epilogue lands in `08_qe_report.md` and the due-file rotates to
|
|
@@ -1051,12 +1058,13 @@ fool it); the settlement epilogue lands in `08_qe_report.md` and the due-file ro
|
|
|
1051
1058
|
nothing re-runs QE automatically, and the validator proves the settlement is procedurally sound —
|
|
1052
1059
|
which model authored the report stays with the human running the brief. RU: гард «кодер не ревьюит
|
|
1053
1060
|
сам себя» осознанно снимается под лимитом; `dz reqe` превращает инструкцию «перепроверь потом»
|
|
1054
|
-
в долг на диске — виден в `dz usage`, гасится только настоящим кросс-семейным отчётом с грейдом.
|
|
1061
|
+
в долг на диске — виден как `reqeDue` в `dz usage --json`, гасится только настоящим кросс-семейным отчётом с грейдом.
|
|
1055
1062
|
|
|
1056
|
-
###
|
|
1063
|
+
### Spend you can inspect — `dz usage`
|
|
1057
1064
|
|
|
1058
|
-
`dz usage`
|
|
1059
|
-
|
|
1065
|
+
`dz usage` reports cost-weighted token spend from local Claude Code and subagent transcripts. It does
|
|
1066
|
+
not predict provider limits: there is no provider usage API, weekly resets are per-account, and
|
|
1067
|
+
ad-hoc resets make a local denominator non-measurable. Feature routing is therefore disabled by design.
|
|
1060
1068
|
|
|
1061
1069
|
Two things changed to make it mean something:
|
|
1062
1070
|
|
|
@@ -1066,20 +1074,44 @@ Two things changed to make it mean something:
|
|
|
1066
1074
|
1-hour TTL write, cache-read 0.1x, output 5x).
|
|
1067
1075
|
- **Subagent transcripts count.** `<session>/subagents/*.jsonl` carry real, non-duplicated usage and
|
|
1068
1076
|
were silently excluded.
|
|
1077
|
+
- **Symlinked project directories are scanned by real path, each real directory once.** Broken links
|
|
1078
|
+
and symlinks to files are skipped.
|
|
1069
1079
|
- **The walk is safe and bounded.** Only regular files are read, symlinked files and directory
|
|
1070
|
-
components
|
|
1071
|
-
|
|
1080
|
+
components cannot create duplicate walks or loops, and the file cap keeps the NEWEST transcripts
|
|
1081
|
+
so a long history cannot push current usage out of view.
|
|
1072
1082
|
|
|
1073
1083
|
```bash
|
|
1074
|
-
dz usage
|
|
1075
|
-
dz usage --json
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1084
|
+
dz usage # seven UTC days + seven-day total + model shares + today-by-model
|
|
1085
|
+
dz usage --json # sessionPct/weeklyPct stay null; spend carries days, total7d, byModel, daysByModel
|
|
1086
|
+
```
|
|
1087
|
+
|
|
1088
|
+
The compatibility keys `sessionPct` and `weeklyPct` remain present and always `null`, so existing
|
|
1089
|
+
feature-adr probes keep parsing the payload without treating a guess as a routing signal.
|
|
1090
|
+
|
|
1091
|
+
**What `unknown` means, and which window each block covers.** The "by model" table is a
|
|
1092
|
+
**seven-day window total** — it is the same seven days as the daily table above it, collapsed
|
|
1093
|
+
across models, never a per-day figure (a defect this project has hit before: a weekly figure read
|
|
1094
|
+
as a daily one). A model row named `unknown` is the aggregation's fallback bucket, literally
|
|
1095
|
+
`event.model ?? 'unknown'` in `spendReport` — it catches BOTH of the two ways an event can carry no
|
|
1096
|
+
usable model: an event with **no model field at all**, and one whose model string did not match
|
|
1097
|
+
any of the four known substrings (`fable`/`opus`/`sonnet`/`haiku`). (Fix-round-1, Codex review
|
|
1098
|
+
MEDIUM #3: an earlier revision of this paragraph said `unknown` was "not an event without a
|
|
1099
|
+
model" — the opposite of what the code does; corrected to name both causes.) MEASURED on this
|
|
1100
|
+
machine, the second cause dominates — almost entirely `<synthetic>` assistant-turn markers, not a
|
|
1101
|
+
parsing failure — and `unknown` is always shown, never hidden, because a hidden `unknown` row would
|
|
1102
|
+
make the visible rows undercount the real total. Both the "by model" table and the "today by model"
|
|
1103
|
+
block print a third column: the model's **share as a fraction 0..1** (two decimals), not a
|
|
1104
|
+
percentage — `by model` shares are of the **seven-day total**, `today by model` shares are of
|
|
1105
|
+
**today's own total**, and a complete breakdown's column sums to `1.00` in either block (never
|
|
1106
|
+
`100` — that would be the percentage form). The `--json` payload additionally carries
|
|
1107
|
+
`spend.daysByModel`: one entry per day (same dates as `spend.days`, same order) with that single
|
|
1108
|
+
day's `{model → weightedTokens}`, `unknown` included — read `daysByModel.at(-1)` for **today's**
|
|
1109
|
+
per-model spend, which the plain-text report prints as the `today (<date>) by model` block right
|
|
1110
|
+
after the seven-day "by model" table. The invariant this rests on — every model breakdown
|
|
1111
|
+
reconciles exactly with the totals it was sliced from — is `spendInvariantViolations()` in
|
|
1112
|
+
`harness-core` (relative tolerance `max(1e-6, 1e-9·max(|a|,|b|))`, and a `NaN`/`Infinity` sum is
|
|
1113
|
+
always a violation, never a silent pass), covered by a dedicated mutation-registry entry
|
|
1114
|
+
(`usage-days-by-model-invariant`).
|
|
1083
1115
|
|
|
1084
1116
|
### Where did the run's budget actually go? — `dz usage --by-stage`
|
|
1085
1117
|
|
|
@@ -1327,6 +1359,22 @@ Four rules the gate itself obeys — these are what distinguish it from a green-
|
|
|
1327
1359
|
undefended property lives in this repo's test suite, and the gate MUST fail on it — a gate that
|
|
1328
1360
|
cannot fail cannot pass.
|
|
1329
1361
|
|
|
1362
|
+
**Where the full output of a RED baseline/rebaseline line lives** (gate-stability, 2026-09-12,
|
|
1363
|
+
fix-round-1 2026-09-12): the bounded 3-line/20-line tail in the verdict is a teaser, and under a
|
|
1364
|
+
multi-entry `--only a,b` run it was measured to hand back an unrelated neighbour's stderr —
|
|
1365
|
+
undiagnosable. When the initial baseline or a per-entry/final rebaseline line comes back non-zero,
|
|
1366
|
+
the executor saves the FULL stdout+stderr to
|
|
1367
|
+
`<os.tmpdir()>/dz-mutgate-output/dz-mutgate-<entryId|baseline>-<phase>-<ISO-timestamp>.log` and the
|
|
1368
|
+
verdict text names the path (`; full output: <path>`); a green line writes nothing. Files older
|
|
1369
|
+
than 7 days in that directory are rotated away on the next write, and rotation only ever touches a
|
|
1370
|
+
name carrying BOTH our own `dz-mutgate-` prefix AND our exact ISO-timestamp shape — a foreign file
|
|
1371
|
+
(even one shaped like `service-baseline-backup.log`, which the pre-fix-round-1 pattern would have
|
|
1372
|
+
matched and deleted) is never touched. If the save itself fails (EACCES/ENOSPC/EROFS/a blocked
|
|
1373
|
+
output directory), the verdict says so instead of silently losing the diagnostic artifact
|
|
1374
|
+
(`; full output NOT saved: <error>`) — the gate's own exit code is never changed by a logging
|
|
1375
|
+
failure. Override the directory with `DZ_MUTGATE_OUTPUT_DIR` (used by this package's own tests to
|
|
1376
|
+
avoid touching the real tmpdir).
|
|
1377
|
+
|
|
1330
1378
|
When to reach for it: after a QE round names safety properties (seed the registry so they STAY
|
|
1331
1379
|
defended); in CI for a package whose protections have burned you before (`npm run test:mutation`);
|
|
1332
1380
|
and in feature-adr Step 8, where the QE reviewer runs it whenever the touched package has a
|
|
@@ -1449,13 +1497,13 @@ Each pack is an npm package — click through for the **full per-skill documenta
|
|
|
1449
1497
|
| [@dzhechkov/skills-academic](https://www.npmjs.com/package/@dzhechkov/skills-academic) | 5 | Thesis-defense toolkit — dissertation review, questions, doc-check, defense eval |
|
|
1450
1498
|
| [@dzhechkov/skills-news](https://www.npmjs.com/package/@dzhechkov/skills-news) | 3 | *dz-original* — news digests (`news-digest`) + delta watches (`news-monitor`) + bundled `goap-research-ed25519` verified-research backend (mandatory) |
|
|
1451
1499
|
| [@dzhechkov/skills-demo-publisher](https://github.com/djd1m/dz-harness/tree/main/packages/%40dzhechkov/skills-demo-publisher) | 1 | *dz-original, staged* — scenario-driven product recording → budgeted static HTML5 video site with Russian captions and fail-closed Pages delivery checks |
|
|
1452
|
-
| [@dzhechkov/skills-idea2prd](https://www.npmjs.com/package/@dzhechkov/skills-idea2prd) | 1 | *dz-original* — `idea2prd-manual`: idea/problem → PRD+ADR+DDD+C4+Pseudocode+Tests+Completion (9 checkpoints); bundles the analyst trio as a sources.json-tracked vendor (
|
|
1453
|
-
| [@dzhechkov/skills-reverse-engineering](https://www.npmjs.com/package/@dzhechkov/skills-reverse-engineering) | 1 | *dz-original* — `reverse-engineering-unicorn`: company → launch playbook (+CJM) via 6-module QUICK/DEEP/VERIFIED pipeline; canonical home that resolved the keysarium↔p-replicator drift (
|
|
1454
|
-
| [@dzhechkov/skills-presentation-storyteller](https://www.npmjs.com/package/@dzhechkov/skills-presentation-storyteller) | 1 | *dz-original* — `presentation-storyteller`: selling deck + verified sources + slide-by-slide speaker script; referenced (not vendored) by reverse-engineering-unicorn's Post-M6 step (
|
|
1455
|
-
| [@dzhechkov/skills-website-cloner](https://www.npmjs.com/package/@dzhechkov/skills-website-cloner) | 1 | *imported (MIT)* — `clone-website`: live site → pixel-perfect Next.js clone (recon → specs → parallel build → visual QA); needs a browser-MCP + Next.js scaffold; referenced by p-replicator's `/replicate` (
|
|
1456
|
-
| [@dzhechkov/skills-pm](https://www.npmjs.com/package/@dzhechkov/skills-pm) | 18 | *imported (MIT)* — product-management toolkit: OST, RICE/ICE prioritization, product-strategy, pricing, OKRs, NSM/metrics/A-B/cohort, outcome-roadmap, stakeholder-map, sprint-plan, strategy-red-team, GTM/growth/beachhead, market-sizing; curated from phuryn/pm-skills (`dz init --preset pm`) (
|
|
1457
|
-
| [@dzhechkov/skills-taste](https://www.npmjs.com/package/@dzhechkov/skills-taste) | 1 | *imported (MIT)* — `design-taste-frontend`: anti-slop landing/portfolio/redesign framework (dials + pre-flight + GSAP skeletons); complements frontend-design (`dz init --select design-taste-frontend`) (
|
|
1458
|
-
| [@dzhechkov/skills-book-digitizer](https://www.npmjs.com/package/@dzhechkov/skills-book-digitizer) | 8 | *dz-original* — book → installable methodology pack: `digitize-book` (orchestrator) + ingest/extract/distill/pack/kb-index + `book-brain-register` (CP6 promote → cross-project brain) + `source-brain-ingest` (repo sibling). Verified provenance, IP-safe, resumable (`dz init --select digitize-book`) (
|
|
1500
|
+
| [@dzhechkov/skills-idea2prd](https://www.npmjs.com/package/@dzhechkov/skills-idea2prd) | 1 | *dz-original* — `idea2prd-manual`: idea/problem → PRD+ADR+DDD+C4+Pseudocode+Tests+Completion (9 checkpoints); bundles the analyst trio as a sources.json-tracked vendor (ADR-0001, contributors-only doc) |
|
|
1501
|
+
| [@dzhechkov/skills-reverse-engineering](https://www.npmjs.com/package/@dzhechkov/skills-reverse-engineering) | 1 | *dz-original* — `reverse-engineering-unicorn`: company → launch playbook (+CJM) via 6-module QUICK/DEEP/VERIFIED pipeline; canonical home that resolved the keysarium↔p-replicator drift (ADR-0001, contributors-only doc) |
|
|
1502
|
+
| [@dzhechkov/skills-presentation-storyteller](https://www.npmjs.com/package/@dzhechkov/skills-presentation-storyteller) | 1 | *dz-original* — `presentation-storyteller`: selling deck + verified sources + slide-by-slide speaker script; referenced (not vendored) by reverse-engineering-unicorn's Post-M6 step (ADR-0001, contributors-only doc) |
|
|
1503
|
+
| [@dzhechkov/skills-website-cloner](https://www.npmjs.com/package/@dzhechkov/skills-website-cloner) | 1 | *imported (MIT)* — `clone-website`: live site → pixel-perfect Next.js clone (recon → specs → parallel build → visual QA); needs a browser-MCP + Next.js scaffold; referenced by p-replicator's `/replicate` (ADR-0001, contributors-only doc) |
|
|
1504
|
+
| [@dzhechkov/skills-pm](https://www.npmjs.com/package/@dzhechkov/skills-pm) | 18 | *imported (MIT)* — product-management toolkit: OST, RICE/ICE prioritization, product-strategy, pricing, OKRs, NSM/metrics/A-B/cohort, outcome-roadmap, stakeholder-map, sprint-plan, strategy-red-team, GTM/growth/beachhead, market-sizing; curated from phuryn/pm-skills (`dz init --preset pm`) (ADR-0002, contributors-only doc) |
|
|
1505
|
+
| [@dzhechkov/skills-taste](https://www.npmjs.com/package/@dzhechkov/skills-taste) | 1 | *imported (MIT)* — `design-taste-frontend`: anti-slop landing/portfolio/redesign framework (dials + pre-flight + GSAP skeletons); complements frontend-design (`dz init --select design-taste-frontend`) (ADR-0002, contributors-only doc) |
|
|
1506
|
+
| [@dzhechkov/skills-book-digitizer](https://www.npmjs.com/package/@dzhechkov/skills-book-digitizer) | 8 | *dz-original* — book → installable methodology pack: `digitize-book` (orchestrator) + ingest/extract/distill/pack/kb-index + `book-brain-register` (CP6 promote → cross-project brain) + `source-brain-ingest` (repo sibling). Verified provenance, IP-safe, resumable (`dz init --select digitize-book`) (ADR-001, contributors-only doc) |
|
|
1459
1507
|
| [@dzhechkov/skills-12factor](https://www.npmjs.com/package/@dzhechkov/skills-12factor) | 12 | *generated by the digitizer, CC BY 4.0* — The Twelve-Factor App distilled into 12 decision-moment skills (one per factor). The first PUBLIC digitized-book pack; paraphrased (shingling-gated), routing-gated (every factor carries triggers), attributed (`NOTICE`) (`dz init --select 12factor-config-in-environment,…`) |
|
|
1460
1508
|
| [@dzhechkov/skills-book-ai-apps](https://www.npmjs.com/package/@dzhechkov/skills-book-ai-apps) | 17 | *generated by the digitizer, CP5-published* — «Building Applications with AI Agents» (Albada, рус. пер.) distilled into 17 decision-moment skills across the whole agent-building arc: agent-fit & model choice, single-vs-multi, orchestration, tool design, knowledge & memory, context engineering, evaluation, probabilistic behaviour checks, release gates, improvement loops, drift, human-in-the-loop, agent UX, governance, security. Ships our page-anchored Knowledge Units, NOT the book text — shingling-gated at 0 uncited verbatim runs >=8 words; publication is the recorded CP5 owner decision; `trust_tier 1` (routing-gated, not human-reviewed) Since 0.2.2 it also ships `brain/ai-apps.sqlite`, the 223-KU knowledge slice: `dz brain add --from-pack @dzhechkov/skills-book-ai-apps` loads it into your `~/.dz/brain`, then `dz brain query --source ai-apps` answers in any project (`dz install @dzhechkov/skills-book-ai-apps --target claude-code`) |
|
|
1461
1509
|
| [@dzhechkov/skills-book-clean-code](https://www.npmjs.com/package/@dzhechkov/skills-book-clean-code) | 9 | *generated by the digitizer, CP5-published 2026-09-11* — «Чистый код» (Robert C. Martin, рус. пер.): intent/comment contract, source layout, function contracts, object/data ownership, error and boundary handling, test-suite feedback, legacy refactoring loop, architecture assembly, concurrency safety; ships `brain/clean-code.sqlite` (259 KU). Shingling IP gate 0 violations on the published bytes; trust tier 1. |
|
|
@@ -1972,10 +2020,10 @@ runs a command that MEASURES the declared artifacts itself. It refuses a null re
|
|
|
1972
2020
|
never recorded as done), an absent or partially-present artifact set, and a stage that declares nothing
|
|
1973
2021
|
to witness — so a stage that did not happen can no longer be recorded, which the old mechanism allowed.
|
|
1974
2022
|
|
|
1975
|
-
## All Commands (
|
|
2023
|
+
## All Commands (92)
|
|
1976
2024
|
|
|
1977
|
-
*(
|
|
1978
|
-
top-level names — the
|
|
2025
|
+
*(92 MEASURED from the bounded command inventory below; rendered `dz --help` exposes 93 unique
|
|
2026
|
+
top-level names — the 92 plus the built-in `help`, which prints USAGE before the dispatch switch and
|
|
1979
2027
|
is therefore documented without being a command. Both numbers are COMPUTED, never typed: the name
|
|
1980
2028
|
sets of this section, the root README, the docs site and `DZ_COMMANDS` are pinned to each other by
|
|
1981
2029
|
`test/command-inventory-parity.test.ts`.)*
|
|
@@ -1992,7 +2040,7 @@ dz teach --from-json <file> [--project <dir>] [--no-mirror] [--harmonize] # bu
|
|
|
1992
2040
|
dz consolidate [--sessions-dir <dir>] [--project <dir>] [--no-mirror]
|
|
1993
2041
|
dz recall "<query>" [--limit <N>] [--domain <name>] [--semantic | --no-semantic] [--full] [--project <dir>] # hybrid lexical+vector when the vector tier is enabled; --domain BOOSTS same-domain lessons (never filters)
|
|
1994
2042
|
dz recall --all [--json] [--stats] [--include-domain <name,…>] # export the learned store (held-out domains are withheld unless named), or inspect learning stats/top uses
|
|
1995
|
-
dz recall --books "<query>" [--book <slug>] # digitized-book KUs; --book narrows to one book
|
|
2043
|
+
dz recall --books "<query>" [--book <slug>] # digitized-book KUs; --book narrows to one book. Reads via a read-only opener (ADR-001, store-readonly-reads): works from a read-only-mounted store directory (falls back to a temporary copy) and no longer writes `-wal`/`-shm` on every invocation
|
|
1996
2044
|
dz vector status [--project <dir>] [--json] # semantic tier: engine availability, mirrored vs lexical counts, pending queue
|
|
1997
2045
|
dz vector reindex [--project <dir>] [--json] # re-embed learned vectors with the CONFIGURED model + stamp the manifest (snapshot first; atomic — a mid-way failure restores the store). Warns about task types it does not own (e.g. book-knowledge → run `dz brain reindex`)
|
|
1998
2046
|
dz vector export <path> [--project <dir>] # portable VECTOR form (.rvf checkpoint; needs the opt-in RVF engine)
|
|
@@ -2001,13 +2049,13 @@ dz vector harmonize [--apply] [--threshold <0..1>] [--json] # SEMANTIC me
|
|
|
2001
2049
|
dz teach --harmonize [--apply] [--threshold <0..1>] # alias of `dz vector harmonize`
|
|
2002
2050
|
dz statusline [--json] [--install] # compact Claude Code statusline: live self-learning pattern count + brain sources
|
|
2003
2051
|
dz store-guard [--status|--reset] [--yes] [--project <dir>] # inspect the monotonic external high-water mark; --reset is the only lowering path and requires confirmation or --yes
|
|
2004
|
-
dz usage [--json] [--project <dir>]
|
|
2052
|
+
dz usage [--json] [--project <dir>] # 7-day UTC spend from local Claude Code + subagent transcripts; provider-limit routing disabled by design
|
|
2005
2053
|
--by-stage [--run <id> | --slug <s>] [--epsilon <0..1>] [--write <file.jsonl>] [--json] # per-stage cost ledger for ONE feature-adr run + reconciliation invariant (BALANCED | DEFECT | INSUFFICIENT_DATA)
|
|
2006
2054
|
dz chain [--project <dir>] [--json] # verify EVERY hash-chained journal in one command; coverage is DERIVED from the CHAINED_JOURNALS registry, so a journal cannot be chained and checked by nobody; an ABSENT journal is NAMED, never omitted; exit 1 on broken/unreadable
|
|
2007
2055
|
dz claim-check [paths...] [--json] [--fail-on high|medium|none] [--project <dir>] # enforce the Integrity Rule: flag untagged/overstated accuracy claims; default scan = READMEs + features' 08_qe_report.md; exit 1 only at/above --fail-on (default high)
|
|
2008
2056
|
dz lint [paths...] [--json] [--config <file>] [--registry <file>] [--project <dir>] # advisory EN/RU prose-style lint; findings exit 0, incomplete input/policy exits 1, usage exits 2
|
|
2009
2057
|
dz brain list [--json] # the durable cross-project knowledge brain
|
|
2010
|
-
dz brain query "<q>" [--source <slug>] [--limit <N>] [--any] [--rerank] [--json] # cross-source recall (--any = OR match; --rerank reorders on-point first). Auto-broadens: if strict all-terms match yields 0 hits, it retries once as OR and labels the result "broadened" (text note + broadened:true in --json) instead of returning empty. Explicit --any is OR from the start (never labeled broadened).
|
|
2058
|
+
dz brain query "<q>" [--source <slug>] [--limit <N>] [--any] [--rerank] [--json] # cross-source recall (--any = OR match; --rerank reorders on-point first). Auto-broadens: if strict all-terms match yields 0 hits, it retries once as OR and labels the result "broadened" (text note + broadened:true in --json) instead of returning empty. Explicit --any is OR from the start (never labeled broadened). `dz brain query`/`dz brain ground` read via the same read-only opener as `dz recall --books` — see ADR-001, store-readonly-reads.
|
|
2011
2059
|
dz brain add [--source <slug>] [--project <dir>] [--from-slice <f>|--from-pack <p>|--from-kus <f> --slug <s> --kind <k> --license <spdx> [--override]] [--json] # grow the brain
|
|
2012
2060
|
dz brain ground "<prompt>" [--k <N>] [--source <slug>] [--text] [--budget <N>] [--full] # retrieve + emit grounding citations (hook entrypoint; silent if irrelevant); --budget N eager-inlines top-K KU content within ~N tokens (chars/4 approx); --full = --budget 8000
|
|
2013
2061
|
dz brain expand <kuId> [--source <slug>] [--json] # full-content lookup by kuId — the command the grounding directive names; prints name/problem/pages/book + FULL content (untruncated)
|
|
@@ -2015,6 +2063,8 @@ dz brain init [--project <dir>] [--k <N>] # opt-in: w
|
|
|
2015
2063
|
dz brain primer <slug> [--json] # print a source's capability card (histogram + top decision moments)
|
|
2016
2064
|
dz brain export --source <slug> --out <file> # write a portable per-book KB slice (ships inside the pack, §8.1)
|
|
2017
2065
|
dz brain update <slug> [--project <dir>] [--json] # non-destructive refresh: re-mirror a re-ingested source, evict stale corpus
|
|
2066
|
+
dz brain reindex [--json] # snapshot + re-embed the brain's book-KU vectors, stamp current model; ALSO rotates the brain's own pre-reindex snapshots on success (default keep 3)
|
|
2067
|
+
dz brain snapshots [--keep <N>] [--prune] [--json] [--project <dir>] # list (default) — or, with --prune, rotate — the brain's own `agentdb.db.pre-reindex-<ms>.bak` snapshot families; reaches the same rotation WITHOUT running a reindex
|
|
2018
2068
|
dz pretrain [--project <dir>]
|
|
2019
2069
|
dz recommend "<task description>" [--json] (RU/EN lexical topics; explicit task/project-stack/none provenance)
|
|
2020
2070
|
dz compose <preset1+preset2+...> [--target <name>]
|
|
@@ -2041,7 +2091,86 @@ dz discrimination-check --test <f[,f]> [--base <ref>] [--name <filter>] [--runne
|
|
|
2041
2091
|
dz amendment-check --slug <slug> | --feature-dir <dir> | --all [--json] (every AM-N / AM-CP-N amendment row must resolve to a test found INSIDE the file the row names; the PLAN is authoritative when it carries rows, and an ideation amendment the plan drops is a failure; --all is a census that always exits 0; exit 0 pass/skip, 1 fail, 3 NOT-ESTABLISHED — ZERO parsed rows may skip only when the whole first paragraph or heading suffix is exactly "None"/"N/A"/"нет", optionally with a full stop; an optional CommonMark closing # sequence is heading furniture, qualified text is refused, and AM-like content beside the declaration is NOT-ESTABLISHED)
|
|
2042
2092
|
dz contract-check --slug <s> [--json] (read-only retrospective feature contract gate: canonical AC-N + ADR Confirmation → CC-N; every item needs one artifact-anchored met|unmet|not-testable verdict; A/B with unmet is refused; exit 0 pass / 1 readable violation / 2 invalid invocation or unreadable/not-established artifacts)
|
|
2043
2093
|
dz journal add --kind decision|verdict|run|error|block "<text>" [--ref <trace>] [--at <ISO>] [--quote <file>] [--commit-quote]; show [--day|--week] [--at <date>] [--kind <kind>] [--json] # UTC day files, witnessed append; quotes local by default
|
|
2044
|
-
dz feature-adr-record --kind ledger|training-pair --stage <s> [--slug <s>] [--row|--pair <json>] [--mark <n>] [--once] [--json] (the witnessed writer: payload as an ARGUMENT never as shell, refused before any write,
|
|
2094
|
+
dz feature-adr-record --kind ledger|training-pair --stage <s> [--slug <s>] [--row|--pair <json>] [--run-id <id>] [--mark <n>] [--once] [--json] (the witnessed writer: payload as an ARGUMENT never as shell, refused before any write; for a ledger row `ts` is ALWAYS the real write instant (a payload `ts` survives as `payloadTs`, never lost); `--run-id` fills a MISSING `runId` — absent, null, empty, or non-string — and tags it `runIdSource:'cli-flag'`; `minutesSincePrev`/`minutesSource` on an auto ledger row measure against the previous row of the same run, reporting `unavailable` on no prior row OR a corrupt/non-object ledger line anywhere in between; new fields never reorder existing ones; append verified by re-reading the tail; exit 0 written|duplicate|skipped, 2 refused, 3 not-verified, never blocking)
|
|
2095
|
+
dz round open --slug <s> --round <n|auto> --topic "<topic>" [--run <id>] [--owner-pid <n> | --owner-run <runId>] [--force] | exec --slug <s> --round <n> --brief <file> [--log <file>] [--model gpt-5.6-sol] [--effort high] [--timeout-min 30] | close --slug <s> --round <n> --outcome shipped|refuted|blocked|abandoned (--lesson teach:<id>... | --no-new-knowledge "<reason>") [--no-cost] | status [--older-than <minutes>] -- every subcommand also takes [--state-root <dir>] (or DZ_ROUND_STATE_ROOT) # open records the parent process by default; --owner-pid records a process and --owner-run records a run-registry owner; live/stalled runs are live, finished/orphaned runs are dead, and unknown registry state stays unknown; open --force refuses a live or unknown owner
|
|
2096
|
+
|
|
2097
|
+
The round owner is the session shell (`process.ppid`) by default. Under `setsid`, or in a container
|
|
2098
|
+
where that parent is PID 1, pass `--owner-pid <pid>` for the real supervising process; otherwise PID 1
|
|
2099
|
+
can make an abandoned round appear permanently owned by a live process.
|
|
2100
|
+
|
|
2101
|
+
`--state-root <dir>` (or `DZ_ROUND_STATE_ROOT=<dir>`, flag wins when both are set) names where round
|
|
2102
|
+
state (`.dz/rounds/`) AND its ledger row live — every subcommand reads/writes under this root instead
|
|
2103
|
+
of cwd when it is given. **`--project` is unrelated and stays recall-only**: `open` only ever passes
|
|
2104
|
+
it to `dz recall` for lessons, round state itself has always lived in cwd (lesson `2ac30a70`), and
|
|
2105
|
+
`--state-root` is the flag that actually redirects that state. The value must be an absolute path —
|
|
2106
|
+
a relative one is refused with exit 2 before anything is written. Without the flag or the variable,
|
|
2107
|
+
behavior is unchanged (state in cwd, exactly as before this flag existed). `open` always prints the
|
|
2108
|
+
resolved root as `state root: <dir>` (text) / `stateRoot` (JSON), so a caller never has to assume it
|
|
2109
|
+
landed in cwd; `status` prints the same `stateRoot` in JSON always, and the `state root: <dir>` text
|
|
2110
|
+
line only when `--state-root`/`DZ_ROUND_STATE_ROOT` was actually given (its default-cwd text output
|
|
2111
|
+
is otherwise unchanged, byte-for-byte, from before this flag existed).
|
|
2112
|
+
|
|
2113
|
+
Every mutation of `.dz/rounds/<slug>-<round>.json` (`open`'s archive+write, `exec`'s owner-claim and
|
|
2114
|
+
owner-restore writes, `close`'s final reread+delete) runs under ONE named lock,
|
|
2115
|
+
`<stateRoot>/.dz/locks/round-state.lock` (`withNamedLockSync`, feature round-state-lock) — two `dz
|
|
2116
|
+
round` processes sharing a `--state-root` can no longer lose each other's update. Recall (`open`) and
|
|
2117
|
+
the run-cost ledger write (`close`) stay OUTSIDE the lock — they can be slow, and the lock must not be
|
|
2118
|
+
held across anything that isn't a short, synchronous read-modify-write. `open` rereads state again
|
|
2119
|
+
UNDER the lock right before writing: if recall ran for a while and a different process opened the
|
|
2120
|
+
same round in the meantime, `open` refuses instead of silently overwriting that process's state.
|
|
2121
|
+
`status` never takes the lock (read-only) and keeps working while it is held elsewhere. Two refusals,
|
|
2122
|
+
both observable, neither one leaves a state file half-written:
|
|
2123
|
+
- **`already-open`** — a different process's state appeared while `open` was recalling: exit 1,
|
|
2124
|
+
`круг уже открыт (pid …) — состояние не перезаписано`, `--json` carries `{"refused":"already-open",
|
|
2125
|
+
"pid": <n>}`. The ORIGINAL state (the other process's) is left on disk untouched.
|
|
2126
|
+
- **`lock-busy`** — the lock could not be acquired before its deadline (another process is still
|
|
2127
|
+
inside its own critical section): exit 1, `lock busy: …`, `--json` carries `{"refused":"lock-busy"}`.
|
|
2128
|
+
Nothing is written; for `close` specifically, the run-cost ledger row is written BEFORE this lock is
|
|
2129
|
+
ever attempted (see above), so a `close` that hits `lock-busy` on its final delete has already logged
|
|
2130
|
+
the outcome — only the round's own state file is left undeleted (retry `close` to finish it).
|
|
2131
|
+
|
|
2132
|
+
**Fix-round (identity beats pid, `stateId`).** Every state `open` writes carries a `stateId` (16
|
|
2133
|
+
random hex chars) — the token `exec`/`close` compare against, not pid: `process.ppid` coincides for
|
|
2134
|
+
two `dz` launched from the same shell, and every run-owned state carries pid 0, so pid alone could
|
|
2135
|
+
not tell a genuine race from an innocent coincidence.
|
|
2136
|
+
- `open`'s recheck-under-lock now refuses on ANY raw-byte change since the pre-recall snapshot
|
|
2137
|
+
(pid is diagnostic-only in the refusal text), except a vanished file — a round closed while `open`
|
|
2138
|
+
was recalling is not a race to refuse, it is the ordinary "no existing round" case, `--force` or not.
|
|
2139
|
+
- `exec`'s claim AND owner-restore sections both refuse — leaving the file untouched — when the state
|
|
2140
|
+
under the lock is gone (`круг закрыт во время exec, владелец не менялся`) or carries a DIFFERENT
|
|
2141
|
+
`stateId` (`состояние круга заменено (stateId …), возврат владельца пропущен`); neither section ever
|
|
2142
|
+
falls back to resurrecting or overwriting with a stale pre-lock snapshot. The owner-restore lock is
|
|
2143
|
+
retried up to 3 times at the same timeout before giving up; if it still cannot recover ownership, the
|
|
2144
|
+
round is left `ownerKind: 'exec'` and the command says so in prose (`владелец круга не восстановлен
|
|
2145
|
+
(ownerKind=exec остался): повторите dz round exec для этого круга, когда блокировка освободится`) —
|
|
2146
|
+
no new flag is added for this. `open` and `status` warn on their own when a round has been sitting at
|
|
2147
|
+
`ownerKind: 'exec'` for 10+ minutes, so a stuck claim is never silently left for someone to trip over.
|
|
2148
|
+
- `close`'s final delete deletes ONLY the state instance its own ledger row was written for (matched by
|
|
2149
|
+
`stateId`): a state that vanished under the lock is `круг уже закрыт (строка леджера записана)` (exit
|
|
2150
|
+
0 — the same round reaching its own success postcondition a different way, not a failure); a state
|
|
2151
|
+
replaced by a different `stateId` is `состояние заменено, не удалено` (exit 1, never deleted). A
|
|
2152
|
+
`close` that hits `lock-busy` on the delete step now says exactly what already happened:
|
|
2153
|
+
`строка леджера записана, состояние круга осталось открытым — повторите close`, `--json` carries
|
|
2154
|
+
`{"refused":"lock-busy","ledgerWritten":true}` — and the retry is idempotent: if the ledger already
|
|
2155
|
+
carries this attempt's row (same slug/round/closedAt), the retry does not append a second one.
|
|
2156
|
+
|
|
2157
|
+
`feature-adr` is one outer round, not one round per stage. Step 0 opens it with `--round auto` and
|
|
2158
|
+
`--run fa:<slug>` plus `--owner-run <runId>` when the run-registry start receipt supplies a non-empty
|
|
2159
|
+
id, so the run registry—not the short-lived command process—owns its liveness. If that best-effort
|
|
2160
|
+
registry write fails, the workflow omits `--owner-run`, logs the fallback explicitly, and keeps round
|
|
2161
|
+
tracking under the command's ordinary explicit owner. Step 8 maps the QE grade to the outcome and
|
|
2162
|
+
closes with `--no-cost`. The existing stage ledger commands remain byte-stable and remain the only
|
|
2163
|
+
cost source, so cadence/usage readers do not count the same minutes or tokens twice. A refused close
|
|
2164
|
+
is logged and returned as `roundClosed:false` without failing the feature run.
|
|
2165
|
+
|
|
2166
|
+
In round rows, `tokens: null` means tokens were not measured; an explicit `--tokens 0` remains zero.
|
|
2167
|
+
Automatic feature-adr stage rows keep total `tokens` null and record the measurable partial cost as
|
|
2168
|
+
`tokensOut`, with `tokensOutSource` naming `budget.spent` or `unavailable`.
|
|
2169
|
+
|
|
2170
|
+
When `args.dzBin` is supplied, feature-adr uses it without a selection/version agent call and logs
|
|
2171
|
+
version `not probed (dzBin given)`. With no `dzBin`, binary selection costs no more than **3 additional
|
|
2172
|
+
agent calls**: up to 2 `probeSessionCwd` attempts when the workspace is not yet known, plus 1 combined
|
|
2173
|
+
probe that both selects the workspace build or PATH fallback and prints the selected binary's version.
|
|
2045
2174
|
dz runs [--settle] [--stall-minutes N] [--json] [--project <dir>] (read the run registry: live / stalled / orphaned / inconclusive / finished)
|
|
2046
2175
|
dz runs-record --event started|heartbeat|finished [--run-id <id>] [--kind <kind>] [--slug <slug>] [--pid <pid|host>] [--parent-run-id <id>] [--outcome <text>] [--project <dir>] [--json] (append one run event)
|
|
2047
2176
|
dz runs-clean [--apply] [--retention-days N] [--project <dir>] [--json] (plan cleanup of old clean merged worktrees and dead/finished registry histories; apply explicitly)
|
|
@@ -2056,7 +2185,7 @@ dz epoch-replay --judge <filled-work-order.json> [--out <file>] [--json] # bli
|
|
|
2056
2185
|
dz epoch-replay --score <judgments.json> --work-order <file> [--slice <name>] [--json] # un-blind against the VERIFIED pre-registered assignment; ONE paired binomial over DECISIVE pairs (ties excluded, reported) → SUPPORTED only when the lift interval (2p−1) lies entirely above zero; FALSIFIED only on harm or a passed non-superiority test (lift upper bound below the margin PRE-REGISTERED in the work order, default 0.05, at 10+ decisive pairs); else INCONCLUSIVE (min 5 decisive pairs). Refuses a forged work order, a --margin flag, or duplicate judgement ids; the verdict is data, not an exit code
|
|
2057
2186
|
dz score --slug <feature> [--project <dir>] [--json] # process scorecard for ONE feature-adr run, from its artifacts: ADR confirmation, discrimination proof, cross-model QE grade, live verification, README-first, learning loop, amendments — DESCRIPTIVE-ONLY (a low score exits 0); evidence lines are shown so the reader judges the heuristics
|
|
2058
2187
|
dz recap [--day|--week|--month] [--at <ISO date>] [--refresh-publishes] [--project <dir>] [--json] # what was done over a window, from records only. `--refresh-publishes` fills the third-party publish-times cache first (the ONLY place this command touches the network — 51 packages in ~7s, batches of 8); the report itself always reads the cache, prints its AGE, and names any package the registry did not answer for: those are MISSING from the numbers, not zero. Deliveries carry the grade an independent review STATED — a report naming two different grades is reported AMBIGUOUS, never guessed; registry publishes come from a cache (51 packages cost 18.3s over the network, MEASURED — never inside a report); gate verdicts and knowledge reuse come from the local stores. --quarter/--half-year/--year are RECOGNISED and REFUSED with the real span in days: there is exactly ONE complete quarter and the longest record is 174 days, so a quarter-over-quarter comparison is arithmetically impossible and a year would be fabrication. Every section carries its own data-start date, and "the source was not read" never prints as a zero. Contaminated measures are NOT computed and the report says so: commit count (this project mandates a commit per logical change), lines changed (352 of 1318 commits are docs), token spend (self-declared an estimate, once wrong sixfold), learning-event volume (the curve tracks when hooks were installed), inventory counts (monotonic — they can only flatter), lesson count (54% of the pool has never been read). exit 0 reported / 2 refused
|
|
2059
|
-
dz cadence [--window day|week|month|quarter|halfyear|year] [--json] # the RHYTHM view of what shipped: graded-shipment counts bucketed by ISO week, npm-publish cadence (reads `dz recap`'s publish-times cache — run `dz recap --refresh-publishes` to warm it), guard repeat DECAY on the FIXED rule set (a rule joins only with pre-window history, so a newborn rule's zero is youth, not virtue — the no-stubs false-zero class excluded by construction), and recall reuse per week. A window deeper than 2× the record is REFUSED with the measured depth and the largest honest window named (a cadence from under two full windows is scale forgery). Sibling of `dz recap`: recap is the narrative what-was-done report over one window; cadence is the week-by-week rhythm across the window. exit 0 / 2 refused-window / 1 usage
|
|
2188
|
+
dz cadence [--window day|week|month|quarter|halfyear|year] [--json] # the RHYTHM view of what shipped: graded-shipment counts bucketed by ISO week, round/round-exec outcomes with every unfinished round named, packages/ commits in the window (`not measured` when git is unavailable), npm-publish cadence (reads `dz recap`'s publish-times cache — run `dz recap --refresh-publishes` to warm it), guard repeat DECAY on the FIXED rule set (a rule joins only with pre-window history, so a newborn rule's zero is youth, not virtue — the no-stubs false-zero class excluded by construction), and recall reuse per week. A window deeper than 2× the record is REFUSED with the measured depth and the largest honest window named (a cadence from under two full windows is scale forgery). Sibling of `dz recap`: recap is the narrative what-was-done report over one window; cadence is the week-by-week rhythm across the window. exit 0 / 2 refused-window / 1 usage
|
|
2060
2189
|
dz profile init | show | set <field> <value> | sync [--target claude] # WHO is being talked to. Per-USER store ~/.dz/profile.json (0600, never under a project root), delivered as a marked block in ~/.claude/CLAUDE.md so it loads in EVERY project on the machine, dz installed or not. Two axes: default register (pro | pro-lite | plain; RU aliases профи / профи лайт / просто) and named domains that move it — `deep` = full pro no scaffolding, `weak` = one plain sentence EVERY time unprompted, MANDATORY there. Three fixed rules ride along and the register cannot override them: an explanation is SELF-CONTAINED (every term glossed at first use in THIS passage), the register governs dialogue and owner-facing surfaces but NEVER ADRs / commits / QE reports / npm READMEs, and it changes FORM not FACTS. `show` always prints the store path and the profile's age; an unknown register value is REFUSED naming the accepted set, never silently defaulted; a hand-edited block is reported as drift and `sync` repairs it with a timestamped backup, foreign content preserved byte-for-byte. Redacted from training-pair capture (.dz/fa-training/ records the full prompt and is deliberately not gitignored)
|
|
2061
2190
|
dz qe-rounds (--slug <feature> | --feature-dir <abs>) [--ceiling <n>] [--project <dir>] [--json] # how many Step-8 review rounds has this feature ALREADY had? The rule "Max iterations: 3" lived only as a sentence in a prose module, so every restart of the agent forgot it — MEASURED, one real slug reached 38 graded rounds. Reads what `dz qe-bridge` already wrote (signoff-<runId>.json / failed-*.json under features/<slug>/.fa-state/qe-bridge) and writes NOTHING itself, so it answers for runs already past. A round is a runId, not a file; an attempt with no verdict is counted separately and never merged; ONE directory, never a union across checkouts. FAILS CLOSED: if any record cannot be counted the verdict is NOT ESTABLISHED, never a smaller number presented as the answer. exit 0 under the ceiling / 1 at-or-over — the owner decides, this never judges whether the rounds were warranted / 2 NOT ESTABLISHED, which is never "zero rounds"
|
|
2062
2191
|
dz restart-advisor --slug <feature> [--threshold C|D] [--rounds <n>] [--json] # manual, read-only advice over this feature's QE history. Defaults: threshold D, rounds 2. Reads only features/<slug>/.fa-state/checkpoints.jsonl and .dz/fa-training/<slug>/qe.jsonl; when both carry QE rounds they must normalize identically and are never unioned. RESTART_CODE_STAGE is a recommendation for the operator, not an action: autoAction is always false, and every firing result includes an explicit decision-log line. exit 0 established recommendation/no-recommendation / 2 invalid or not established / 1 unexpected runtime failure
|
|
@@ -2071,12 +2200,12 @@ dz backlog <sub> add "<idea>" | list | show <id> | goals [--validate] | roul
|
|
|
2071
2200
|
dz sign --init --out <path> | --pack <dir> --key <path> # --init: generate the Ed25519 keypair (private OUTSIDE the repo, prints the public key for keys/dz.pub); else sign a pack's manifest + CycloneDX SBOM
|
|
2072
2201
|
dz sbom --pack <dir> [--out <file>] # emit the CycloneDX 1.5 SBOM for a pack standalone (file-level bill of materials); print to stdout or write to a file
|
|
2073
2202
|
dz verify-pack --pack <dir> [--pubkey <path>] # signature check of a pack: fail-closed, and the trust root comes from the repo, never from the pack it is verifying
|
|
2074
|
-
dz guard check --op <publish|teach|consolidate|reindex> [--text <s>] [--json] [--force <reason>] # declarative constraint layer before self-mutating ops: HARD violation → block (exit 1), SOFT → warn; zero-config defaults, .dz/guard.json to customise; dz guard --init | dz guard log (append-only audit). dz publish runs it automatically (--no-guard "<reason>" = logged escape hatch)
|
|
2203
|
+
dz guard check --op <publish|teach|consolidate|reindex> [--text <s>] [--json] [--force <reason>] # declarative constraint layer before self-mutating ops: HARD violation → block (exit 1), SOFT → warn; zero-config defaults, .dz/guard.json to customise; dz guard --init | dz guard log (append-only audit). The built-in SOFT `rounds-traced` rule warns at 10 packages/ commits since the latest round receipt (or the ledger's first row when no round exists); a null git fact is `not measured`, and `.dz/config.json` `rounds.traced:false` is a named skip. dz publish runs it automatically (--no-guard "<reason>" = logged escape hatch)
|
|
2075
2204
|
dz guard promote [--dry-run | --apply] [--window-days <N>] [--periods <N>] [--json] # lesson → guard-rule promotion: ranks lessons by firings × cost, SHADOW-replays each candidate over real commits, and proposes a rule only after TWO consecutive wins AND two window-lengths of REAL elapsed time since first observation. Non-dry runs add bounded prospective funnel evidence to .dz/promotion-state.json without feeding the verdict; --dry-run remains write-free. --apply installs SOFT rules only; promotions/refusals remain under features/guard-promotion/promotions/
|
|
2076
2205
|
dz feature-adr-setup --guards [--loc-cap <n>] [--apply] # P3: scaffold DETERMINISTIC guard tests into the project — guards.config.json + a zero-dependency check.mjs runner (LOC cap, secret scan, frozen-file sha256 pins, waivers-with-reasons); wire `node architecture/guards/check.mjs` into CI
|
|
2077
|
-
dz publish [--filter <name>] [--bump-only] [--claim-check <off|warn|error>] [--mirror-cmd <cmd>|--no-mirror] (dry-run by default; pass --yes/--confirm to go live; a configured mirror must return a live receipt or the published run exits 3; config: publish.mirrorCommand)
|
|
2206
|
+
dz publish [--filter <name>] [--bump-only] [--claim-check <off|warn|error>] [--mirror-cmd <cmd>|--no-mirror] [--allow-sibling-drift] [--include-drifted] (dry-run by default; pass --yes/--confirm to go live; a configured mirror must return a live receipt or the published run exits 3; config: publish.mirrorCommand; sibling-drift + packed-install-smoke gates, feature publish-sibling-drift-gate, ADR-001 — a workspace sibling whose registry build differs blocks with a `--filter <batch>,<S>` fix-it, --allow-sibling-drift overrides (logged to .dz/guard-audit.jsonl), --include-drifted auto-extends the batch; the whole batch is packed + installed together and every bin runs `--version`, exit 0 + non-empty stdout required)
|
|
2078
2207
|
dz parity [--target <name>] [--json] # honest feature×target map COMPUTED from the capability model — full / manual (via which form) / absent, per target
|
|
2079
|
-
dz release [--filter <name>] [--affected] [--audit-dev] [--tag] [--publish] [--json] [--dry-run] [--no-issue] # VERIFIED release: 4 HARD gates in front of dz publish — package test suites, pnpm audit --prod >=high (--audit-dev widens), node --check of every dist/bin file (unbuilt package with a build script ⇒ MISSING_DIST fail), bin smoke-boot "node <bin> --help" (temp cwd + timeout); --affected narrows to git-touched packages (fail-open); any red gate STOPS the release (exit 1) + best-effort gh issue; green ⇒ re-sign reminder, then the ready dz publish command (never with --yes injected)
|
|
2208
|
+
dz release [--filter <name>] [--affected] [--audit-dev] [--tag] [--publish] [--json] [--dry-run] [--no-issue] # VERIFIED release: 4 HARD gates in front of dz publish — package test suites, pnpm audit --prod >=high (--audit-dev widens), node --check of every dist/bin file (unbuilt package with a build script ⇒ MISSING_DIST fail), bin smoke-boot "node <bin> --help" (temp cwd + timeout), packed-install smoke (same rule as dz publish's, feature publish-sibling-drift-gate — pack the batch, install together, `--version` every bin) when the set has a bin; --affected narrows to git-touched packages (fail-open); any red gate STOPS the release (exit 1) + best-effort gh issue; green ⇒ re-sign reminder, then the ready dz publish command (never with --yes injected)
|
|
2080
2209
|
dz auto-canonicalize --source <github-url> --pack <skills-pack>
|
|
2081
2210
|
dz sync-upstream [--package <dir>] [--list] [--all]
|
|
2082
2211
|
dz drift-check [--all] [--json] [--project <dir>] # CI gate: exit 1 on NEW shared-skill drift (baseline: .dz/drift-allowlist.json; --all incl .claude dogfood)
|
|
@@ -2101,7 +2230,7 @@ dz import-ecc [--local-path <dir>] [--select id,id,...] [--limit N] [--out
|
|
|
2101
2230
|
```
|
|
2102
2231
|
|
|
2103
2232
|
Built-in, not a command: `dz help` prints this same USAGE and is handled before the dispatch switch,
|
|
2104
|
-
so `dz --help` lists
|
|
2233
|
+
so `dz --help` lists 93 names while the canonical inventory above holds 92 (ADR-001 of feature
|
|
2105
2234
|
`command-count-triad`).
|
|
2106
2235
|
|
|
2107
2236
|
**Adding a command — the whole checklist, in order.** It replaces the seven-place folklore that used
|
|
@@ -2244,27 +2373,25 @@ echo "how do I handle replication lag?" | dz brain ground --budget 2000 # eage
|
|
|
2244
2373
|
|
|
2245
2374
|
### Live self-learning panel (`dz statusline`)
|
|
2246
2375
|
|
|
2247
|
-
The
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
store guard reads it as an integrity signal, and narrowing it would look like a store collapse.
|
|
2255
|
-
The JSON payload exposes these warnings as `patternMirror`; parity omits that field. Both surfaces
|
|
2256
|
-
carry the indicator — the combined panel helper and `dz statusline` itself.
|
|
2376
|
+
The panel always names the mirror: `mirror: N lessons (pending M)` when readable, or `mirror: absent` when it is not configured.
|
|
2377
|
+
Its JSON `mirror` section reports `{available, rows, lessons, pending, source:'agentdb'}`; `patternMirror` compares only mirrorable lexical lessons and reports class/noise exclusions.
|
|
2378
|
+
|
|
2379
|
+
A mirror that EXISTS but cannot be read remains a distinct degraded state (`mirror: unreadable ⚠`).
|
|
2380
|
+
Mirror lesson counts exclude backlog ideas and book units, while the lexical comparison also excludes
|
|
2381
|
+
class lessons and noise rejected by the writer. `vectorRows` remains the full physical count because
|
|
2382
|
+
the store guard consumes it as an integrity signal.
|
|
2257
2383
|
|
|
2258
2384
|
`dz statusline` renders a compact Claude Code statusline that surfaces dz's learning at a glance:
|
|
2259
2385
|
|
|
2260
2386
|
```
|
|
2261
|
-
🎓 dz: 12 (9 active · 3 quarantined)
|
|
2387
|
+
🎓 dz: 12 (9 active · 3 quarantined) · mirror: 11 lessons (pending 1) · 🧠 3 sources (223/315/60)
|
|
2262
2388
|
```
|
|
2263
2389
|
|
|
2264
|
-
The parenthesized split is read
|
|
2390
|
+
The parenthesized split is read from the primary lexical store; its JSON source is `lexical+mirror`
|
|
2391
|
+
when the mirror is readable and `lexical` otherwise. A row is quarantined exactly
|
|
2265
2392
|
when parsed metadata has `qStatus: "quarantined"`; historical fields do not count. The quarantine
|
|
2266
2393
|
fragment is omitted at zero, `⚠` appears at one third of the pool, and `⚠ tiers ΔN` reports a
|
|
2267
|
-
quarantine-label difference greater than five rows
|
|
2394
|
+
quarantine-label difference greater than five rows across the mirrorable populations. `M sources` is how many
|
|
2268
2395
|
brain sources (book-KBs / grounding stores) are wired, and the parenthesised list after it gives the
|
|
2269
2396
|
KU volume of EACH source in brain order — four sources of 300 units and four of three read
|
|
2270
2397
|
identically without it. The list is omitted (bare source count) when the volumes cannot be
|
|
@@ -2426,75 +2553,36 @@ the exact `dz store-guard --reset --project '<dir>'` command. `--status` and gua
|
|
|
2426
2553
|
selected lexical source; when both SQLite and JSONL exist they also name the ignored JSONL row count.
|
|
2427
2554
|
The snapshot helper supports both lexical formats.
|
|
2428
2555
|
|
|
2429
|
-
### Usage
|
|
2430
|
-
> **Pin the weekly reset to an ABSOLUTE instant.** `weeklyResetAnchor: "Wed 08:59"` is
|
|
2431
|
-
> server-timezone-relative — measured: the same moment lands a week apart under UTC vs `+03:00`, so
|
|
2432
|
-
> after a real account reset the counter can keep showing the OLD week for hours while printing the
|
|
2433
|
-
> "correct" clock time. Add your offset: `"Wed 08:59 +03:00"` in `.dz/config.json` — the boundary
|
|
2434
|
-
> then never moves with the machine's timezone, and `dz usage` prints the full anchor
|
|
2435
|
-
> (`resets Wed 08:59 +03:00`). Without an offset it warns on every run.
|
|
2556
|
+
### Usage spend (`dz usage`)
|
|
2436
2557
|
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
counts use the active fixed-length transcript block (`memory.usage.sessionBlockHours`, normally `5`).
|
|
2558
|
+
`dz usage` prints a READONLY, never-throw spend report over the last seven UTC calendar days,
|
|
2559
|
+
aggregated from local `~/.claude/projects/**/*.jsonl` Claude Code and subagent transcripts. Every day
|
|
2560
|
+
shows weighted tokens, raw input/output/cache-read/cache-write tokens, and event count; the report
|
|
2561
|
+
also carries a seven-day total and cost-weighted model shares.
|
|
2442
2562
|
|
|
2443
2563
|
```bash
|
|
2444
|
-
dz usage
|
|
2445
|
-
dz usage --json
|
|
2446
|
-
```
|
|
2447
|
-
|
|
2448
|
-
**Exit code is 0 ALWAYS** (even unconfigured/error → all-null JSON) — a probe must never distinguish
|
|
2449
|
-
"usage unknown" from "command failed" via a non-zero exit. Percentages are **ESTIMATES** from local
|
|
2450
|
-
transcripts; claude.ai/settings/usage is authoritative. They are `null` until you configure the
|
|
2451
|
-
plan-dependent limits in `.dz/config.json`:
|
|
2452
|
-
|
|
2453
|
-
```json
|
|
2454
|
-
{
|
|
2455
|
-
"memory": {
|
|
2456
|
-
"usage": {
|
|
2457
|
-
"sessionTokenLimit": 200000000,
|
|
2458
|
-
"weeklyTokenLimit": 1000000000,
|
|
2459
|
-
"weeklyResetAnchor": "Wed 08:59",
|
|
2460
|
-
"sessionBlockHours": 5,
|
|
2461
|
-
"weeklyTokenLimitByModel": { "fable": 500000000 }
|
|
2462
|
-
}
|
|
2463
|
-
}
|
|
2464
|
-
}
|
|
2564
|
+
dz usage
|
|
2565
|
+
dz usage --json
|
|
2465
2566
|
```
|
|
2466
2567
|
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
when it has at least one valid model limit (`fable`, `opus`, `sonnet`, or `haiku`), `weeklyPct` is the
|
|
2470
|
-
binding per-model percentage and `--json` adds:
|
|
2568
|
+
The weighting is input `1x`, five-minute cache write `1.25x`, one-hour cache write `2x`, cache read
|
|
2569
|
+
`0.1x`, and output `5x`. The JSON contract is:
|
|
2471
2570
|
|
|
2472
2571
|
```json
|
|
2473
2572
|
{
|
|
2474
|
-
"
|
|
2475
|
-
"
|
|
2573
|
+
"sessionPct": null,
|
|
2574
|
+
"weeklyPct": null,
|
|
2575
|
+
"routing": "disabled-by-design",
|
|
2576
|
+
"spend": { "days": [], "total7d": {}, "byModel": {} },
|
|
2577
|
+
"reqeDue": 0
|
|
2476
2578
|
}
|
|
2477
2579
|
```
|
|
2478
2580
|
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
```bash
|
|
2485
|
-
dz usage --calibrate --session 20 --weekly 50 --model fable=76 --project .
|
|
2486
|
-
```
|
|
2487
|
-
|
|
2488
|
-
It computes each limit as `currentTokens / (pct / 100)`, writes only `memory.usage` in
|
|
2489
|
-
`.dz/config.json`, and records `calibratedAt` plus `source: "claude.ai/settings/usage"`. Invalid
|
|
2490
|
-
percentages, unknown models, missing transcripts, and zero-token calibration requests are skipped with
|
|
2491
|
-
exit code `0`.
|
|
2492
|
-
|
|
2493
|
-
This feeds `/feature-adr`'s **usage-adaptive routing** — the pipeline probes `dz usage --json` at each
|
|
2494
|
-
phase boundary and pre-emptively routes the remaining stages to Codex when `sessionPct` or the binding
|
|
2495
|
-
`weeklyPct` crosses the threshold (default 70%). **Honest caveat:** at TRUE exhaustion even the Codex
|
|
2496
|
-
dispatch dies (`codex:codex-rescue` is a Claude wrapper), so the switch must happen BEFORE — the
|
|
2497
|
-
pre-emptive probe, not reactive detection, is the real defense.
|
|
2581
|
+
The percentage keys deliberately remain present and always `null` for the existing feature-adr probe.
|
|
2582
|
+
Provider limits are not measurable locally: there is no provider usage API, weekly resets are tied to
|
|
2583
|
+
an account, and ad-hoc resets invalidate a learned denominator. `--calibrate` was removed and returns
|
|
2584
|
+
exit `2` with that reason. Existing `.dz/config.json` limit fields are neither read for this report nor
|
|
2585
|
+
modified.
|
|
2498
2586
|
|
|
2499
2587
|
### Claim check (`dz claim-check`)
|
|
2500
2588
|
|
|
@@ -3135,6 +3223,61 @@ dz publish --filter skills-devops # publish specific package
|
|
|
3135
3223
|
dz publish --filter skills-devops --bump-only # bump version only, no publish
|
|
3136
3224
|
```
|
|
3137
3225
|
|
|
3226
|
+
#### Sibling-drift + packed-install-smoke gates (feature `publish-sibling-drift-gate`, ADR-001)
|
|
3227
|
+
|
|
3228
|
+
`workspace:^`/`workspace:~`/`workspace:*` pins a sibling dependency to the exact version on disk —
|
|
3229
|
+
but the REGISTRY under that version can carry an OLDER build if the sibling changed without a
|
|
3230
|
+
version bump (the 2026-09-13 incident: 15 minutes of a broken `@dzhechkov/harness-cli` on npm). Two
|
|
3231
|
+
HARD gates catch this before anything ships, and both run on `--dry-run` too — a dry run ALWAYS
|
|
3232
|
+
prints both verdicts, even once sibling-drift already blocks (no gate goes silent because an
|
|
3233
|
+
earlier one failed):
|
|
3234
|
+
|
|
3235
|
+
1. **Sibling drift.** For every workspace `S` a batch package depends on (`dependencies`,
|
|
3236
|
+
`peerDependencies` AND `optionalDependencies` — all three pin and ship identically) that is NOT
|
|
3237
|
+
itself part of the batch, the gate hashes `S`'s published inventory — `dist/**`, every path
|
|
3238
|
+
named in `package.json#files`, and every `bin` target (not `dist/**` alone: a changed bin script
|
|
3239
|
+
or template outside `dist/` is drift too) — plus a normalized `package.json` (version/gitHead/
|
|
3240
|
+
`_*`/`imports`/`browser`/`sideEffects`/`man` compared, not just entry points) against the
|
|
3241
|
+
workspace copy. A mismatch blocks; anything this gate cannot build — a fetch that fails
|
|
3242
|
+
(offline, 404), an unreadable/invalid `package.json` on either side, or a `workspace:`-spec'd
|
|
3243
|
+
name it does not recognize — is `unavailable` and blocks too; `unavailable` is never silently
|
|
3244
|
+
treated as a pass. `--include-drifted` auto-extends the batch and RE-CHECKS the expanded batch's
|
|
3245
|
+
own new edges until nothing new drifts (a fixed point over transitive drift, capped at the
|
|
3246
|
+
package count) — a folded-in sibling that itself depends on a drifted sibling is not missed.
|
|
3247
|
+
2. **Packed-install smoke.** The batch's `.tgz` files are installed TOGETHER into a clean directory
|
|
3248
|
+
(siblings outside the batch resolve from the registry — exactly like a fresh user), then every
|
|
3249
|
+
declared `bin` — including one whose target file turns out NOT to exist after the install,
|
|
3250
|
+
which blocks with `declared bin missing after packed install` rather than silently reading as
|
|
3251
|
+
n/a — runs `--version` and must exit 0 with non-empty stdout. On a **live** publish this gate
|
|
3252
|
+
packs each package's tarball exactly ONCE, right after its own version bump — the SAME bytes are
|
|
3253
|
+
then smoke-tested and handed to `npm publish <tgz>`; their sha256 is printed
|
|
3254
|
+
(`tarball <pkg>@<ver> sha256:<hex>`) and written to `.dz/guard-audit.jsonl` alongside every
|
|
3255
|
+
pass/block/override/n-a verdict, so "the smoke tested what shipped" is a checkable claim rather
|
|
3256
|
+
than an architectural one. `dz release --dry-run` plans the same steps inside its `smoke` gate
|
|
3257
|
+
(`smoke:packed-install:*`) and `dz release`'s own execution judges the `--version` step through
|
|
3258
|
+
the identical rule — the two doors apply one rule, for real, not only on paper.
|
|
3259
|
+
|
|
3260
|
+
```bash
|
|
3261
|
+
dz publish --filter harness-cli # ✓ sibling drift: none / ✓ packed install smoke, or BLOCKED with a fix-it command
|
|
3262
|
+
dz publish --filter harness-cli --allow-sibling-drift # override (logged to .dz/guard-audit.jsonl) — refused if the audit write itself fails
|
|
3263
|
+
dz publish --filter harness-cli --include-drifted # auto-extend the batch (transitively) with the drifted sibling(s) instead of blocking
|
|
3264
|
+
```
|
|
3265
|
+
|
|
3266
|
+
A BLOCKED sibling-drift verdict always names the fix: `add S to the batch (--filter <batch>,<S>) or
|
|
3267
|
+
publish it first`.
|
|
3268
|
+
|
|
3269
|
+
```
|
|
3270
|
+
$ dz publish --filter harness-cli
|
|
3271
|
+
dz publish: BLOCKED harness-cli — sibling drift: @dzhechkov/memory@0.2.20 on the registry differs from the workspace (3 file(s)); add @dzhechkov/memory to the batch (--filter harness-cli,@dzhechkov/memory) or publish it first
|
|
3272
|
+
dz publish: refusing to publish (1 sibling-drift violation(s))
|
|
3273
|
+
|
|
3274
|
+
$ dz publish --filter harness-cli --yes
|
|
3275
|
+
dz publish: tarball @dzhechkov/harness-cli@0.8.24 sha256:9f2c…e10a
|
|
3276
|
+
dz publish: ✓ packed install smoke
|
|
3277
|
+
✓ @dzhechkov/harness-cli 1.0.0 → 1.0.1 published (confirmed by registry after 1 probes)
|
|
3278
|
+
sha256:9f2c…e10a
|
|
3279
|
+
```
|
|
3280
|
+
|
|
3138
3281
|
### dz auto-canonicalize — discover skills in GitHub repos
|
|
3139
3282
|
|
|
3140
3283
|
```bash
|
|
@@ -3416,6 +3559,136 @@ dz setup --target claude-code --preset devops --memory agentdb # AgentDB (vect
|
|
|
3416
3559
|
| **MCP tools** | 0 | pattern, reflexion, causal, skill, hierarchy (whatever the pinned `agentdb` build exposes — `dz` hardcodes no count) |
|
|
3417
3560
|
| **Dependencies** | None | agentdb (optional, via npx) |
|
|
3418
3561
|
|
|
3562
|
+
### Repeat setup — the backend comes from your config, not from a forgotten flag
|
|
3563
|
+
|
|
3564
|
+
**A plain `dz setup --target claude-code` re-run (no `--memory`) now keeps the backend `.dz/config.json`
|
|
3565
|
+
already names — a repeat setup takes the backend from your config; downgrading to jsonl needs an
|
|
3566
|
+
explicit `--memory jsonl`.** Before this feature, a repeat `dz setup --target claude-code` with no
|
|
3567
|
+
`--memory` decided the backend as "`--memory` or jsonl" and silently reset an agentdb project back
|
|
3568
|
+
to jsonl, dropping `.dz/agentdb-writer.mjs` from the `SessionStart` hook — the config still said
|
|
3569
|
+
`agentdb`, the hooks quietly stopped writing to it.
|
|
3570
|
+
|
|
3571
|
+
| You run | `.dz/config.json` before | Result |
|
|
3572
|
+
|---|---|---|
|
|
3573
|
+
| `dz setup --target claude-code` | `memory.backend: "agentdb"` | stays **agentdb** — hooks/writer untouched, byte-identical to the flagged run |
|
|
3574
|
+
| `dz setup --target claude-code --memory agentdb` | anything, or absent | **agentdb** (explicit, unchanged from before) |
|
|
3575
|
+
| `dz setup --target claude-code --memory jsonl` | `memory.backend: "agentdb"` | **downgrades to jsonl** — printed loudly: `⚠ memory backend downgraded agentdb → jsonl by --memory jsonl`; the config is rewritten to jsonl too (even without `--force`), so the two never disagree |
|
|
3576
|
+
| `dz setup --target claude-code` | no config yet | **jsonl** (the documented default — unchanged) |
|
|
3577
|
+
|
|
3578
|
+
Every run also prints where the backend came from, e.g. `memory backend: agentdb (from
|
|
3579
|
+
.dz/config.json)` / `memory backend: jsonl (from --memory)` / `memory backend: jsonl (default — no
|
|
3580
|
+
.dz/config.json)` — never left to be inferred from the flag alone.
|
|
3581
|
+
|
|
3582
|
+
`dz doctor` cross-checks the two truths too: a new `memory hooks match config` row goes red when
|
|
3583
|
+
`.dz/config.json`'s `memory.backend` and the ACTUAL `SessionStart`/`SessionEnd`/`PreCompact` hooks in
|
|
3584
|
+
`.claude/settings.json` disagree in either direction, naming the exact fix (`run: dz setup --target
|
|
3585
|
+
claude-code --memory agentdb`, or the jsonl equivalent).
|
|
3586
|
+
|
|
3587
|
+
### The apply leg — `dz setup --memory agentdb` installs the whole loop, not two of three
|
|
3588
|
+
|
|
3589
|
+
Self-learning is a three-leg loop: **collect** (session hooks write into the store above),
|
|
3590
|
+
**rank** (`dz teach` / `dz recall` / `dz consolidate` score and retrieve), and **apply** (a
|
|
3591
|
+
`UserPromptSubmit` hook injects the top-ranked lessons back into your next prompt, automatically).
|
|
3592
|
+
Before this feature `dz setup` shipped the first two legs only — the apply leg's files existed
|
|
3593
|
+
solely in this repo's own `.claude/helpers/`, so every OTHER project that ran `dz setup --memory
|
|
3594
|
+
agentdb` got collection and ranking, but never automatic recall (MEASURED: a clean install wrote no
|
|
3595
|
+
`UserPromptSubmit` entry at all, on 0.8.10 and 0.8.24 alike, with or without `--memory agentdb`).
|
|
3596
|
+
|
|
3597
|
+
`dz setup --target claude-code --memory agentdb` now installs all three, additively (a repeat run
|
|
3598
|
+
changes nothing; a foreign hook you wrote yourself is left exactly where it is):
|
|
3599
|
+
|
|
3600
|
+
| What | Where | Purpose |
|
|
3601
|
+
|---|---|---|
|
|
3602
|
+
| `recall-hook.cjs` | `.claude/helpers/` | `UserPromptSubmit` hook — asks the embed daemon for relevant lessons, injects them as prompt context, silent when nothing clears the relevance floor |
|
|
3603
|
+
| `dz-embed-daemon.mjs` | `.claude/helpers/` | Resident embedding daemon behind a unix socket — keeps the ~1.5 s model-load cost off every single prompt |
|
|
3604
|
+
| `UserPromptSubmit` entry | `.claude/settings.json` | Runs the recall hook (`node ".../recall-hook.cjs" 2>/dev/null \|\| true` — a broken hook never blocks a prompt) |
|
|
3605
|
+
| `SessionStart` entry | `.claude/settings.json` | Spawns the embed daemon detached (`sh -c 'nohup node ".../dz-embed-daemon.mjs" ... & exit 0'`) |
|
|
3606
|
+
|
|
3607
|
+
The hook resolves your harness-core installation by an ABSOLUTE PATH baked in at `dz setup` time
|
|
3608
|
+
(the installation actually running the command), first in its candidate list — no more guessing at
|
|
3609
|
+
`/usr/lib/node_modules/...`, which silently failed on any other npm prefix (nvm, `/usr/local`, a
|
|
3610
|
+
global install elsewhere). Project-local candidates (`node_modules/`, a monorepo checkout) stay as
|
|
3611
|
+
fallbacks after it.
|
|
3612
|
+
|
|
3613
|
+
**On the jsonl backend** (no `--memory agentdb`) the step reports `skipped` with the reason named —
|
|
3614
|
+
the embed daemon needs agentdb's transitive `@huggingface/transformers`/`@xenova/transformers`
|
|
3615
|
+
dependency, which jsonl mode never installs. This is an honest boundary, not a missing feature: run
|
|
3616
|
+
`dz setup --memory agentdb` when you want the automatic apply leg.
|
|
3617
|
+
|
|
3618
|
+
**Memory footprint and idle lifecycle.** OWNER-MEASURED: the resident embed daemon holds ~1.0 GB
|
|
3619
|
+
RSS with only 7 patterns loaded — the multilingual embedding model dominates that number, not the
|
|
3620
|
+
pattern count, so it does not grow materially with a larger store. The recommended mental model is
|
|
3621
|
+
"spawns on session start, exits after 30 minutes idle" (`DZ_EMBED_IDLE_MS`, default
|
|
3622
|
+
`30 * 60 * 1000`) — not "runs forever": a machine that cannot spare ~1 GB resident for a background
|
|
3623
|
+
process should stay on the jsonl backend rather than tune the idle window down to zero, since `0`
|
|
3624
|
+
(or a negative/non-numeric value) now DISABLES the idle exit entirely (issue #10 defect 7) rather
|
|
3625
|
+
than exiting immediately — the daemon is meant to be reaped by inactivity, not pinned forever by a
|
|
3626
|
+
misconfigured knob. A value above Node's 32-bit `setTimeout` ceiling (2 147 483 647 ms, ~24.9 days)
|
|
3627
|
+
is clamped to that ceiling with a logged line (`idle clamp: <value> -> 2147483647 ms`) instead of
|
|
3628
|
+
silently wrapping to ~1 ms — the pre-fix bug that made a "30 days" idle setting exit in about a
|
|
3629
|
+
second.
|
|
3630
|
+
|
|
3631
|
+
**`dz doctor` and `dz parity` measure this, they don't declare it.** Both read the SAME
|
|
3632
|
+
`applyLegStatus(root)` function — a plain filesystem check (do the two files exist? does
|
|
3633
|
+
`settings.json` reference them?) — so neither can say "installed" about a project that only has the
|
|
3634
|
+
memory backend configured:
|
|
3635
|
+
|
|
3636
|
+
```bash
|
|
3637
|
+
dz setup --target claude-code --memory agentdb # installs all three legs
|
|
3638
|
+
dz doctor # apply-leg installed: ✓ (or a red row naming: dz setup --target claude-code --memory agentdb)
|
|
3639
|
+
dz parity --target claude-code # ✓ Self-learning: automatic apply-leg via UserPromptSubmit hook (auto recall)
|
|
3640
|
+
```
|
|
3641
|
+
|
|
3642
|
+
Without the apply leg installed, `dz doctor` prints a RED `apply-leg installed` check with the
|
|
3643
|
+
exact fix command, and `dz parity`'s `learning-apply` row for `claude-code` reads `◐ manual` with
|
|
3644
|
+
`not installed — run dz setup --target claude-code --memory agentdb` — never a silent `✓` read off
|
|
3645
|
+
a capability table that has never looked at your project.
|
|
3646
|
+
|
|
3647
|
+
**Deeply nested checkout? The socket moves to a short tmpdir path, automatically.** A unix socket
|
|
3648
|
+
path is capped at ~100-108 bytes by the OS (`sun_path`); `<project>/.dz/embed.sock` can exceed that
|
|
3649
|
+
in a project nested several directories deep, and past the limit the daemon used to bind nowhere
|
|
3650
|
+
while still looking "ready". It now falls back to a short, deterministic path under your system temp
|
|
3651
|
+
directory and drops a pointer file (`.dz/embed.sock.path`) the recall hook and `dz doctor` both
|
|
3652
|
+
read — `dz doctor`'s liveness line names the actual path in that case: `embed socket present at
|
|
3653
|
+
/tmp/dz-embed-<hash>.sock (tmpdir-short: project path 118 bytes > 100)`. Nothing to configure; set
|
|
3654
|
+
`DZ_EMBED_SOCKET` yourself only if you need to pin an exact path.
|
|
3655
|
+
|
|
3656
|
+
#### Post-install verification (acceptance check, dz-harness-hub issue #10)
|
|
3657
|
+
|
|
3658
|
+
A live end-to-end check for a fresh `--memory agentdb` install — every line below is something the
|
|
3659
|
+
install must produce, not a smoke test of the CLI parsing its own flags:
|
|
3660
|
+
|
|
3661
|
+
```bash
|
|
3662
|
+
# 1. Install — all three legs, on a bare Node 20/22 host (no C toolchain required: AM-2 pins
|
|
3663
|
+
# better-sqlite3@^11, the range with a prebuilt binary for Node 20's ABI 115).
|
|
3664
|
+
dz setup --target claude-code --project . --memory agentdb
|
|
3665
|
+
|
|
3666
|
+
# 2. Both hook entries actually landed in settings.json.
|
|
3667
|
+
grep -c recall-hook.cjs .claude/settings.json # → 1
|
|
3668
|
+
grep -c dz-embed-daemon.mjs .claude/settings.json # → 1
|
|
3669
|
+
|
|
3670
|
+
# 3. The pinned dependency resolved to a version WITH a prebuilt binary.
|
|
3671
|
+
node -e "console.log(require('./node_modules/better-sqlite3/package.json').version)" # → 11.x
|
|
3672
|
+
|
|
3673
|
+
# 4. A lesson taught right after setup — before any session has ever ended — still mirrors
|
|
3674
|
+
# (AM-4: setup pre-creates an empty .dz/agentdb.db so this is never silent).
|
|
3675
|
+
dz teach "acceptance check lesson" --allow-cold-start # → "↳ mirrored to vector tier (agentdb)"
|
|
3676
|
+
|
|
3677
|
+
# 5. The embed daemon comes up (spawned by SessionStart; give it up to ~20s to load the model).
|
|
3678
|
+
timeout 20 sh -c 'until [ -S .dz/embed.sock ]; do sleep 1; done' && echo "daemon socket is up"
|
|
3679
|
+
|
|
3680
|
+
# 6. The recall hook actually injects context for a relevant prompt, and stays silent for one
|
|
3681
|
+
# that clears no relevance floor — never a hang, never a stray print on stdout.
|
|
3682
|
+
echo '{"prompt":"acceptance check lesson"}' | node .claude/helpers/recall-hook.cjs # → one line of JSON, hookSpecificOutput.additionalContext non-empty
|
|
3683
|
+
echo '{"prompt":"unrelated weather report"}' | node .claude/helpers/recall-hook.cjs # → empty stdout, exit 0
|
|
3684
|
+
|
|
3685
|
+
# 7. Doctor confirms the leg is alive, not merely installed.
|
|
3686
|
+
dz doctor # → "apply-leg alive (embed daemon): embed socket present at <path> — recall injection can run"
|
|
3687
|
+
```
|
|
3688
|
+
|
|
3689
|
+
Every step above is a REPRODUCER, not a claim: run it on a scratch project before trusting a `dz
|
|
3690
|
+
setup --memory agentdb` install on a new machine.
|
|
3691
|
+
|
|
3419
3692
|
### AgentDB self-learning algorithms
|
|
3420
3693
|
|
|
3421
3694
|
When using `--memory agentdb`, the following algorithms automatically tune search quality:
|
|
@@ -3756,8 +4029,8 @@ Learned routing outcomes (what `auto-cost` currently believes):
|
|
|
3756
4029
|
Cold-start (no history) walks a cheapest-first chain and escalates on failure; once a model clears the bar it is
|
|
3757
4030
|
chosen directly. Two invariants held hard: `auto-cost` on the **qe** stage only ever ranks the **cross-family of
|
|
3758
4031
|
the coder** (a model never self-QEs), and the whole thing is **opt-in** — with no `auto-cost` spec anywhere the
|
|
3759
|
-
pipeline is byte-identical and the store is never touched.
|
|
3760
|
-
|
|
4032
|
+
pipeline is byte-identical and the store is never touched. Provider-limit overrides are disabled by design;
|
|
4033
|
+
`auto-cost` decisions use only their own gated outcome history. Storage is a plain JSON file — zero native deps.
|
|
3761
4034
|
|
|
3762
4035
|
### `dz bto-optimize` — when you want to improve a skill WITHOUT gaming its own benchmark
|
|
3763
4036
|
|
|
@@ -3891,7 +4164,7 @@ invariants: HARD rules **block** the operation, SOFT rules warn. Zero config nee
|
|
|
3891
4164
|
cover the known rakes; `.dz/guard.json` (via `dz guard --init`) exists only if you want to tune a severity
|
|
3892
4165
|
or disable a rule.
|
|
3893
4166
|
```bash
|
|
3894
|
-
dz guard check --op publish # no-workspace-star · no-skill-drift · no-secrets · readme-consistency · readme-first · signature-fresh · skills-registrable · lockfile-in-sync · marketplace-parity · no-stubs · review-round · licence-hold
|
|
4167
|
+
dz guard check --op publish # no-workspace-star · no-skill-drift · no-secrets · readme-consistency · readme-first · signature-fresh · skills-registrable · lockfile-in-sync · marketplace-parity · no-stubs · review-round · rounds-closed · rounds-traced · licence-hold
|
|
3895
4168
|
dz guard check --op teach --text "the fix: export sk-abc..." # → BLOCK (exit 1): looks like a credential
|
|
3896
4169
|
dz guard log # append-only audit: every verdict + every forced override
|
|
3897
4170
|
```
|
|
@@ -4373,6 +4646,119 @@ stay in the previous embedding space until their own reindex runs) instead of le
|
|
|
4373
4646
|
Only models listed in `KNOWN_EMBED_DIMS` are accepted — the store's `vectorDim` is 384, so a 768-dim
|
|
4374
4647
|
model is rejected rather than silently writing mismatched vectors.
|
|
4375
4648
|
|
|
4649
|
+
#### Pre-reindex snapshots pile up — rotating them
|
|
4650
|
+
|
|
4651
|
+
Every `dz brain reindex` (and every `dz vector reindex`) copies the store to
|
|
4652
|
+
`<db>.pre-reindex-<ms>.bak` first, as an undo point. Nothing pruned those copies before this feature —
|
|
4653
|
+
13 snapshots / 50 MB accumulated on one real brain home before anyone noticed. Two ways to clear them:
|
|
4654
|
+
|
|
4655
|
+
```bash
|
|
4656
|
+
$ dz brain reindex
|
|
4657
|
+
dz brain reindex: re-embedded 812 KU vector(s) with Xenova/paraphrase-multilingual-MiniLM-L12-v2 (manifest v4)
|
|
4658
|
+
snapshot: /home/you/.dz/brain/agentdb.db.pre-reindex-1757754000000.bak
|
|
4659
|
+
↳ snapshots: kept 6, removed 8 (41.2 MB)
|
|
4660
|
+
```
|
|
4661
|
+
|
|
4662
|
+
`dz brain reindex` now rotates automatically after a SUCCESSFUL reindex, keeping the newest 3
|
|
4663
|
+
snapshot families by default (`opts.keepSnapshots`) — the family it just created is never removed,
|
|
4664
|
+
even at `keep=0`. A reindex that itself fails rotates nothing (the old snapshots may be the only
|
|
4665
|
+
working copy left).
|
|
4666
|
+
|
|
4667
|
+
When you cannot or do not want to run a reindex — e.g. a hub where reindexing itself is off-limits
|
|
4668
|
+
today, but old snapshots have piled up regardless — rotate directly:
|
|
4669
|
+
|
|
4670
|
+
```bash
|
|
4671
|
+
$ dz brain snapshots
|
|
4672
|
+
dz brain snapshots — 9 family(-ies) @ /home/you/.dz/brain/agentdb.db
|
|
4673
|
+
2026-09-01T08:00:00.000Z ms=1756713600000 2 file(s) 4.1 MB
|
|
4674
|
+
2026-09-05T08:00:00.000Z ms=1757059200000 2 file(s) 4.1 MB
|
|
4675
|
+
...
|
|
4676
|
+
(dry run — pass --prune to remove families older than --keep)
|
|
4677
|
+
|
|
4678
|
+
# The PROJECT store (.dz/agentdb.db, written by the vector-tier reindex) is addressed with --project:
|
|
4679
|
+
$ dz brain snapshots --project .
|
|
4680
|
+
dz brain snapshots — 13 family(-ies) @ /path/to/project/.dz/agentdb.db
|
|
4681
|
+
|
|
4682
|
+
$ dz brain snapshots --prune --keep 3
|
|
4683
|
+
dz brain snapshots: kept 6, removed 12 (37.1 MB)
|
|
4684
|
+
removed: agentdb.db.pre-reindex-1756713600000.bak, agentdb.db.pre-reindex-1756713600000.bak.embed-manifest.json, ...
|
|
4685
|
+
```
|
|
4686
|
+
|
|
4687
|
+
`dz brain snapshots` never touches anything but the brain's own strictly-named
|
|
4688
|
+
`agentdb.db.pre-reindex-<ms>.bak` family (a symlink or a differently-named neighbour is left alone);
|
|
4689
|
+
without `--prune` it only lists, and a bad `--keep` — negative, non-numeric, empty, or whitespace-
|
|
4690
|
+
padded (`--keep ' 2'`) — is refused with exit 2 rather than silently treated as 0 or 2.
|
|
4691
|
+
|
|
4692
|
+
**Fix-round hardenings (2026-09-13, after a Codex review found the earlier version could delete
|
|
4693
|
+
every snapshot on a bad `--keep`):**
|
|
4694
|
+
|
|
4695
|
+
- **10-minute grace period.** A family younger than 10 minutes is never removed, even past `--keep`
|
|
4696
|
+
— there is no flag to shorten or disable this; it protects a snapshot a DIFFERENT, still-running
|
|
4697
|
+
process just wrote from looking "old" to a `--prune` invoked moments later.
|
|
4698
|
+
- **Removal order inside a family: siblings first, `.bak` last, only if every sibling actually
|
|
4699
|
+
unlinked.** If a sibling (the manifest, `-shm`, `-wal`) fails to unlink, the `.bak` — the one file
|
|
4700
|
+
that alone still proves the snapshot existed — is left in place, and the family's `⚠ .bak
|
|
4701
|
+
preserved after a sibling failure` line names it.
|
|
4702
|
+
- **A scan error blocks the whole rotation, not just that one file.** If the brain directory itself
|
|
4703
|
+
cannot be listed (or a file's status cannot be read) for a reason other than "it does not exist",
|
|
4704
|
+
the command prints `⚠ scan error(s), nothing removed this call` and removes NOTHING — an
|
|
4705
|
+
incomplete file list is never a safe basis for "these are the old ones".
|
|
4706
|
+
|
|
4707
|
+
```bash
|
|
4708
|
+
$ dz brain snapshots --prune --keep 3
|
|
4709
|
+
dz brain snapshots: kept 6, removed 12 (37.1 MB)
|
|
4710
|
+
removed: agentdb.db.pre-reindex-1756713600000.bak, agentdb.db.pre-reindex-1756713600000.bak.embed-manifest.json, ...
|
|
4711
|
+
⚠ .bak preserved after a sibling failure in famil(y/ies): 1756713600000 # only printed if a sibling unlink failed
|
|
4712
|
+
⚠ scan error(s), nothing removed this call: readdir /home/you/.dz/brain: EACCES # only printed on a scan failure
|
|
4713
|
+
```
|
|
4714
|
+
|
|
4715
|
+
**Snapshot lock (agentdb-snapshot-lock, 2026-09-13).** `--prune` now takes the SAME advisory lock a
|
|
4716
|
+
concurrent `dz brain reindex`/`reindexAgentdbRows` uses (`<store dir>/.dz/locks/agentdb-snapshot.lock`)
|
|
4717
|
+
before it removes anything — a `rotate --keep 0` racing a live reindex used to be able to delete the
|
|
4718
|
+
undo point the reindex was still relying on; now it waits for the lock, or reports the timeout
|
|
4719
|
+
explicitly instead of silently succeeding on an empty rotation:
|
|
4720
|
+
|
|
4721
|
+
```bash
|
|
4722
|
+
$ dz brain snapshots --prune --keep 0 # a concurrent reindex is mid-flight and holds the lock
|
|
4723
|
+
dz brain snapshots: kept 0, removed 0 (0.0 MB)
|
|
4724
|
+
⚠ 1 error(s): lock busy: the lock at …/.dz/locks/agentdb-snapshot.lock stayed held for 10000ms — …
|
|
4725
|
+
$ echo $?
|
|
4726
|
+
1
|
|
4727
|
+
```
|
|
4728
|
+
|
|
4729
|
+
A family a LIVE reindex marker names (`<db>.reindex-inprogress.json`, written for the duration of
|
|
4730
|
+
that reindex, not just the moment the lock is held) also survives `--prune`, even at `--keep 0`; an
|
|
4731
|
+
EXPIRED marker (older than 60 minutes) is cleaned up and named honestly in a `note:` line rather than
|
|
4732
|
+
either protecting it forever or treating its removal as a scan error:
|
|
4733
|
+
|
|
4734
|
+
```bash
|
|
4735
|
+
$ dz brain snapshots --prune --keep 0
|
|
4736
|
+
dz brain snapshots: kept 2, removed 4 (12.3 MB)
|
|
4737
|
+
note: stale reindex marker (ms=1757754000000, startedAt=2026-09-13T01:00:00.000Z) ignored and removed
|
|
4738
|
+
```
|
|
4739
|
+
|
|
4740
|
+
If the marker could not actually be removed (e.g. a permission error), the note says so instead of
|
|
4741
|
+
silently claiming success: `"… ignored, removal failed: <err>"` — never `"… ignored and removed"` for
|
|
4742
|
+
a removal that did not happen.
|
|
4743
|
+
|
|
4744
|
+
**Marker ownership + a stuck rollback (fix-round, 2026-09-13).** The marker file is now written and
|
|
4745
|
+
removed with an ownership token: a `dz brain reindex` genuinely still in flight refuses a SECOND
|
|
4746
|
+
concurrent reindex of the same store outright (no snapshot for the refused attempt), and nothing but
|
|
4747
|
+
the owning reindex can clear its own marker. If a reindex fails and its rollback cannot re-acquire the
|
|
4748
|
+
snapshot lock (e.g. `--prune` or another reindex is mid-critical-section), the marker is deliberately
|
|
4749
|
+
LEFT IN PLACE rather than cleared — the reported error names both the snapshot and the marker path and
|
|
4750
|
+
says `requires manual recovery`:
|
|
4751
|
+
|
|
4752
|
+
```
|
|
4753
|
+
error: index failed: …; rollback failed: lock busy: …; snapshot at /home/you/.dz/brain/agentdb.db.pre-reindex-1757754000000.bak
|
|
4754
|
+
was not confirmed restored; marker at /home/you/.dz/brain/agentdb.db.reindex-inprogress.json is left
|
|
4755
|
+
in place — requires manual recovery
|
|
4756
|
+
```
|
|
4757
|
+
|
|
4758
|
+
Recovery is manual: inspect the named snapshot, restore it by hand if the store looks wrong, then
|
|
4759
|
+
delete the marker file. **The snapshot lock's own stale threshold is 5 minutes** — a base whose own
|
|
4760
|
+
snapshot genuinely takes longer needs external coordination, not a bigger default.
|
|
4761
|
+
|
|
4376
4762
|
**Before → after** (what changes when you enable it):
|
|
4377
4763
|
|
|
4378
4764
|
| | Before (lexical only) | After (hybrid vector tier) |
|
|
@@ -4738,7 +5124,22 @@ refusal as the honest answer.
|
|
|
4738
5124
|
|
|
4739
5125
|
## Status
|
|
4740
5126
|
|
|
4741
|
-
`harness-core v0.8.
|
|
5127
|
+
`harness-core v0.8.32` · `harness-cli v0.8.24` — **this release: `dz publish` refuses a broken pair, `dz setup`
|
|
5128
|
+
reads the memory backend from config, and the embed daemon says "ready" only with a socket that exists.**
|
|
5129
|
+
(1) Sibling-drift gate + packed install smoke: before any live `npm publish`, every `workspace:*` sibling on
|
|
5130
|
+
the registry is compared with the workspace (dist/files/bin + the shipping fields of package.json); a
|
|
5131
|
+
drifted sibling BLOCKS the batch (`add <sibling> to the batch or publish it first`), and each package that
|
|
5132
|
+
declares a `bin` is packed post-bump, installed into a clean directory and asked `--version` — the exact
|
|
5133
|
+
incident of 2026-09-13 (a CLI published against a core that did not export what it imports) is now caught
|
|
5134
|
+
in the dry run. Transport is transactional: the first failed `npm publish` stops the batch. (2) `dz setup`
|
|
5135
|
+
without `--memory` takes the backend from `.dz/config.json` (`memory backend: agentdb (from .dz/config.json)`),
|
|
5136
|
+
downgrades only on an explicit `--memory jsonl` with a warning, and `dz doctor` gained `memory hooks match
|
|
5137
|
+
config` — all three session events must invoke `.dz/agentdb-writer.mjs` when config says agentdb.
|
|
5138
|
+
(3) A project whose `.dz/embed.sock` path exceeds the unix limit gets a short socket in a private
|
|
5139
|
+
`<tmpdir>/dz-<uid>/` directory (mode 0700) with an atomically published pointer `.dz/embed.sock.path`; the
|
|
5140
|
+
daemon prints `ready` only after the socket exists and exits 3 on a bind failure. (4) The qe-bridge signoff
|
|
5141
|
+
record carries `writeSequence` (diagnostic sequencing metadata) so the tests no longer race on file mtimes.
|
|
5142
|
+
Previous release (0.8.30/0.8.22): **the store guard tells "busy" from "broken",
|
|
4742
5143
|
and a publish is not finished until the public mirror confirms it.** (1) The learning-store guard used to
|
|
4743
5144
|
turn ANY read failure into `unreadable` and refuse the write; a neighbour holding the SQLite write lock
|
|
4744
5145
|
(`SQLITE_BUSY`) or a store still being initialised (`no such table`) now gets bounded retries and, if still
|
|
@@ -4761,7 +5162,7 @@ exports (`commandInventory`, `declaredCommands`, `dispatchedCommands`, `document
|
|
|
4761
5162
|
`stripNonCode`, `validateExceptionList`, `INTERNAL_ENTRY_POINTS`, `PSEUDO_COMMANDS`) — instead of a
|
|
4762
5163
|
fourth private regex and a fourth number. Four hidden commands (`mr-rakes`, `retro`,
|
|
4763
5164
|
`feature-adr-setup`, `bto-optimize`) gained USAGE lines, so `--help` changed; `help` is a documented
|
|
4764
|
-
pseudo-command, not a `case` label. **
|
|
5165
|
+
pseudo-command, not a `case` label. **92 canonical commands, 93 names in rendered `--help`** (the 92
|
|
4765
5166
|
plus the built-in `help`) — both COMPUTED from `cli.ts`, neither typed into a test. Three cross-family QE rounds closed
|
|
4766
5167
|
six parser defects the naive version had: four that INVENTED a command (regex literals with a lone
|
|
4767
5168
|
`}`, `case` labels in comments or templates, sub-verb labels from nested switches, ` dz <name>` lines
|
|
@@ -4781,6 +5182,43 @@ plan-route choice. Every failure is fail-open; versioned `.fa-state/decision-rec
|
|
|
4781
5182
|
receipt coverage and repeat-related outcomes derivable offline. The hypothesis is external `[SRC],
|
|
4782
5183
|
n=1`, books were silent on retrieval timing, and no runtime threshold gates a stage.
|
|
4783
5184
|
|
|
5185
|
+
`harness-core` / `harness-cli` — **staged, not published: `ts` and `minutesSincePrev` on the run-cost
|
|
5186
|
+
ledger.** The writer could not measure a stage's full duration (the workflow sandbox never calls
|
|
5187
|
+
`Date.now()`, for resume-safety) but it always knew the moment of each write and the run it belonged
|
|
5188
|
+
to — so every ledger row now also gets `ts` (the ISO instant it was recorded, next to `date`), and an
|
|
5189
|
+
`auto:true` row that carries a `runId` additionally gets `minutesSincePrev` (a number, one decimal
|
|
5190
|
+
digit, ≥ 0) plus `minutesSource: 'ledger-ts-delta'`, measured against the LAST row of the same run —
|
|
5191
|
+
found via `dz feature-adr-record --run-id <id>` or a `runId` already in the payload. When there is no
|
|
5192
|
+
prior row, or it carries no `ts`, the pair reads `minutesSincePrev: null` / `minutesSource:
|
|
5193
|
+
'unavailable'` rather than a guess. `minutes` itself is untouched and stays `null` on every auto row:
|
|
5194
|
+
a partial measurement gets its own named field and source, and is never folded into the field that
|
|
5195
|
+
implies the whole stage's duration was known. `dz cadence`'s round summary reads unaffected fixtures
|
|
5196
|
+
unchanged — the new fields are additive, never repositioning an existing key.
|
|
5197
|
+
|
|
5198
|
+
**Fix-round-1 (cross-family review, grade B → 5 findings closed), still staged, not published:**
|
|
5199
|
+
a Codex `gpt-5.6-sol` review of the above found five contract gaps, all closed by measurement:
|
|
5200
|
+
(1) the reverse scan for the previous row's `ts` used to skip PAST a torn or non-object ledger line
|
|
5201
|
+
and keep looking further back, so an OLDER row for the same `runId` could be returned while a newer
|
|
5202
|
+
one sat hidden behind the corrupt line; it now stops and reports `unavailable` — named
|
|
5203
|
+
`ledger-corrupt-line` — the instant it hits a line it cannot parse as an object, never a guess made
|
|
5204
|
+
by skipping past what it could not read. (2) `--run-id` filling a MISSING `runId` was already correct
|
|
5205
|
+
— "missing" means absent, `null`, `''`, or a non-string value, the same "missing when absent or
|
|
5206
|
+
blank" rule `runnerId` uses — but it was untested beyond the plain non-empty-string case and
|
|
5207
|
+
undocumented; both are fixed now, behavior unchanged. (3) when `--run-id` actually fills the gap, the
|
|
5208
|
+
row is now tagged `runIdSource: 'cli-flag'` — the same provenance discipline `resolved-at-write`
|
|
5209
|
+
already gets for the OTHER runId source (write-time auto-resolution) — and an existing non-empty
|
|
5210
|
+
`runIdSource` is left untouched. (4) a payload's own `ts` is no longer trusted for the delta: `ts` on
|
|
5211
|
+
a ledger row is now ALWAYS the actual write instant, and a caller-supplied one survives, renamed,
|
|
5212
|
+
as `payloadTs` — no data lost, just no longer the value the delta measures from. (5) object key order
|
|
5213
|
+
now matches the documented convention exactly: a `runnerId` this call itself stamps keeps its position
|
|
5214
|
+
ahead of `ts`/`minutesSincePrev`/`minutesSource`, which land strictly last regardless of which fields
|
|
5215
|
+
the incoming payload already carried. `test/run-records.test.ts` (48, +10) and
|
|
5216
|
+
`test/feature-adr-record-cli.test.ts` (22, +7) cover all five, plus fractional-minute rounding
|
|
5217
|
+
(2m30s → 2.5, 1m3s → 1.1) and a pinned negative-delta case; the `ledger-minutes-since-prev-measured`
|
|
5218
|
+
mutation-gate entry was RE-MEASURED at `failingCount: 3` (three of the new tests now discriminate the
|
|
5219
|
+
same mutation, up from one) and the registry updated to match — `dz mutation-gate --only
|
|
5220
|
+
ledger-minutes-since-prev-measured` verdict `PROVEN`, exit 0.
|
|
5221
|
+
|
|
4784
5222
|
`v0.8.8` — **staged, not published.** `dz init` now reports exactly one MCP and one hook outcome,
|
|
4785
5223
|
adds `integrations-verify`, content-bound authorization, explicit skills-only opt-out, and named
|
|
4786
5224
|
partial-failure exits; only receipt-proven live registration may be called emitted.
|
|
@@ -4911,7 +5349,7 @@ partial design). The compat floor is unchanged — this CLI uses no new core exp
|
|
|
4911
5349
|
|
|
4912
5350
|
**v0.5.1** — published 2026-08-20. Ships `dz workflow run`, the portable plan enactor: it INTERPRETS a `loop-plan/1` plan instead of executing a rendered script, dispatching to `codex exec` or an isolated `claude -p`, exit 0/1/2/75 (75 = a typed pause whose last stdout line is a `wf-pause-envelope/1`). Requires `@dzhechkov/harness-core >= 0.5.1` (the compat guard refuses below it by name). See "Who writes the trace" above for the stated scope of the cross-host equivalence claim — it is narrower than "the two hosts agree".
|
|
4913
5351
|
|
|
4914
|
-
`v0.5.0` — published.
|
|
5352
|
+
`v0.5.0` — published. Claude Plugin packaging exists for contributors only (see [Claude Plugin](#claude-plugin) — a public marketplace install does not work today). Part of [DZ Harness Hub](https://github.com/djd1m/dz-harness).
|
|
4915
5353
|
|
|
4916
5354
|
New in 0.5.0 (feature `qe-bridge-claude`, cross-runtime leg 3/4): `dz qe-bridge --family claude`
|
|
4917
5355
|
runs an INDEPENDENT Claude reviewer from any host — a Codex session included — and lands a PARSED
|
|
@@ -4935,21 +5373,21 @@ Previously: the global `dz --version` / `-v` / `dz version` surface (one parseab
|
|
|
4935
5373
|
|
|
4936
5374
|
## Claude Plugin
|
|
4937
5375
|
|
|
4938
|
-
|
|
5376
|
+
Using the whole hub as a Claude Code plugin needs the source repo — this is a path for
|
|
5377
|
+
**contributors and plugin developers**, not something an `npm install -g` user needs (see
|
|
5378
|
+
Install above). A public marketplace install does **not** work today: `claude plugin marketplace add djd1m/dz-harness` fails with `Marketplace file not found` (MEASURED 2026-09-13, scratch probe) — the public mirror ships each package's `npm pack` contents only, never the root-level `.claude-plugin/marketplace.json`.
|
|
4939
5379
|
|
|
4940
5380
|
```bash
|
|
4941
|
-
#
|
|
4942
|
-
claude plugin marketplace add djd1m/dz-harness-hub
|
|
4943
|
-
claude plugin install dz-harness-hub@dz-harness-hub
|
|
4944
|
-
|
|
4945
|
-
# Or test locally:
|
|
5381
|
+
# From a cloned repo (contributors / plugin developers only):
|
|
4946
5382
|
claude --plugin-dir /path/to/dz-harness-hub
|
|
4947
5383
|
|
|
4948
5384
|
# Generate plugin manifest from current inventory:
|
|
4949
5385
|
dz plugin --version 0.3.86
|
|
4950
5386
|
```
|
|
4951
5387
|
|
|
4952
|
-
The `.claude-plugin/` directory contains `plugin.json` + `marketplace.json`
|
|
5388
|
+
The `.claude-plugin/` directory (source repo only) contains `plugin.json` + `marketplace.json`
|
|
5389
|
+
compatible with [pi-claude-marketplace](https://npm.im/pi-claude-marketplace) and
|
|
5390
|
+
[skill-hub](https://npm.im/@jasonwen/skill-hub).
|
|
4953
5391
|
|
|
4954
5392
|
## Related Projects
|
|
4955
5393
|
|
|
@@ -5031,3 +5469,18 @@ Core APIs: `settleDeadRuns` and `planRegistryArchive` are pure registry decision
|
|
|
5031
5469
|
`planWorktreeCleanup` accepts injected `WorktreeFact` values and returns remove/keep decisions;
|
|
5032
5470
|
`renderCleanupPlan` renders them. `worktreeRemovalsToApply` selects removals only when apply is true.
|
|
5033
5471
|
No process is terminated and no branch is deleted.
|
|
5472
|
+
|
|
5473
|
+
## From source (contributors only)
|
|
5474
|
+
|
|
5475
|
+
Everything below is for people building or testing `dz` itself — not for `npm install -g` users.
|
|
5476
|
+
The buildable source lives in the public mirror, [github.com/djd1m/dz-harness](https://github.com/djd1m/dz-harness) (each package's own npm-pack contents; the full monorepo, including this feature's design docs, stays in the private source repo).
|
|
5477
|
+
|
|
5478
|
+
### Test execution
|
|
5479
|
+
|
|
5480
|
+
`npx vitest run` uses two projects and returns one combined verdict: `parallel` runs the ordinary
|
|
5481
|
+
suites concurrently, while `serial` runs process-spawning and real-time suites one file at a time.
|
|
5482
|
+
The serial paths in `test/serial-suites.txt` are regenerated from
|
|
5483
|
+
`test/serial-suites-census.test.ts`, which scans test sources for synchronous and asynchronous
|
|
5484
|
+
process markers, including `execSync(` and `execFile(`, and fails when the list and census differ.
|
|
5485
|
+
CF-2 records uncommented explicit test budgets in each package's `test/budget-debt-ceiling.json`: growth fails with `file:line` findings; shrinkage passes and suggests a lower ceiling.
|
|
5486
|
+
The ceiling files live in `packages/@dzhechkov/harness-core/test/` and `packages/@dzhechkov/harness-cli/test/` and are lowered by hand: a ratchet on existing debt, not a migration that clears it in one shot.
|