npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@dzhechkov/harness-cli

v0.8.24

Published

The dz CLI — install AI skills for Claude Code, Codex, OpenCode, Hermes, OpenClaude, GitHub Copilot. 87 commands, 14 presets, 10 platform targets.

Readme

@dzhechkov/harness-cli

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.

Install in 30 seconds

npm install -g @dzhechkov/harness-cli
dz setup --target claude-code --preset devops
dz doctor

You do NOT need to clone any repository to use dz. Source is for contributors — see From source (contributors only) at the end of this README.

Why dz?

dz is a package manager + cross-compiler for your AI agent harness. Write a skill once in one canonical form; dz installs it into any agent's harness, holds it to a quality bar, and lets the harness learn over time.

The problem. You accumulate 260 skills (design-thinking, QE, devops, web3, MCP, academic…). Five pains follow:

  1. Every agent wants a different layout. Claude Code reads .claude/skills/, Codex .codex/, OpenCode/Hermes/OpenClaude their own. Hand-maintaining N copies is sync hell.
  2. Skills arrive from many upstream repos — they must be canonicalized (brought to one form) and kept in sync without losing provenance.
  3. It's hard to know which skill to reach for out of a hundred.
  4. Quality drifts — there's no single bar.
  5. Experience doesn't accumulate — the harness doesn't learn from feedback.

The answer — one canon → many platforms. There is a single source of truth (a CanonicalSkill); dz compiles it for each target — so the same skill drops into .claude/skills/, .codex/, etc. without hand-copying.

Every command maps to one of five jobs:

| Job | Commands | What it does | |-----|----------|--------------| | Author / canonicalize | auto-canonicalize, sync-upstream, diff, create-skill | pull a skill from any repo into one canonical form + keep it in sync with upstream | | Install / assemble | init, setup, install, compose, presets, upgrade | deploy the right set of skills into a chosen agent harness (10 targets) | | Find / recommend | registry, scout, recommend, skill-advisor | for a task, suggest which skill / preset / package to use | | Guarantee quality | benchmark (L0 A–F), verify, doctor | one bar — 20 deterministic checks per skill | | Learn | teach, consolidate, recall (hybrid lexical+vector), vector, pretrain, roam (reward-learning) | accumulate patterns, harvest session outcomes, recall ranked memory (semantic when the vector tier is enabled), improve recommendations over time |

(+ ops: publish, bundle (portable export), stats, downloads, dashboard, plugin.)

Analogy: npm for distribution, a compiler / Babel for one source → many targets (adapters for 10 targets), and a linter / CI for a quality bar (benchmark) — but for AI agent skills, not ordinary code.

Install

npm install -g @dzhechkov/harness-cli

MCP and hook companion configuration

A skill can request companion configuration through a bounded adjacent INTEGRATIONS.json. The first integration-aware init prints its aggregate digest; only --allow-integrations <that-digest> can authorize the exact content. The live registration probe is non-executing: it uses target-owned list/get surfaces, never the manifest command or URL.

The measured support matrix currently admits Claude Code 2.1.235 project MCP only. Every other target/component pair is a named refusal, except that the existing Codex hook writer can map to emitted when its live veto probe reports ready: true. Claude Pending approval is registration with ready: false. Use --no-integrations for explicit skills-only installation; --no-verify does not authorize emission.

Note: If you get EUNSUPPORTEDPROTOCOL workspace:*, you're inside a pnpm/yarn workspace. Run the install from /tmp or ~ instead.

Updating an already-installed dz

dz does not auto-update — an old global install stays old until you upgrade it explicitly. Upgrading also refreshes all bundled skill packs to their latest published versions.

# Check installed vs. latest:
npm ls -g @dzhechkov/harness-cli          # what you have
npm view @dzhechkov/harness-cli version   # latest on npm

# Upgrade (run from /tmp to avoid the workspace:* error above):
cd /tmp && npm install -g @dzhechkov/harness-cli@latest

On an old version? Tell-tale signs: dz registry shows an other bucket instead of product/design categories, or dz init/dz setup finds no skills. Upgrade as above. A system-wide global on Linux may live in /usr/lib/node_modules and need sudo.

Using the arsenal: new vs. existing project

Install dz once, globally — it ships all skill packs bundled, so you never install packs per-project. Then run dz from inside a project to write skills into its agent directory (.claude/skills/, .codex/, …). Nothing lands until you choose a target + skills.

See what's available (from any directory):

dz registry                    # browse the full catalog by category
dz registry search <keyword>   # search skills
dz registry --category devops  # one category
dz stats                       # totals + full preset & target lists
dz help                        # all commands; the Presets:/Targets: lines list valid --preset/--target values
dz recommend "<your task>"     # task → recommended skills + preset

New project:

mkdir my-app && cd my-app
dz setup --target claude-code --preset devops   # skills + hooks + self-learning (.dz/)
dz init  --target claude-code --preset devops   # or: skills only

Existing project — same commands from the project root; dz is additive and only touches the agent directory, never your source:

cd existing-project
dz init --target claude-code --preset qe                       # add a preset
dz init --target claude-code --select terraform,pr-review      # add individual skills
dz install @dzhechkov/skills-web3                              # add one pack
dz verify && dz doctor                                         # check health

Re-running is safe (existing files are skipped unless --force). Targets: claude-code, codex, opencode, hermes, openclaude, copilot, agents-md, cursor, gemini.

Target coverage — which coder/agent maps to which --target

Don't see your tool below? Two fallbacks: if it reads CLAUDE.md/.claude/ use --target claude-code; otherwise dz bundle --select <ids> --out <dir> gives a portable tree of raw SKILL.md files you can 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).

✅ Shipped native targets (each compiles to the tool's own layout):

| Coder / agent | --target | Emits | |---------------|-----------|-------| | Claude Code | claude-code | CLAUDE.md + .claude/skills/ | | OpenAI Codex CLI | codex | .agents/skills/ | | OpenCode | opencode | .opencode/skills/ | | Hermes Agent | hermes | .hermes/skills/ | | OpenClaude (incl. the "OpenClaw"/Claw-Code fork — it mirrors Claude Code) | openclaude | .openclaude/skills/ | | GitHub Copilot | copilot | .github/instructions/*.instructions | | ~15 tools that read a root AGENTS.md (Zed, Warp, Aider, goose, Gemini CLI, RooCode, Kilo, Junie, Trae, Augment, Devin, pi, Windsurf) | agents-md | root AGENTS.md (merged — preserves user content, owns a fenced block; lossy/flattening, no per-skill frontmatter) | | Cursor | cursor | .cursor/rules/*.mdc (per-skill, YAML frontmatter description/globs/alwaysApply; plain .md in that dir is ignored) | | Gemini CLI / Code Assist | gemini | root GEMINI.md (merged — preserves user content, owns a fenced block; lossy/flattening, no per-skill frontmatter — same shape as agents-md) | | Windsurf | windsurf | .windsurf/rules/*.md (per-skill, YAML trigger frontmatter — model_decision, description, optional globs; cursor's shape with a plain .md extension. .devin/rules/ rebrand is an out-of-scope watch item) |

🗺️ On the roadmap (verified rules-formats — see the research doc):

| Coder(s) / agent | planned --target | reads | priority | |------------------|--------------------|-------|----------| | Cline · Continue · Kiro | cline · continue · kiro | .clinerules/ · .continue/rules/ · .kiro/steering/ | mid |

❌ No target applies: nemoclaw (NVIDIA agent-safety runtime — not a code editor, no rules file) · v0 (UI-only, no repo file). (pi is a real coder but reads AGENTS.md → covered by agents-md.)

--target aliases and did-you-mean

--target claude used to be rejected outright — the canonical name is claude-code, and the error just re-printed the list. All eight --target-taking commands (init, verify, install, compose, setup, upgrade, parity, feature-adr-setup) now resolve the value first.

(This sentence used to say "every" and name only seven: dz parity was missed, and shipped the original defect verbatim. It is now checked rather than promised — test/target-alias-cli.test.ts asserts that no command reads --target without reaching the resolver, and that every command whose --help advertises --target appears in the per-command sweep.)

Accepted aliases (a table, so adding one is a data edit):

| You type | You get | Why it is a row | |----------|---------|-----------------| | claude · cc | claude-code | the tool's everyday name | | agents | agents-md | the everyday name of the AGENTS.md target | | gpt · openai | codex | the vendor name, not the CLI's |

Case, padding and separators are handled without a row: CLAUDE, Claude_Code, claudecode and claude-code all resolve to claude-code; agentsmd and agents.md resolve to agents-md.

A typo is SUGGESTED, never silently accepted — installing to the wrong target on a guess is worse than one round-trip:

$ dz init --target clade-code --preset devops > out.txt   # the refusal is on STDERR
dz init: unknown --target "clade-code" — did you mean "claude-code"?
  --target must be one of: agents-md, claude-code, codex, copilot, cursor, gemini, hermes, openclaude, opencode, windsurf
$ echo $?
1
$ wc -c out.txt
0 out.txt        # stdout stays a clean data channel, even on a refusal

Both lines go to stderr — the refusal, like the alias note below, is diagnosis, not data. dz parity --target <bad> --json likewise writes its structured error to stderr and leaves stdout empty, so | jq is never handed a diagnostic.

An ambiguous prefix gets no guess at all (--target co could be codex or copilot), and neither does nonsense (--target totally-bogus prints the plain list). When an alias IS accepted, the substitution is announced on stderr, so piped stdout stays machine-readable:

$ dz init --target claude --preset devops > installed.txt
dz init: --target "claude" → claude-code (alias)

When this matters: you are following a blog post or a teammate's snippet that says --target claude. It now works, and you are told what it resolved to.

dz list — one broken skill never hides the rest

dz list used to abort on the FIRST unparseable SKILL.md: exit 1, an error naming neither the file nor a count, and every other skill in the tree invisible. A pack you installed could blank your whole listing. Now the loadable skills are listed on stdout and the unloadable ones are named on stderr:

$ dz list --skills-dir .claude/skills
105 skill(s) in /home/you/proj/.claude/skills:

  api-design                          Designs REST and GraphQL APIs with OpenAPI specs…
  …103 more…
  test-writer                         Writes focused unit and integration tests…
$ echo $?
1

…with the diagnosis kept out of the data:

$ dz list --skills-dir .claude/skills 2>/dev/null   # stdout only — clean, pipeable
105 skill(s) in …

$ dz list --skills-dir .claude/skills 1>/dev/null   # stderr only — the actionable part
dz list: 105 listed, 1 skipped in /home/you/proj/.claude/skills
⚠ 1 skill(s) skipped (unparseable SKILL.md):
  /home/you/proj/.claude/skills/broken-one/SKILL.md
    SKILL.md must begin with a "---" frontmatter fence
    (line 1: "# Broken One")

The full contract:

| valid skills | skipped | stdout | stderr | exit | |--------------|---------|--------|--------|------| | >0 | 0 | the listing | empty | 0 | | >0 | >0 | the listing of the valid ones | named summary | 1 | | 0 | >0 | nothing | named summary (0 listed, N skipped) | 1 | | 0 | 0 | nothing | dz list: no skills found in <dir> | 1 |

dz init, dz install and dz sync behave the same way — the good skills are installed, the bad ones are named, and the command exits 1.

Two failure kinds, two headers, two subjects. A skill that will not PARSE and a skill that will not WRITE are different accusations, so dz init reports them separately:

$ dz init --target claude-code --skills-dir ./skills --project ./proj
dz init --target claude-code: 1 skill(s), 1 file(s) written, 0 skipped
dz init: 1 installed, 1 failed to write                       # ← stderr
✗ 1 skill(s) failed to install (compile/write error):
  alpha
    EEXIST: file already exists, mkdir './proj/.claude/skills/alpha'

The header names the target, not alpha/SKILL.md — which is perfectly valid. (It used to print ⚠ 1 skill(s) skipped (unparseable SKILL.md) and quote line 1: "---", a valid frontmatter fence, as its evidence: a failure that names the wrong artifact is worse than an anonymous one.)

dz install renders the offending path relative to the package and says so explicitly, because a node_modules/** path is not something you can act on:

$ dz install @someone/skills-pack
dz install @someone/skills-pack: 12 skill(s), 24 file(s) written, 0 skipped
dz install: @someone/skills-pack ships 1 unparseable skill(s) —
⚠ 1 skill(s) skipped (unparseable SKILL.md):
  skills/broken-one/SKILL.md
    SKILL.md must begin with a "---" frontmatter fence
This is a defect in the package, not in your project.
Workaround: npx -y @someone/skills-pack init

When this matters: a package you installed shipped a broken skill — you still see everything else, you know exactly which file is at fault, and you know whose defect it is.

dz requires @dzhechkov/harness-core >= 0.4.7. If you ever see dz: needs @dzhechkov/harness-core >= 0.4.7, found 0.4.1, a stale core was reused from a cache: rm -rf ~/.npm/_npx && npx @dzhechkov/harness-cli@latest --version. That named message replaced a bare SyntaxError: … does not provide an export named 'GRADE_SUCCESS_FLOOR' that used to kill even dz --version.

"Nothing installs" / "no skills found"? Update the CLI: cd /tmp && npm i -g @dzhechkov/harness-cli@latest. Older global installs couldn't locate their own bundled packs outside the monorepo — now fixed, so dz registry/dz init/dz setup work from any directory.

User Journey — from install to mastery

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:

DISCOVER → INSTALL → USE → CREATE → MAINTAIN → SHARE

dz profile — say once who you are, and stop being explained the wrong things

The failure this closes is measured, not hypothetical. On 2026-08-28 an OS pipe buffer was explained to this repository's owner across three paragraphs of kernel mechanics — he holds a CCIE, and "tail drop on a full queue with no backpressure signal" would have landed in one line. In the same session ADR and vitest worker went by unexplained, in a domain where he had said plainly he is not a professional. Neither failure was ignorance. Both were not knowing who was listening.

dz profile init
# 1/5 Dialogue language (ru, en, …) [ru]: ru
# 2/5 Default register — pro / pro-lite / plain (профи / профи лайт / просто) [pro-lite]: профи лайт
# 3/5 Назовите 2–4 области, где вам НЕ нужно пояснять термины … : networking (CCIE; NSX), cloud architecture
# 4/5 Где наоборот — терминам нужна одна поясняющая фраза? : software architecture, testing internals
# 5/5 Do you teach — must explanations be re-tellable? y/n [y]: y
#
# wrote ~/.dz/profile.json (0600) — register pro-lite (профи лайт), language ru, teaches yes
#   deep: networking (CCIE; NSX), cloud-architecture · weak: software-architecture, testing-internals
# synced block into ~/.claude/CLAUDE.md

That block now loads in every project on the machine, including projects where dz is not installed — because ~/.claude/CLAUDE.md is read by the runtime itself, not by a hook.

dz profile show          # store path, age in days, drift verdict, the rendered block
dz profile set weak add build-toolchains
dz profile set register профи        # RU aliases accepted; stored as the neutral `pro`
dz profile sync          # after a hand-edit: repairs the block, timestamped backup, foreign content untouched

When to use it: once, at onboarding — and again whenever you correct the register twice in one session, which is the signal the profile is wrong rather than the moment to absorb it silently.

What it deliberately does not do. It never changes the FACTS — numbers, caveats, risks and bad results survive every register, or "simpler please" becomes a hole in the honesty rules. It never touches artifacts written for future readers: ADRs, commit messages, code comments, QE reports and npm READMEs keep their own conventions, because their audience is not the current operator. And it is redacted from training-pair capture, because .dz/fa-training/ records the full prompt and is deliberately not gitignored — without that, "never write personal data into a project" would be defeated one path over.

What no test can prove. That the explanation actually landed is a judgement only the reader makes. The acceptance step is human by design and recorded as such (features/operator-profile/08_acceptance_cf7.md): the same passage rendered at two registers, and the owner says which one works. That run found a real defect — a term glossed in one breath and another assumed in the next — and produced the rule the block now carries: an explanation is self-contained; every term gets its gloss at first use in THIS passage, because the earlier text has scrolled away and a new session never had it.

Phase 1: Discover (what's available?)

npm install -g @dzhechkov/harness-cli    # install the CLI

dz help                                   # see all commands
dz pretrain                                # analyze project files → recommend by tech stack
dz recommend "build API and deploy to K8s" # keyword match → skills + toolkits
dz recommend "work on this project"        # unmatched? → labels suggestions as PROJECT-STACK, not task-derived
dz stats                                  # 58 packages, 260 skills, 10 targets, 14 presets
dz dashboard                              # visual panel — packages, adapters, skill packs
dz registry                               # browse all 260 skills by category
dz registry search kubernetes             # find specific skills
dz registry --category devops             # filter by domain
dz downloads                              # npm weekly download stats

Russian and English word forms share the same lexical search tier; both the query and the catalogue text are normalized. The current workspace reproducer prints the same count for the two Russian forms (the catalogue count may grow, but the pair must stay equal):

$ dz registry search "анализы"
Search: "анализы" — 8 result(s)
$ dz registry search "анализ"
Search: "анализ" — 8 result(s)

$ dz recommend "пришли анализы крови, хочу разобраться"
║  Topics: health

dz recommend --json reports topicSource as task, project-stack, or none. When no topic matches, human output explicitly says that any suggestions came from the project stack; if the stack also yields nothing, it prints that no recommendations were found.

Phase 2: Install (set up your workspace)

# Full setup with self-learning (recommended):
dz setup --target claude-code --preset devops  # pretrain + hooks + memory + installs the preset skills

# With AgentDB vector memory (semantic search + self-learning):
dz setup --target claude-code --preset devops --memory agentdb  # vector memory + agentdb MCP server

dz setup also installs the destructive-command guard into your project: the hook body at .claude/hooks/destructive-guard.cjs plus its PreToolUse entry on ^Bash$ in .claude/settings.json. It refuses a deletion whose target is a LITERAL path into a protected store (.dz/, .agentic-qe/, a .db/.sqlite/.rvf file) and prints, on every verdict it speaks about, the four things it does NOT decide — a target held in a shell variable, a relative target after a directory change, git rm, and quoted text under any head other than the delete verb or sh -c. dz hooks-sync --target codex installs the same check on the Codex host. Both hook bodies resolve @dzhechkov/harness-core by path, including the absolute path of the installation that emitted them, so a global install (npm i -g @dzhechkov/harness-cli) guards a project that has no local copy of the package. If the guard cannot load it says so on one line and lets the command through — it never blocks on its own failure, and it is never silent about failing.

Setup is additive here too, and deliberately incurious: if .claude/hooks/destructive-guard.cjs already exists WITHOUT dz's ownership marker, the file is yours. dz does not overwrite it, does not touch your settings.json entry for it, and — since a hook can only be proven to work by running it — does not RUN it either: a file a repository shipped is not something dz setup may execute on your behalf. You get one line saying so, and dz setup --force replaces the file (keeping a timestamped backup) if that is what you want.


# Or just install skills (no learning):
dz init --target claude-code --preset devops   # 30 DevOps skills
dz init --target openclaude --preset web3      # 12 DeFi skills for OpenClaude
dz init --target codex --preset mcp            # 16 MCP skills for Codex

# Or pick individual skills:
dz init --target claude-code --select terraform,kubernetes,docker-compose

# Or install from any npm package:
dz install @dzhechkov/skills-devops            # npm install + copy skills

# Verify everything is correct:
dz verify                                       # structural validation
dz doctor                                       # 7 health checks
dz list                                         # show installed skills
dz info --id terraform                          # detailed info about a skill

Phase 3: Use (work with your agent)

# Now use Claude Code / Codex / OpenCode / Hermes normally.
# Skills are auto-discovered from the platform's skills directory.
# Example in Claude Code:
#   "Review this PR" → pr-review skill activates
#   "Design an API" → api-design skill activates
#   "Fix this CI" → ci-fix skill activates
#   "Сделай AI-дайджест за февраль" → news-digest (cited report); "what's new since last week" → news-monitor (delta)

Phase 4: Create (build your own skills)

# Scaffold a new skill:
dz create-skill --name my-skill --description "What it does" --tier 2

# With BTO-compatible eval templates:
dz create-skill --name my-skill --bto

# Benchmark your skill (aim for Grade A):
dz benchmark .claude/skills/my-skill           # single skill — 20 L0 checks
dz benchmark packages/@dzhechkov/skills-devops --all   # batch all
dz benchmark skill-a --compare skill-b          # A/B compare

# Find skills to canonicalize from the ecosystem:
dz scout                                        # scan 11 sources (GitHub, npm+plugins, HN, ...)
dz scout --deep                                 # deep analysis with SKILL.md parsing
dz auto-canonicalize --source github.com/user/repo --pack packages/@dzhechkov/skills-devops

Phase 5: Maintain (keep skills fresh)

# Check for upstream changes (canonicalized skills):
dz sync-upstream --list                                 # which packages have external sources?
dz sync-upstream --all                                  # check all against upstream
dz sync-upstream --package packages/@dzhechkov/skills-devops  # check one

# Check installed skills vs canonical:
dz upgrade                                      # shows which skills need update
dz upgrade --target openclaude                  # check specific platform

# Sync canonical to legacy layout:
dz sync                                         # canonical → project skills
dz migrate                                      # detect legacy installations

# Author + gate custom Workflow loops (loop-plan/1):
dz workflow init --name my-loop --pattern pipeline --o my-loop.plan.json
dz workflow render my-loop.plan.json --o my-loop.js
dz workflow-lint my-loop.js --plan my-loop.plan.json --require-plan

# Cross-host state sync:
dz roam --apply                                 # sync agent state across machines

# Is the self-learning loop actually paying off?
dz compounding                                  # readiness + payoff report (INSUFFICIENT_DATA is a real answer)
dz deadwood --weeks 8                           # advisory deprecation candidates; shallow history → INSUFFICIENT_DATA
dz epoch-replay --mock --n 24 --effect 0.9      # $0 dry run of the cold-vs-warm verdict math
dz epoch-replay --emit                          # ready? emit the real cold-vs-warm work order

Phase 6: Share (publish to the world)

# Verified release — 4 HARD gates (tests, audit, syntax, smoke-boot) in FRONT of dz publish:
dz release --dry-run                            # print the full gate plan, execute nothing
dz release --filter skills-devops --tag         # gates for one release set; on green: git tag + notes
dz release                                      # gates for the whole workspace; green prints the ready dz publish command

# Publish updated packages to npm:
dz publish --dry-run                            # preview
dz publish --filter skills-devops               # publish specific package
dz publish                                      # publish all changed packages
dz publish --yes --mirror-cmd "node scripts/publish-mirror.mjs"  # live publish + required mirror receipt
dz publish --yes --no-mirror                    # explicit one-run mirror opt-out

# Export portable, self-contained skill bundles for a generic consumer (e.g. a LangGraph app):
dz bundle --preset news --out ./dist            # → ./dist/skills/<id>/ (SKILL.md + references/scripts/assets)
dz bundle --select news-digest,goap-research-ed25519 --out ./dist

For a live sweep that publishes at least one package, dz publish can run a command-hook epilogue. Set it for one invocation with --mirror-cmd, or persist the command in .dz/config.json:

{
  "publish": {
    "mirrorCommand": "node scripts/publish-mirror.mjs"
  }
}

The CLI exports DZ_PUBLISHED=name@version,… and appends --expect name@version,… --json. It marks the mirror confirmed only when the command returns JSON containing the live-manifest receipt; unconfirmed, skipped, and not-configured remain separate report states. If npm publication failed, the command returns exit 1. If npm publication landed but a configured mirror was not confirmed, it returns exit 3 and prints a usable re-run: command. --dry-run, --no-mirror, --bump-only, and a live sweep with zero published packages do not execute the hook. A malformed or unreadable .dz/config.json leaves the mirror not-configured, returns the ordinary publish exit code, and prints ⚠ mirror: .dz/config.json unreadable — …; an explicit --mirror-cmd still takes precedence. The repository wrapper prints human-readable output by default; scripts/publish-mirror.mjs --json prints exactly one JSON document (the dz publish epilogue always selects this mode).


Three Ways to Install Skills

| | Individual Skill | Preset | npx Package | |---|---|---|---| | What | 1 SKILL.md file | Curated list of skill names | Full toolkit with orchestration | | Contains | Instructions for 1 task | N skill references | Skills + commands + rules + shards + agents + memory | | Pipeline | No | No | Yes (phases, checkpoints, governance) | | Self-learning | No | dz setup adds it | Built-in | | Install | dz init --select X | dz setup --preset X | npx @dzhechkov/X init | | Example | terraform | devops (30 skills) | keysarium (7-phase research) |

# One skill:
dz init --target claude-code --select design-thinking

# Curated set by topic (recommended):
dz setup --target claude-code --preset meta          # 20 development skills + self-learning

# Full toolkit with orchestrated pipeline:
npx @dzhechkov/keysarium init                        # 7-phase research + commands + memory

When to use which:

  • Need 1 specific capability--select
  • Need a themed set that works together → --preset
  • Need a full pipeline with commands and governance → npx

dz sign / dz verify-pack — cryptographic tamper-evidence

Ed25519 over a file manifest, plus a CycloneDX SBOM. Zero dependencies (node:crypto).

What it answers: are the bytes I am looking at the bytes the holder of the pinned key signed? What it does NOT answer: whether those bytes are any good. A signature gives provenance and tamper-evidence, never truthfulness.

# One-time: generate the Ed25519 keypair. The PRIVATE key is written OUTSIDE the repo (mode 0600);
# the PUBLIC key is printed — commit it as keys/dz.pub. dz refuses an --out inside the repo tree.
dz sign --init --out ~/.dz/keys/dz.key

# Sign a pack. The private key MUST live outside the repo — dz refuses otherwise.
dz sign --pack packages/@dzhechkov/skills-qe --key ~/.dz/keys/dz.key

# Verify an unpacked artifact. The public key comes from the REPO (keys/dz.pub), never from the pack:
# whoever replaced the artifact would have replaced a key shipped inside it.
dz verify-pack --pack ./unpacked-tarball/package             # exit 0 = artifact unmodified
dz verify-pack --pack ./downloaded-pack --pubkey keys/dz.pub # explicit trust root

# The SBOM on its own (CycloneDX 1.5, a file-level bill of materials for the pack):
dz sbom --pack packages/@dzhechkov/skills-qe                 # print to stdout
dz sbom --pack packages/@dzhechkov/skills-qe --out sbom.json # write to a file

A single flipped byte, a deleted file, or an added file inside the authenticated npm shipment set fails verification and names the path. Directory segments node_modules, .git, .agentic-qe, and .dz are unsigned local/dependency/VCS state by design and are absent from both manifest and SBOM; an OK verdict makes no claim about bytes placed there. A symlink smuggled anywhere else still fails loudly. sbom.json is required even though it is not self-hashed: after the signature is valid, verify-pack derives the canonical CycloneDX bytes from the signed manifest and rejects a missing, malformed, duplicated, renamed, re-hashed, or metadata-modified SBOM. This keeps the trust chain acyclic without leaving the SBOM as unauthenticated decoration. CycloneDX SHA-256 fields describe raw bytes only. Because packers may reorder ordinary package.json metadata, format v3 publishes its semantic canonical digest through explicit dz:canonical-json-sha256-v2 and dz:digest-basis=package-json-ordered-conditions-v2 properties. Canonicalisation still sorts packer-noise keys, but preserves every object key order under exports, imports, and typesVersions; changing first-match condition order therefore changes the signed digest. Current/v3 signing and verification refuse malformed, duplicate-key, or precision-losing JSON. Verification retains compatibility-only readers for existing v1/v2 manifests; new evidence emits v3. dz sign hashes the pnpm tarball because pnpm rewrites package.json and may synthesize or omit files; the authoring tree is therefore not the signed object. dz publish rebuilds and verifies that exact artifact, while direct verify-pack is for an already unpacked artifact or installed package. Re-sign after ANY pack change (the manifest hashes package.json too) — sign is the LAST step before publish. Every degenerate input (no manifest, empty file list, empty signature, no public key) fails closed — absence never reads as success. dz doctor and dz drift-check run this check over the installed packs: a tampered pack is fatal (blocks); an unsigned pack or a missing trust root is reported, not fatal (transitional — the existing packs are not yet signed).

dz publish runs the check before publishing anything. With keys/dz.pub committed, an unsigned or mismatching pack blocks the release. Until then, packs publish unsigned and dz publish says so on every run; --require-signing turns that into a refusal today.

From Claude Code, in plain language:

"Sign the QE skill pack with my key at ~/.dz/keys/dz.key, then verify it." "Check whether the pack I just downloaded matches what we published." "Publish, but refuse if anything is unsigned."

Signature checks in dz doctor and dz upgrade

dz doctor verifies every installed skills-* pack against a pinned Ed25519 key, and dz upgrade verifies what it just installed. A pack that does not match its signed manifest is fatal:

dz doctor                      # ... signatures: 23 verified, 0 unsigned, 0 TAMPERED (the gate is ARMED: keys/dz.pub committed)
dz doctor --require-signing    # an unsigned pack becomes fatal too
dz upgrade                     # a TAMPERED pack aborts the upgrade
dz doctor --pubkey ./my.pub    # verify against a key you pinned yourself

Key precedence: --pubkey > the repository's keys/dz.pub > the key shipped inside harness-cli. The key never comes from the pack being verified — whoever replaced the pack would have replaced a key that travelled inside it.

Honest limits. The packaged key lives in the verifier and vouches for other packs; a compromised harness-cli is outside the threat model, because you have already run its code. And a signature proves the bytes are unmodified — never that the skill is any good. Today no key is committed, so every pack reports unverifiable and nothing fails.

From Claude Code, in plain language:

"Run doctor and tell me if any installed pack was modified." "Upgrade, but abort if anything fails its signature."

npm provenance on release

dz publish appends --provenance only where an OIDC token can be minted — GITHUB_ACTIONS=true plus both ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN, which GitHub exports under permissions: id-token: write.

dz publish                 # auto: provenance in CI, silent no-op locally
dz publish --provenance    # force. FAILS before the batch if the environment cannot mint a token
dz publish --no-provenance # escape hatch for a registry outage; prints why it was used

Provenance proves which workflow, at which commit, built this tarball — and there is no private key for anyone to leak. It does not prove the code is good, and an attacker who can push to main and trigger the release job gets a perfectly attested malicious package.

A ready-to-install workflow is at features/publish-provenance/07_code_changes/publish.yml; copy it to .github/workflows/ and add an NPM_TOKEN secret.

Lesson quarantine — a fresh lesson is a hypothesis, not knowledge

Self-learning has a poisoning problem: the moment dz teach stores a lesson, it ranks alongside patterns proven over months and can ride the auto-inject hook into your next task's context — even if it is wrong, one-off, or junk. Quarantine (opt-in) closes the gap between COLLECT and RANK:

// .dz/config.json
{ "memory": { "learning": {
    "quarantine": true,            // fresh lessons start as quarantined hypotheses
    "quarantineDamp": 0.5,         // rank multiplier for ⚠q hits in recall (0..1]
    "quarantineExpireDays": 30     // unconfirmed after N days ⇒ expiry CANDIDATE (report only)
} } }

Three surfaces, three strictness levels — and promotion is EARNED, never automatic:

dz teach "..."                        # → "⚠ quarantined: excluded from auto-inject, damped in recall"
dz teach "..."                        # the same normalized text reinforces the existing lesson instead of adding a duplicate; quarantine is preserved
dz recall "topic"                     # ⚠q hits are VISIBLE but marked + rank-damped (never hidden)
# the UserPromptSubmit auto-inject hook EXCLUDES ⚠q lessons entirely (logged, never silent)

dz teach --reinforce "<exact text>"   # confirming a lesson IS its promotion
dz recall --promote <dzId> --apply    # or promote explicitly (dry-run by default)

dz consolidate --prune-quarantine           # report expired unconfirmed lessons (dry-run)
dz consolidate --prune-quarantine --apply   # remove them (snapshots first) — a SEPARATE gate,
                                            # never coupled to --prune-noise (unproven ≠ garbage)

Absent config = zero behavior change. Existing lessons are grandfathered as promoted; a corrupt quarantine marker reads as promoted (a metadata glitch must never isolate proven knowledge). When to use: any project where subagents teach lessons unattended — the quarantine is the gate between "an agent wrote this down" and "agents now act on it".

Target parity — dz parity (the honest feature × target map)

The harness runs on 10 targets, but not every feature runs everywhere: hooks, MCP (Model Context Protocol) and the Workflow runtime exist only on some platforms. dz parity answers "what do I actually get on X?" from a COMPUTED capability model — the matrix is never hand-written (a hand-maintained table is a drift surface; the model lives next to the code, under tests that refuse an unclassified 11th target).

dz parity                    # the full grid: ✓ full / ◐ manual (via which form) / — absent
dz parity --target codex     # one target in detail: what works, THROUGH what
dz parity --json             # machine contract (targets, capabilities, per-cell level + via)

Example (real output, trimmed):

dz parity — codex  (capabilities: shell, skills, mcp)
  ✓ dz CLI (all commands)                    via shell command
  ◐ feature-adr pipeline                     via interactive skill (plain /feature-adr)
  ◐ Step-10 Delivery Gate                    via dz delivery-check (CLI 4-plane hand-off protocol)
  ◐ Integrity claim-check                    via dz claim-check (CLI) + publish gate

When to use: before promising a workflow to a teammate on Cursor/Codex/Hermes; when choosing a target for a project; as the requirements input for porting a feature to more targets.

Does the learning loop actually pay? — dz compounding

dz's self-learning has collect, rank and apply legs — this command answers whether they COMPOUND, honestly. Ported from rUv's darwin-mode with a deliberate split: the seeded statistics came over verbatim (deterministic bootstrap, lower-95 promotion, and a minimum of 5 samples per arm — darwin's own calibration measured a 33% false-discovery rate at n=3); darwin's measurement legs did NOT (they score fixtures, not your data). The measurements here run over what your machine actually recorded:

$ dz compounding
  POOL PAYOFF: 154 lessons · 27 ever injected by the apply leg · 89 touched by any recall
    write-only ratio (strict bar): 82%
  GUARD TRAJECTORY (violations, first half vs second half of the audit span):
    ↓ no-workspace-star: 31 → 0
    ↓ readme-first: 49 → 4
  COLD-VS-WARM REPLAY: 2 unique prompt event(s); 5 needed — queries are recorded as of 2026-07-28
  INSTRUMENTATION: last apply-leg record … — live
  EVIDENCE CHAIN .dz/recall-usage.jsonl: verified · 3 chained · 133 pre-chain (uncovered)
  EVIDENCE CHAIN .dz/guard-audit.jsonl: verified · 3 chained · 82 pre-chain (uncovered)
  LESSON → RULE FUNNEL (calendar month, observed traffic only):
    2026-08 · eligible/attempted/accepted/executions NOT MEASURED (promotion-history-not-recorded)

Four honesty rules are load-bearing:

  • a gate without enough data says INSUFFICIENT DATA — never a verdict (the apply-leg log turned out to have been silently dead for 19 days; "no data" is a finding, not a pass);
  • readiness is not a result — the replay section says ready, never promote;
  • improvement is judged by RATE (violations per audit), so a quiet afternoon cannot masquerade as progress;
  • zero promotions is not itself a finding — the funnel names a stopped stage only when its predecessor is non-empty and it stays empty for three consecutive measured UTC months. A missing, malformed, unreadable, unobserved, or anchorless source prints NOT MEASURED (<reason>), never 0.

The funnel is prospective: ordinary non-dry dz guard promote runs append bounded candidate/status observations to the existing .dz/promotion-state.json; --dry-run still writes nothing. Guard firings join by the opaque digest of the exact effective template+params carried in the audit row, never by a display rule id alone. Text and --json render the same counts/status/findings model and issue no overall learning-health verdict.

The prompt queries that make replay possible stay on your machine: .dz/recall-usage.jsonl is git-ignored, entries are truncated at 200 chars and flagged when truncated (a prefix is not a prompt, so flagged rows never count as replayable).

dz deadwood --weeks 8 applies the same no-data discipline to harness maintenance: until command history spans the requested window and sample floor, it prints VERDICT: INSUFFICIENT_DATA. Once ready, it lists only human-review deprecation candidates, reports safety-net exclusions with their written reasons, and labels skills no-instrumentation because no skill invocation signal exists. It never deletes, disables, renames, or deprecates a command, skill, or rule.

Is the evidence itself intact? — the event chain

Every number above is computed from two JSONL files, and a compaction bug already inflated one of them once (read totals grew 2 → 4 → 6 across three compactions, fixed 2026-07-28). So each record appended to .dz/recall-usage.jsonl and .dz/guard-audit.jsonl now carries a sequence number and a hash of the line before it, and both dz compounding and dz doctor verify the chain:

$ dz compounding | grep 'EVIDENCE CHAIN'
  EVIDENCE CHAIN .dz/recall-usage.jsonl: verified · 3 chained · 133 pre-chain (uncovered)

$ dz doctor            # silent while clean; on damage:
  [XX] evidence chain (.dz/guard-audit.jsonl) - 1 defect(s): BrokenLink@L3 —
       learning verdicts computed from this log are unsafe

Defects are named, not lumped: BrokenLink (an edited or lost record), DuplicateSeq (a duplicated record, or two writers racing), NonMonotonicSeq (an unrecorded restart), TornTail (a partial write), DoubleCounted (a rewrite that emits more events than it read — the 2 → 4 → 6 class), plus three that keep a rewrite from certifying itself: LedgerImbalance, MalformedLedger and ClaimInterrupted.

Two rules make the check hard to fool, both learned from cross-model review:

  • compaction refuses to launder. A rewrite that re-chains a damaged file would turn corruption into a clean chain — so compaction verifies its input first and REFUSES a defective one. The log then grows past its size cap, on purpose: the cap is a convenience, the evidence is the product.
  • a rewrite cannot silently eat a concurrent append. The whole-file rewrite takes an exclusive lock and re-reads the live file immediately before the rename; an append that landed in between aborts the attempt and is folded into the retry instead of being overwritten.

Honest scope, stated everywhere it appears: this is corruption detection for our own bugs — compaction, torn writes, races. FNV-1a is not cryptography and the threat model has no adversary: anyone who can edit the log can recompute the chain. When to use: read the line before you quote any dz compounding number, and after any crash that interrupted a write.

Three properties make it safe to run on a per-prompt hook: chain fields come from the last line only (no full-file scan per append); records written before chaining existed stay valid and are reported as an uncovered pre-chain prefix rather than flagged; and a tail that cannot be read never blocks the write — the writer starts a fresh, explicitly marked segment.

Did the lessons actually change outcomes? — dz epoch-replay

dz compounding says a cold-vs-warm replay can be run. dz epoch-replay runs it and reports what it found: Epoch 0 (cold — the prompt alone) vs Epoch 1 (warm — the same prompt plus exactly the lessons the apply leg injected), on the same instances, scored into a three-valued verdict.

The test is PAIRED. Each instance is one judgment on one prompt, so the statistic is a single binomial over decisive pairs: p̂ = warm wins / (warm wins + cold wins), with a 95% Wilson interval reported on the lift scale 2p̂ − 1. Ties carry no direction — they are excluded from the denominator and reported separately.

SUPPORTED only when the lift interval lies entirely above zero. FALSIFIED only on harm (entirely below zero) or on a passed non-superiority test — the lift upper bound below a pre-registered margin, default 0.05, at 10+ decisive pairs. Everything else is INCONCLUSIVE, a first-class honest outcome; below 5 decisive pairs there is no verdict at all.

A tie is under-powered, not refuted. 6/12 gives a lift interval of [-0.492, 0.492] — that excludes nothing, so it reads INCONCLUSIVE. So does a perfectly even 500/500 over 1000 pairs (lift upper 0.0619): the most uninformative result the protocol can produce must not be reported as a refutation. A refutation has to clear a bar too.

Try it at $0 first — --mock generates seeded synthetic outcomes at a TRUE effect you choose, and runs them through the real verdict math:

$ dz epoch-replay --mock --n 24 --effect 0.9 --seed 20260729
  COLD (epoch 0, no injected lessons): 1/24   CI95 [0.007, 0.202]
  WARM (epoch 1, apply-leg lessons):   23/24  CI95 [0.798, 0.993]
  VERDICT: SUPPORTED
    warm 23/24 CI [0.798, 0.993] is DISJOINT above cold 1/24 CI [0.007, 0.202]

$ dz epoch-replay --mock --n 24 --effect -0.9 --seed 20260729   # → FALSIFIED (harm)
$ dz epoch-replay --mock --n 24 --effect 0.4  --seed 20260729   # → INCONCLUSIVE (neither separates nor excludes)
$ dz epoch-replay --mock --n 12 --effect 0    --seed 7          # → INCONCLUSIVE (6/6 tie: under-powered, NOT refuted)
$ dz epoch-replay --mock --n 24 --effect 0.9 --seed 20260729
  SLICE: all · 24 scored instance(s) · 24 DECISIVE pair(s)
  COLD (epoch 0, no injected lessons): 1/24 decisive   CI95 [0.007, 0.202]
  WARM (epoch 1, apply-leg lessons):   23/24 decisive  CI95 [0.798, 0.993]
  LIFT (paired, 2p−1 over decisive pairs): +0.917  [0.595, 0.985]
  VERDICT: SUPPORTED — the lift interval lies ENTIRELY above zero

Every mock run prints SYNTHETIC … it is NOT evidence about the learning loop, and the same seed gives byte-identical output — a demo is a reproducer.

Real mode: the runner ORCHESTRATES and SCORES — it never calls a model. Generation and judging happen out of band, so the core stays pure, offline and reproducible:

$ dz epoch-replay --emit                   # → .dz/epoch-replay/work-order.json  (git-ignored: raw prompts)
     25 instance(s) · seed 20260729 · blind A/B assignment PRE-REGISTERED
  # 1. have an agent fill coldPlan / warmPlan for each item (symmetric length, same task)
$ dz epoch-replay --judge .dz/epoch-replay/work-order.json     # → blind judge prompts
  # 2. have an EXTERNAL, cross-model judge answer them → [{ "id": …, "winner": "A|B|TIE" }]
$ dz epoch-replay --score judgments.json --work-order .dz/epoch-replay/work-order.json --slice task

Three things make that blind real rather than decorative:

  • The judge sees {id, prompt} and nothing else. No assignment, no arm names, no slice label, not even a path back to the work order. The judge file is byte-identical whichever way the assignment fell, so it cannot be decoded. (Skipped items are reported on stdout, not in the file — their reasons name arms.)
  • The work order is integrity-checked. It carries a sha256 digest over its pre-registered core (version, seed, margin, corpus fingerprint, every [id, warmIsA]); --judge and --score recompute it and re-derive every assignment from the stated seed, refusing on any mismatch. A hand-written order does not buy a verdict.

    Honest scope: this is an integrity check against accidental corruption and mismatch — not a cryptographic commitment. The hash is self-contained, so a determined operator can re-forge it (seed-searching a matching assignment at n=12 takes a few thousand tries). The threat model is you making a mistake: a hand-edited file, a stale order paired with fresh judgments. The honest-use contract is procedural — emit once, then judge, and keep the emitted file. --emit records emittedAt + a corpus fingerprint and --score prints the digest, seed and margin, so a reviewer can ask for the original and compare three numbers.

  • The non-superiority margin is pre-registered. --margin is accepted only at --emit, is stored in the work order and covered by the digest, and --score refuses a --margin flag — a margin chosen once you can see the counts is not a pre-registration, and --margin 99 at scoring time would simply buy FALSIFIED. Out of range (outside (0, 0.5]) is refused, not clamped.
  • Corrupt input is refused, not measured. Duplicate judgement ids exit 1 rather than counting one opinion N times. Unknown ids and unparseable winners are skipped with a reason, never guessed.

The warm arm's only delta is the injected lessons: no gold answers, no verdicts, no outcome labels ever enter a work order.

When to use: after dz compounding reports the replay as READY; before claiming that recall "works"; and any time you want the claim re-checked as the corpus grows.

Обратный мост QE: Claude-ревьюер из Codex-сессии — dz qe-bridge

The cross-family rule ("the family that writes the code must not review it") was enforceable in one direction only. When Codex hosts the run there is no Claude agent plane to dispatch from — and dz reqe's brief admits it: for a claude review family it prints null where the codex branch prints a ready command. dz qe-bridge is that missing vehicle: a plain-shell command that probes a Claude model, sends a Step-8-shaped brief over SCOPED extracts, and PARSES the verdict.

# MEASURED 2026-08-19 on this repo — reproducer: the exact command below, reviewing a real shipped feature
$ dz qe-bridge --family claude --slug wave1-scorer-negation --coder-family codex --model opus
dz qe-bridge: GRADE C from claude/opus — 7 finding(s) in 343s
  report:  features/wave1-scorer-negation/08b_reqe_report.md
  signoff: features/wave1-scorer-negation/.fa-state/qe-bridge/signoff-2026-08-19T18-48-45-545Z.json
  settle:  dz reqe --slug wave1-scorer-negation --done --report features/wave1-scorer-negation/08b_reqe_report.md
  the bridge REPORTS (any grade exits 0); gating stays with dz reqe and the host pipeline.

# the same command with a binary that cannot answer — a failed call, and NO report to settle with
$ DZ_QE_BRIDGE_CLAUDE_BIN=/bin/false dz qe-bridge --family claude --slug wave1-scorer-negation --coder-family codex
dz qe-bridge: FAILED — probe-failed
  no candidate model answered the liveness probe — opus: exit 1, no `OK` in 0 chars of stdout; sonnet: exit 1, …; haiku: exit 1, …
  record: features/wave1-scorer-negation/.fa-state/qe-bridge/failed-2026-08-19T18-48-52-931Z.json
  no report was written — an unparseable or absent review is never a passing one.

# with a debt on record, the report settles it through the untouched fail-closed path
$ dz reqe --slug add-x --done --report features/add-x/08b_reqe_report.md
dz reqe: debt settled: re-QE grade C (report …) — settlement appended to features/add-x/08_qe_report.md

When to use: you are hosting a run outside Claude Code (Codex, CI, a plain terminal), you have just written code, and the independent reviewer must be the OTHER family. Also: whenever dz reqe lists a debt whose coder family is openai.

The reviewer runs isolated. Both calls (probe and review) run from an EMPTY temporary directory with --safe-mode --strict-mcp-config --tools '' --no-session-persistence, and the verdict is read from the --output-format json result envelope. Why: customization output lands on the same stdout — MEASURED on this machine, a session-start plugin prints a banner ahead of the model's answer — so a crafted hook could otherwise print a complete grade-A signoff and a stream parser would believe it (reproducer: features/qe-bridge-claude/07_code_changes/mutants/c1-forgery-repro.mjs). Residue, stated: --safe-mode leaves ADMIN-MANAGED policy settings in force, and no flag proves which binary answered.

What makes the grade valid. Three channels must EXIST and AGREE, each read LAST-anchored, and the marker must be the FINAL content of the answer: the terminal QE-BRIDGE-SIGNOFF grade=<A-F> findings=<n> line, the last fenced qe-bridge-signoff JSON block, and the report's own line-anchored GRADE: line. Repo content flows into the prompt and comes back quoted, so a planted earlier verdict must lose — and it does (there is a test whose fixture plants grade=A early and requires the genuine trailing grade=D to win). Extracts are DEFANGED on the way in, so quoted content can never mint a verdict. Empty, gradeless, marker-only or self-contradicting output is a named failure — one of 17 closed reasons (envelope-unparseable, marker-not-terminal, findings-count-mismatch, grade-mismatch, ambiguous-grade, audit-write-failed, report-write-failed, … ; closed BOTH ways — every one is produced by a real run in the suite and leaves a record) — with an audit record under features/<slug>/.fa-state/qe-bridge/ and the raw stdout beside it, never findings: []. Finding numbers are the reviewer's: a missing, non-positive or duplicated n fails the call instead of being renumbered, and a marker whose findings=<n> disagrees with the block is findings-count-mismatch.

The record is auditable, not just a conclusion. Every run writes a runId, the resolved executable plus binOverride (true whenever DZ_QE_BRIDGE_CLAUDE_BIN was used — the documented TEST SEAM; there is no --claude-bin flag), the prompt sha256, the byte offsets at which each channel was found, the requestedOut path and reportWritten: true|false — so "no report was written" is a stated fact rather than an inference from an absent file. Records and reports are written 0600 in a 0700 directory, through O_EXCL, with realpath containment that refuses a symlinked parent — and the state directory itself is contained the same way, before anything is created in it. The audit trail is written BEFORE the report and corrected after it, so reportWritten can only ever understate; if the trail cannot be written at all, the run FAILS (audit-write-failed) rather than shipping a verdict nobody can re-derive. The record also carries writeSequence — diagnostic sequencing metadata: a self-reported, process-local trace of the signoff-write-started / report-written / record-update-prepared steps with monotonic stamps taken at each named event (the start of the first record write, the moment the report is on disk, and just before the atomic record update). It replaces a file-mtime comparison in the tests (a race); the write ORDER itself is proven by the report-failure test (record exists and says false when the report never lands) and the failpoint test (reportWritten:true only after the report), not by this field.

Exit codes: 0 a signoff was parsed (ANY grade — a grade F still exits 0: the bridge reports, it does not gate), 1 a named failure, 2 a usage error. Honest limits: it proves the call was procedurally sound (a live model was probed, a scoped brief was sent, a self-consistent verdict came back); it cannot prove which model authored the text, and it cannot classify your secrets — the extracts you scope are what leaves the machine. RU: мост в обратную сторону — из Codex-сессии позвать независимого Claude-ревьюера и получить РАЗОБРАННЫЙ вердикт; пустой или безоценочный ответ — это названная ошибка, а не «чисто».

Строка объявления стадии — что за модель сейчас запустится

Каждый прогон /feature-adr печатает перед каждым диспатчем стадии одну строку — всегда, без флага:

▸ router · session · routing not requested
▸ adr · fable · budget table cell
▸ code · codex:gpt-5.6-sol:high · coder knob = codex · landed barrier
▸ qe · sonnet · cross-family QE (the coder never self-reviews)
▸ qe · opus · codex refused before dispatching — nothing ran

Последняя строка — про случай, который легко принять за отработавшую ступень: модель Codex ОТВЕТИЛА на пробу, но ступень отказалась строить диспатч (непригодный ref области ревью, небезопасный id). Ни один агент не запускался, и строка говорит именно это, а не «предыдущая ступень ничего не отдала» — та формулировка утверждала бы запуск, которого не было.

Тот же разбор действует, когда рантайм вовсе не знает типа агента codex:codex-rescue: строка скажет codex unsupported at this dispatch — Claude. И исход принадлежит своему вызову — дизайн- стадии идут параллельно, поэтому соседняя стадия не может подменить твоей стадии причину.

Три поля: стадия · модель · ветка, которая эту модель выбрала. session означает, что маршрутизация не запрашивалась и стадия наследует модель сессии. Хвост landed barrier появляется там, где стадия резолвится на Codex И пишет артефакт вне процесса (code, plan и четыре стадии дизайна): конвейер после диспатча ЖДЁТ, пока файл ляжет на диск, — если прогон замер, эта пометка говорит, почему.

Строка описывает фактический диспатч, а не намерение: возобновлённая из точки сохранения стадия не печатает ничего (она не запускается); при coder=codex-fallback первая ступень объявляется как Claude, вторая — как Codex в момент своего запуска; codex-строка несёт пробированный id модели, тот же, что попадёт в итоговый modelsUsed. Модель и причина берутся из ОДНОГО возвращённого значения резолвера, поэтому строка, диспатч и отчёт не могут разойтись.

Пересмотр после аварийного само-ревью — dz reqe

The feature-adr pipeline's cross-model guard says the model that writes code must not review it. Historical usage-switched runs could suspend that guard under provider-limit pressure: coder AND Step-8 QE both ran on Codex. The rule used to say "re-review manually after limits reset" — an instruction nobody remembers. dz reqe turns it into a debt with a lifecycle: the run records features/<slug>/.fa-state/reqe-due.json, dz usage --json carries the outstanding count as reqeDue, and settlement is FAIL-CLOSED.

$ dz usage --json
{"sessionPct":null,"weeklyPct":null,"routing":"disabled-by-design","spend":{"days":[...],"total7d":{...},"byModel":{...}},"reqeDue":1}

$ dz reqe                        # the ledger
dz reqe — 1 unsettled re-QE debt(s):
  add-x  coder=openai qe=openai grade=B  2026-07-30T10:00:00Z  → dz reqe --slug add-x

$ dz reqe --slug add-x           # the ready cross-family review brief (the OTHER family than the coder)
$ dz reqe --slug add-x --done --report features/add-x/08b_reqe_report.md
dz reqe: debt settled: re-QE grade C (report …) — settlement appended to features/add-x/08_qe_report.md

When to use: any time dz usage --json reports a positive reqeDue, or a feature-adr result carried reqeDue: true. Fail-closed settlement: the report must exist, be non-trivial, and name exactly one line-anchored GRADE (the boilerplate phrase GRADE A-F does not count); the run's own 08_qe_report.md can never settle its own debt (real-path AND inode compared — a hard link doesn't fool it); the settlement epilogue lands in 08_qe_report.md and the due-file rotates to reqe-settled.json (evidence kept, never deleted). Honest scope (printed by the command): nothing re-runs QE automatically, and the validator proves the settlement is procedurally sound — which model authored the report stays with the human running the brief. RU: гард «кодер не ревьюит сам себя» осознанно снимается под лимитом; dz reqe превращает инструкцию «перепроверь потом» в долг на диске — виден как reqeDue в dz usage --json, гасится только настоящим кросс-семейным отчётом с грейдом.

Spend you can inspect — dz usage

dz usage reports cost-weighted token spend from local Claude Code and subagent transcripts. It does not predict provider limits: there is no provider usage API, weekly resets are per-account, and ad-hoc resets make a local denominator non-measurable. Feature routing is therefore disabled by design.

Two things changed to make it mean something:

  • Cost-weighted, not a raw sum. A flat token sum is 89–99.7% cache-read (MEASURED), which grows with conversation length, not with work done — two sessions doing identical work differed by orders of magnitude. Tokens are now input-equivalents (input 1x, cache-write 1.25x — 2x for a 1-hour TTL write, cache-read 0.1x, output 5x).
  • Subagent transcripts count. <session>/subagents/*.jsonl carry real, non-duplicated usage and were silently excluded.
  • Symlinked project directories are scanned by real path, each real directory once. Broken links and symlinks to files are skipped.
  • The walk is safe and bounded. Only regular files are read, symlinked files and directory components cannot create duplicate walks or loops, and the file cap keeps the NEWEST transcripts so a long history cannot push current usage out of view.
dz usage         # seven UTC days + seven-day total + model shares + today-by-model
dz usage --json  # sessionPct/weeklyPct stay null; spend carries days, total7d, byModel, daysByModel

The compatibility keys sessionPct and weeklyPct remain present and always null, so existing feature-adr probes keep parsing the payload without treating a guess as a routing signal.

What unknown means, and which window each block covers. The "by model" table is a seven-day window total — it is the same seven days as the daily table above it, collapsed across models, never a per-day figure (a defect this project has hit before: a weekly figure read as a daily one). A model row named unknown is the aggregation's fallback bucket, literally event.model ?? 'unknown' in spendReport — it catches BOTH of the two ways an event can carry no usable model: an event with no model field at all, and one whose model string did not match any of the four known substrings (fable/opus/sonnet/haiku). (Fix-round-1, Codex review MEDIUM #3: an earlier revision of this paragraph said unknown was "not an event without a model" — the opposite of what the code does; corrected to name both causes.) MEASURED on this machine, the second cause dominates — almost entirely <synthetic> assistant-turn markers, not a parsing failure — and unknown is always shown, never hidden, because a hidden unknown row would make the visible rows undercount the real total. Both the "by model" table and the "today by model" block print a third column: the model's share as a fraction 0..1 (two decimals), not a percentage — by model shares are of the seven-day total, today by model shares are of today's own total, and a complete breakdown's column sums to 1.00 in either block (never 100 — that would be the percentage form). The --json payload additionally carries spend.daysByModel: one entry per day (same dates as spend.days, same order) with that single day's {model → weightedTokens}, unknown included — read daysByModel.at(-1) for today's per-model spend, which the plain-text report prints as the today (<date>) by model block right after the seven-day "by model" table. The invariant this rests on — every model breakdown reconciles exactly with the totals it was sliced from — is spendInvariantViolations() in harness-core (relative tolerance max(1e-6, 1e-9·max(|a|,|b|)), and a NaN/Infinity