agentleFS
foryouself83foryouself83/harness-tier/.claude/CLAUDE.md

harness-tier

CLAUDE.md10 starsChanged 31 days agoApache-2.0View on GitHub

This repo is the Claude Code plugin itself, not a consumer of it. Usage: README.md (core idea + install) · USAGE.md (per-topic index into docs/usage/), every file with a Korean twin that doc-sync keeps in step. Component authoring specs (agent/hook/skill frontmatter) come from the official docs as SSOT, never model knowledge: skills · plugins-reference · hooks · permissions. allowed-tools pre-approves tools, it does not restrict — enforced at point of use by .claude/rules/skill-frontmatter.md and tests/skills/. vway-kit is the internal sister…

The file

Files
CLAUDE.md

CLAUDE.md

This repo is the Claude Code plugin itself, not a consumer of it. Usage: README.md (core idea + install) · USAGE.md (per-topic index into docs/usage/), every file with a Korean twin that doc-sync keeps in step. Component authoring specs (agent/hook/skill frontmatter) come from the official docs as SSOT, never model knowledge: skills · plugins-reference · hooks · permissions. allowed-tools pre-approves tools, it does not restrict — enforced at point of use by .claude/rules/skill-frontmatter.md and tests/skills/.

vway-kit is the internal sister repo — not a consumer install and not an older name: the same disciplines and gate scripts, maintained separately, propagating in neither direction. A session here runs the installed vway-kit, so a discipline fixed here does not govern the work that fixed it, and reflecting a fix there is its own task.

Commands

uv run python -m evals.run --dry-run --all     # session count + wall-clock, no model calls
uv run python -m evals.run                     # measure skills whose description changed
uv run python -m evals.outcome                 # measure the outcome arm

A falling eval number re-measures that skill to confirm it, doubling its sessions over what --dry-run advertised. ShellCheck every *.sh change in WSL: a shell bug hides as FAIL-OPEN on the Windows hook runtime. A .sh checks out LF; other text files are CRLF in the worktree.

Conventions

  • English in the repo — docs, commit messages, comments/docstrings, test assertion messages. Korean stays only where load-bearing: text the repo quotes rather than authors, the strings a test compares against it, and fixtures whose non-ASCII bytes ARE the case — translated, the test stays green and stops exercising anything. Untracked docs/superpowers/ stays Korean.
  • Write only what the code can't say — rules/doc-style.md; for a commit body, rules/commit-discipline.md; for generated harness artifacts, rules/harness-rules.md 5-2.
  • Dogfood new CI — a workflow-rendering feature also lands in this repo's own .github/workflows/, every job with a tight timeout-minutes. Exempt: a template whose subject does not exist here (a REST service, a browser front end, a deployment target).
  • A test file past 500 lines becomes a folder tests/<what it covers>/, every file under the cap, with an __init__.py — without it, the day two packages share a basename, pytest aborts the session. A file under the cap stays flat.
  • The dev host is Windows, CI is ubuntu — core.autocrlf=true, and .gitattributes pins only *.sh (LF) and *.cmd (CRLF): every other tracked text file is CRLF in the worktree, LF in the blob. Never digest a tracked file's raw bytes (local pytest green, CI red, in silence); normalize CRLF inside every new digest. Check shell, PATH, shebangs, file modes and path separators in WSL before a push. /flow-init copies byte-for-byte, so a .sh lands in the host LF; the host's own checkouts then follow its core.autocrlf.
  • Mutation-test a fix, and assert the mutation applied — a no-op edit reads as verified. Apply it in Python with assert old in text, never sed -i; revert with git checkout -- from an already-clean tree. Assert the baseline is green where the battery runs, or every mutation reports as caught; a battery that carries rows forward says which it dropped for a moved anchor, since the edit under review moves them and the rest still sweeps clean. Mutate POSIX-only guards in WSL, and diff collected node ids around a mechanical test edit. A/B a claim that a gate over- or under-blocks against the released tag, over a command matrix, before acting on it.

Folder structure

agents/, skills/ are auto-discovered, and hooks/claude/hooks.json is declared in plugin.json: adding a component is a new file. Consumers install the plugin branch, a plugin-only tree .github/scripts/plugin_dist.py builds at release; a file the plugin reads at runtime that its SHIP list misses is absent there (tests/test_plugin_dist.py).

.claude-plugin/  plugin manifest · marketplace entry pinned to the plugin branch; .codex-plugin/ · .agents/ mirror this for Codex
.claude/         this file and dev-only rules for this repo: authoring guidance, and what loads rules/ here — never ships
agents/          subagents the skills dispatch
hooks/           SessionStart · PostToolUse · Notification scripts (claude/hooks.json) — the commit gate is not one; Codex runs the pair from the host's .codex/hooks.json
skills/          one directory per slash command
rules/           shipped SSOTs: tier discipline (+ on-demand parts), harness generation, prose
scripts/         gate + setup scripts; the host copy lists are flow_init_setup.py COPY_FILES/HARNESS_COPY_FILES; harness/<name>/ holds each harness's own installer
github/          consumer workflow templates /flow-init and /wiki-init render; .github/ is this repo's own CI
templates/       design-doc templates /flow-init seeds once into the host (host-owned after)
tests/           pytest over scripts/ and over the shipped skill and rule files
evals/           skill measurement (invocation, outcome), incl. codex_probe/ — NOT shipped: commit as test:/chore:
docs/            usage/ consumer guide (English + .ko twins, shipped) · superpowers/ design records and reference notes (Korean, gitignored, local only)

Architecture

  • Installed outside the host (in a cache) → dual paths. ${CLAUDE_PLUGIN_ROOT} reads, ${CLAUDE_PROJECT_DIR} writes. Never write into the plugin directory. Host writes group under .claude/harness-tier/, except files whose location an external tool forces.
  • The commit gate is registered in the host's settings.json, not the plugin's hooks.json, for deny-enforcement reliability. settings.json cannot resolve ${CLAUDE_PLUGIN_ROOT}, so /flow-init copies the gate scripts and policy into the host (Codex: .codex/hooks.json).
  • Script propagation is one-way — SOURCE (scripts/, flow-tiers.yaml) → cache → host copies. Fix only the SOURCE — /flow-init overwrites a host copy on its next re-sync.
  • Policy stays environment-free — flow-tiers.yaml is plugin-owned and immutable in a host, and its merge_strategy names flows only by flow-config.branches key.
  • A consumer-facing .md change (rules, skills) commits as feat/fix — docs/chore trigger no release, and only a plugin.json version bump reaches a consumer.
  • rules/risk-tiers.md is the tier-discipline SSOT, injected at SessionStart beside a doc-style.md summary (injected for Codex always, for Claude only while no leftover copy from an older /flow-init remains in the host); the split-out files are read on demand. Editing it or the hook that injects it costs every hook_assisted skill a live re-measure. A rate moves with where text sits beside ## Principle's mandate, not with how much, even on a byte-identical description: leave that section alone, move whole sections, and leave no "moved to X" stub — a pointer-only section can cost more than the text it replaced. Compare a rate only to a baseline of the same model and --reps — a plain --all already matches.
  • Three verification layers, independent: the host's .pre-commit-config.yaml; the flow gate (PreToolUse, agent-session commits and merges only — terminal commits and CI bypass it); and CI, which closes that blind spot. Per-gate mechanism: rules/gate-mechanics.md. PR mode takes a flow's merge out of the hook's sight (rules/promotion.md PR workflow).
  • Ask a review agent for a literal VERDICT: PASS / VERDICT: FAIL line — an ambiguous report reads as a pass, and the marker then records a review that never happened.
  • Skills are measured — tests/skills/ checks the file is well-formed, evals/ that it is reached (stale when its description or a fixture its cases run in moves) and, in the outcome arm, executed, whose fingerprint covers the body and every fixture input: a body edit costs a re-measure the invocation check never shows.

Invariants (break these and the gate is silently neutralized)

Preserve these in scripts/* and hooks/*.sh; code, tests and skills cite them by number.

  1. FAIL-OPEN — a transient internal error lets the gate pass, so a broken gate never permanently blocks commits. Three fail-closed exceptions:
    • Exception 1: python3 ≥ 3.8 or PyYAML missing or outdated → the runner blocks.
    • Exception 2: the policy loads with its tiers, the config loads or is absent, no tier marker exists, and the config names the branch neither staging nor production → flow_gate_check blocks the unclassified commit. A missing or broken policy, or a broken config, fails open: the test is "works reliably", not "the file exists".
    • Exception 3: a git merge, or a git pull that names a branch without rebasing, whose flags violate its flow's merge_strategy row — a missing require flag or a present forbid flag, nothing else — is blocked, decided from the command string alone, so no internal error can misfire it. Anything uncertain fails open, as does a command whose merges all run elsewhere; one merge naming no directory beside one that does keeps the whole command judged, behind a cd a deliberate over-block.
  2. Windows encoding — the hook's Python runs in a cp949 locale, where a Korean print() or a UTF-8 open() can FAIL-OPEN and let a commit that should be blocked through. Keep the PYTHONUTF8=1 · force_utf8_io() · encoding="utf-8" defenses.
  3. Block = exit 2 + a reason on stderr — emit the JSON permissionDecision too; exit 2 decides.
  4. No if field on the settings.json gate hook — it suppresses the hook per build. Filter in the runner's stdin self-filter instead.
  5. /flow-init is idempotent — match-then-skip on every addition it makes to a host file.
  6. Worktree re-designation stays FAIL-OPEN — the commit path re-points ROOT to the worktree the commit runs in, read from the command, else from the hook's cwd; anything uncertain falls back to main, the resolver never guesses between directories the command's invocations name, and re-designation must never newly block. One exception: a command whose commit tree cannot be pinned to one place is gated anyway, since whichever tree it resolves to, its being clean says nothing — invocations naming different directories, an untrackable cd/pushd/popd hop (a subshell counts) before a bare commit other than the leading prefix, a -C value still carrying shell expansion or a glob, or a commit the directory readers never see to resolve — one inside a script handed to an interpreter, or one a quote, backslash or ANSI-C escape spells (com''mit, c\ommit, $'\x63ommit'). Same-repo identity is --git-common-dir equality, never a path prefix. Keep the uncertain set small. Cases: scripts/_harness_paths.py. A merge whose target the command never names, in a command that names and moves to no directory, reads that branch from the hook's cwd through the same resolver: Exception 3's verdict, not a re-designation, so it may block.
  7. One authority for what a git invocation is — the classifier decides; the runner's stdin filter only decides whether to spawn it, and stays coarser: a spelling one of them alone accepts is the gate off in silence. Quoting, escapes, comments and heredoc bodies are read in one place, and every rule is located on that mask (the anchored cd prefix excepted). Quoted text and heredoc bodies are data only until something runs them: any exemption from reading them as a command must err toward over-gating, and git never earns one. A missed commit is the one direction this may never fail in; tests/skills/ pins real invocations and mere mentions. Skills spell git commit, git merge and git pull flags literally — the hook reads them unexpanded. Exemption and heredoc rules: scripts/_harness_paths.py.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.