Skip to content

nacharbeit ​

Reviews a Claude Code plugin against the official Anthropic standard, then reworks the mechanical and local-rewrite share of what falls short.

The name. Nacharbeit is the manufacturing word for exactly that: rework of a part that did not pass, back to the drawing. This plugin is the review that finds where a plugin's skills, agents, commands, workflow prompts, hooks, scripts, report viewers, manifest, README and developer docs fall short of the standard, and the fix pass that reworks the mechanical and local-rewrite share of that — under a lock, blind-verified, and never past the tier a model can apply without judgement it lacks.

  • Use when you have written or inherited a plugin and want to know where it falls short of the Anthropic standard, and to have the safe share of that fixed.
  • Not when the thing under review is the application a plugin is pointed at — use befund for documented conventions, lehre for an enforced doctrine or passung for undocumented variants.

Use case ​

Situation. You added a skill and a hook to andon and want to know whether either would load with empty metadata or silently discard its deny, before it ships. Call. /nacharbeit:nacharbeit-review review the andon pluginWrites. analysis/nacharbeit/ (baked args, run.js, return.json, results) and, inside werkstoff, docs/prompt-quality-findings.md. It never edits the plugin; that is nacharbeit-fix. Next. Read the calibration line first, then the per-plugin verdicts. Run /nacharbeit:nacharbeit-fix for the haiku and sonnet tiers and decide the opus- and human-tier entries yourself.

nacharbeit review 2026-09-09T06:12:04Z · rubric 3f9c1a2b7d0e · 3 plugins, 19 batches, 20 fixtures (kinds: assets, docs, hooks, manifest, scripts, skills)
calibration: r1 recall 0.76 (min angle 0.40, min family 0.50) → rewrite → r2 recall 0.83 (min angle 0.60, min family 0.67)
sealed hold-out: 0.79 overall; Q 0.81, HQ 0.75, SQ 0.67, AQ 0.75, PQ 0.80, DQ 1.00 — every family above its floor, finder frozen
...
backlog: haiku 31 · sonnet 96 · opus 2 · human 4
held for a person (never auto-applied):
  [opus ] zirkel: plugins/zirkel/workflows/solve.js — design a real gate for each stage's output_contract …
  [human] andon:   plugins/andon/skills/andon-loop/SKILL.md — decide whether andon-loop supports scoped runs …

Excerpt from the ## Output format block of plugins/nacharbeit/skills/nacharbeit-review/SKILL.md.

Why this exists ​

The instrument behind this plugin was built in PR #56 as repo-internal tooling: a frozen rubric that settles the seven places official Anthropic guidance and third-party sources disagree (official docs win), a sabotage-tested linter for the mechanical rules, a review workflow whose sonnet finder must pass a planted-defect calibration and a sealed hold-out before it grades a real file, and a fix workflow that applies only the haiku and sonnet tiers with a blind verifier behind every edit. It reviewed the nine plugins of this workshop, found 244 verified defects, and fixed 274 of 297 entries.

Three things were wrong with leaving it there. It could not be installed anywhere else. It graded prose only — rubric decision F5 scoped hooks out, and scripts, viewers, manifests, READMEs and the docs that wire a plugin in were never looked at, although every one of them has shipped broken in this repo (a hooks.json whose deny the runtime silently ignored, a plugin missing from the root README, a .gitignore line swallowing a whole scripts/lib/ package). And its fix pass edited other plugins' files with nothing but prose telling it which ones — the one layer this repo has measured to hold one run in three.

nacharbeit is that instrument as a plugin, with five more rule families, a PreToolUse hook that turns the fix scope into a refusal, and every werkstoff-specific path behind a flag with a werkstoff default.

What it is not ​

  • Not a design or code reviewer for the application a plugin is pointed at — that is befund (documented conventions, idioms), lehre (an enforced doctrine) and passung (undocumented variants). nacharbeit's object is the plugin.
  • Not cupertino-handbook-check / cupertino-handbook-fix, which check new work against a project's persisted handbook; nacharbeit checks a plugin against a fixed, externally sourced rubric.
  • Not a proof that a fix is correct. Its verifier checks that an entry was applied and nothing regressed; whether the reworked skill works is andon-verify's job, and the fix skill hands off there.
  • Not a Markdown-only reporter, and not a dashboard of its own making. The review's primary output is the Markdown findings report; assets/review-viewer.html (built by scripts/build_review_html.py, see The review report) renders findings by rule family, severity and fix tier, adds none of its own, and is graded by nacharbeit's own A-* rules like every other plugin's viewer.
  • Not a planning or spec-authoring entry point — that is arbeitsplan-compile (the arbeitsplan plugin), which compiles a stated problem into an executable workflow spec, with a question rather than a change going to zirkel-solve instead; nacharbeit grades and reworks what already exists against a fixed, externally sourced rubric, so it does not plan, author a spec, or decide what should be built.

Install ​

/plugin marketplace add Anselmoo/werkstoff
/plugin install nacharbeit@werkstoff

Or point Claude Code at the directory: claude --plugin-dir /path/to/werkstoff/plugins/nacharbeit. The hook is inert until a fix pass opens analysis/nacharbeit/fix_scope.json, so installing it changes nothing about an ordinary session.

The seven surfaces and their rules ​

surfacemechanical (script)judgement (model)what it delegates to
skills, agents, commands, workflow prompts, referencesM-*Q-*— (PR #56's set, unchanged)
hooks/hooks.json and its guard scriptsH-*HQ-*takt_guard.py's contract; verify_hooks_deny.py as a post-check
scripts/**, hooks/*.py, workflows/*.jsS-*SQ-*ast, node --check, test/plugins/lint-oracles.sh's forms; scripts/ci/check_workflow_models.py (vendored) for S-WF-MODEL and S-WF-RELAY
assets/*-viewer.htmlA-*AQ-*scripts/ci/check_viewer_conformance.py (vendored) for the six codes CI decides; the editorial rules it refuses go to the finder
plugin.json, README.md, CHANGELOG.mdP-*PQ-*lint-plugin-authors.py, build_prompt_index.py's scan, rrt docs inject
repo docs wiring (docs/, root README, CLAUDE.md, orchestration references)D-*DQ-*the docs generators; validate_catalog.py

Every rule, its severity and its source page is in references/rubric.md. Per-family and total counts are derived from the rubric, not typed by hand anywhere — run python3 plugins/nacharbeit/scripts/nacharbeit_lint.py --count (add --format json for a machine-readable breakdown) rather than trusting a number in prose. The linter plants one defect per mechanical rule and blanks each rule in turn to prove it load-bearing (scripts/test_nacharbeit_lint.py); the finder is calibrated per family against the planted-defect fixtures shipped inside the plugin (scripts/fixtures/calibration/) and refuses to grade a family whose sealed recall falls below its floor.

Skills ​

skillrolewhat it does
nacharbeit-preflightleaf, read-onlyinventory by kind, available checkers, other live guards, open lock
nacharbeit-lintleaf, zero tokensthe calibration, then every mechanical rule (--count for the number)
nacharbeit-revieworchestratorbuild and bake args → calibrated workflow → persist → report
nacharbeit-fixorchestratoropen the lock and snapshot → remediate / verify / repair per file → post-checks and contract diff → release
nacharbeit-statusstatuswhat ran, what is held for a person, whether a lock is open

Two agents exist for sessions without the Workflow tool: component-finder grades one batch for one lens and labels its result uncalibrated (the fix pass refuses such a run); fix-verifier blind-verifies one file and runs its post-checks.

Example Prompts ​

Say any of these to Claude Code once the plugin is installed — they're plain-language prompts, not exact phrasing Claude has to match. Claude routes them to the skill below by intent.

See what a review would measure here ​
prompt
"what would nacharbeit check in this repo, and is anything blocking a run?"

Triggers nacharbeit-preflight: units per plugin by kind, which checkers exist, which other guards are live, and whether a fix lock is open.

Lint a plugin against the standard, for free ​
prompt
"lint plugins/lehre against the Anthropic plugin standard — frontmatter, hooks.json, scripts, the README"

Triggers nacharbeit-lint: the sabotage calibration first, then every mechanical rule (nacharbeit_lint.py --count prints how many); findings by rule and file, nothing applied.

Run the calibrated review ​
prompt
"review our plugins against the nacharbeit rubric and give me the backlog by model tier"

Triggers nacharbeit-review: calibration per family, sealed hold-out, two-lens finders, routing simulation, refuter, opus synthesis, and the findings report.

Apply what a model can apply, under the lock ​
prompt
"apply the haiku and sonnet findings from the review, one file at a time, and tell me what's left for me"

Triggers nacharbeit-fix: the lock opens, the guard denies everything outside it, each file is reworked and blind-verified, the opus and human entries are listed for you.

Check that a skill actually fires ​
prompt
"does the documented prompt for zirkel-clarify-scope actually fire it? measure it, don't guess"

Triggers nacharbeit-probe: dry-runs first with a cost estimate, then runs the prompt headless in fresh processes and reports fired, captured (naming the capturing skill), silent, or UNSTABLE — with the model the rate belongs to.

Find out what is waiting on a person ​
prompt
"nacharbeit status — which findings need a human, and is a fix pass still open?"

Triggers nacharbeit-status: the last run, the held entries verbatim, and a stale lock with its release command.

Hooks ​

One PreToolUse hook, type: "command", matching Write|Edit|MultiEdit|Bash. Never type: "prompt" — a prompt hook asks a model to decide, which is the model-mediated path this plugin exists to replace.

  • Inert when analysis/nacharbeit/fix_scope.json is absent: the call is allowed before it is even inspected. NACHARBEIT_STATE_DIR relocates the lock.
  • While the lock is open, denies a Write/Edit/MultiEdit whose target is not in the lock or cannot be determined, an edit to a file the lock lists as opus- or human-tier, and a Bash command that changes git state (git commit|push|reset|…, gh pr create|merge). Writes under the state directory are always allowed.
  • Fail-closed once the lock exists: a malformed lock or any internal error denies, naming the escape hatch. A stale lock therefore denies, which is the safe direction.
  • Proven live, not assumed. nacharbeit-preflight reports whether the guard is present, declared and actually denies in the copy that is running; build_fix_args.py refuses to open a lock otherwise. While a lock is open the guard writes guard-heartbeat.json, and build_fix_args.py --confirm-guard bakes fix-run.js only once that heartbeat exists — a plugin installed without hooks/ cannot start a fix pass.
  • Why a lock and not repo state: a PreToolUse payload carries no field saying which agent issued the edit, so a guard that gated on "this repo is mid-review" would sweep every edit in the session into the gate — the failure docs/orchestration/references/hazards.md records for befund. The lock's fields and lifecycle are in references/fix-scope-schema.md.

Running it outside werkstoff ​

Every werkstoff-specific location is a flag: --plugins-root, --state-dir, --fixtures-root, --known-answers (a prompt index for the routing simulation; without one, collisions are labelled hints), --ambiguous, --docs-root, --marketplace, --write-roots, --artifact-copies, --repo-name and --repo-notes. build_report.py --no-vitepress writes plain Markdown.

The calibration fixtures are the exception: they ship with the plugin, so the installed plugin alone can calibrate in any repository. build_args.py stages them into <state-dir>/fixtures/ (so the workflow reads repo-relative paths) and the review refuses to grade a kind that has no tuning + sealed pair. --fixtures-root DIR swaps in another set: one <name>/planted.json per fixture, whose cleanFiles and planted[].file are paths relative to that fixture's own directory, with a directory name starting sealed for the hold-out.

The fix pass has the same shape for the hook post-check. build_fix_args.py bakes verify_hooks_deny.py into a hook-script fix only when --fixtures-root (default test/plugins/fixtures, resolved against the repository root) holds hook-violation-<plugin>/ or the generic ledger-missing-blast-radius/. Otherwise that one check is skipped by name: a WARN post-check skipped line on stderr and an entry in fix-check.json postChecks.skipped, while the hook's unit test and py_compile still run. Read skipped before trusting clean: true — outside werkstoff a fixed hook is not behaviourally probed unless the repository ships its own violating fixture.

Known-answer routing is the one thing that does not travel: werkstoff's docs/prompt-index.md maps its own prompts to its own skills, so another repository has no known answers unless it passes its own --known-answers. nacharbeit-preflight says so up front under cannot measure.

The scripts that parse frontmatter declare pyyaml in a PEP 723 header, so uv run --script "${CLAUDE_PLUGIN_ROOT}/scripts/<name>.py" resolves it; with plain python3 the linter stops with exit 2 and the remedy, and preflight reports pyyaml=no.

The review report ​

A rule-family by severity heatmap fills the screen, each cell a count with a glyph and the fix tiers inside it, the verdict and tier counts floating over it, and the open cell's finding listed in the side panel

bash
python3 plugins/nacharbeit/scripts/nacharbeit_lint.py plugins/* --docs-root docs --format json > /tmp/review.json
python3 plugins/nacharbeit/scripts/build_review_html.py --lint /tmp/review.json --out /tmp/review.html

Rendered from committed demo data at scripts/fixtures/review-demo.json. The fixture carries a blocker and a human-tier finding on purpose: the tier column exists to separate what a model can close from what is a judgement call, and a demo without one cannot show that.

The heatmap is the figure: click a cell to filter the findings list below to it and read its findings in the side panel, then a finding for its quote and suggested fix.

The page also states plainly that a family at 0/n is not evidence of health — it is evidence that nothing in the reviewed plugin exercised that family.

Verifying a change to this plugin ​

CI runs the self-tests below as the nacharbeit_selftests step of plugin-checks.yml.

bash
python3 plugins/nacharbeit/scripts/test_nacharbeit_lint.py     # the linter asserts itself: every rule planted, blanked, synced; pyyaml absent
python3 plugins/nacharbeit/scripts/test_build_args.py          # the shipped fixtures calibrate in a repository that is not werkstoff
python3 plugins/nacharbeit/scripts/test_fix_guard.py           # a missing or silent guard stops the fix pass
python3 plugins/nacharbeit/scripts/test_fix_post_checks.py     # outside werkstoff the hook post-check is skipped by name: never fatal, never silent
node plugins/nacharbeit/scripts/test_review_routing.js          # review.js's routing path against stub hooks, sabotaged 7 ways
python3 plugins/nacharbeit/scripts/trigger_probe.py --selftest  # the probe's parser, verdicts and refusals; no tokens
python3 plugins/nacharbeit/hooks/test_nacharbeit_guard.py      # the hook denies AND allows, and writes its heartbeat only under a lock
python3 plugins/nacharbeit/scripts/nacharbeit_lint.py plugins/nacharbeit --docs-root docs   # the plugin lints clean under its own rules
python3 test/plugins/lint-frontmatter.py plugins/nacharbeit
python3 test/plugins/verify-hooks-deny.py plugins/nacharbeit
node --check plugins/nacharbeit/workflows/review.js && node --check plugins/nacharbeit/workflows/fix.js
claude plugin validate plugins/nacharbeit --strict
python3 plugins/nacharbeit/scripts/build_args.py               # bakes analysis/nacharbeit/run.js without launching it

Measurement history, kept because the corrections matter more than the numbers:

  • nacharbeit-lint-hooks-shape's first real run scored PASS on a transcript that opened "I couldn't run the actual scripts here". Under root, run.sh's acceptEdits fallback denied every Bash call, the model hand-read the guard, and happened to name the right rule. The tally said pass; the transcript said luck. run.sh now grants the interpreters in the clean box under root, and the oracle rejects the admission itself (recorded in cases.tsv and as a must-FAIL case in the calibration script).

test_nacharbeit_lint.py runs first because an instrument must prove it can fail before its silence means anything. Its first run against the ten plugins caught three rules that matched themselves — a shell=True regex flagged the linter's own pattern, the \b!== check flagged its own table, and a viewer rule flagged a constant error string as an injection surface — each tightened before a single real finding was believed.

Behavioural cases ​

Four cases in test/plugins/cases.tsv exercise the model-mediated half. The hook is not among them: it is deterministic and covered by the two scripts above.

bash
bash test/plugins/calibrate-nacharbeit-oracles.sh   # ALWAYS first
bash test/plugins/verify-clean-box.sh
bash test/plugins/run.sh nacharbeit-lint-hooks-shape
caseseeded defect
nacharbeit-lint-hooks-shapea hooks.json whose guard emits systemMessage — a deny the runtime ignores; its anti-pattern rejects a transcript that admits it never ran the linter
nacharbeit-preflight-inventorya plugin with a hook, a viewer and no node-free way to check its workflow; the report must name what it cannot measure
nacharbeit-status-stale-locka two-day-old fix_scope.json; the answer must lead with the release command
nacharbeit-fix-refuses-uncompleteda run.json with completed: false; nothing may be applied

Escape hatch ​

NACHARBEIT_DISABLE_GUARD=1 bypasses the guard for one call. It is deliberately visible and deliberately total. The intended way out of a denial is to finish the pass and release the lock with python3 plugins/nacharbeit/scripts/post_fix_check.py --release-lock; the intended way past an opus- or human-tier entry is a person deciding it.