agentleFS
andr-caandr-ca/agentharness/CLAUDE.md

agentharness

CLAUDE.md1 starsChanged 2 months agoMITView on GitHub

This file is loaded into every session that touches this repo. Keep it short — everything else is one link away. Full index: MANIFEST.md. Planned-but-not-built: ROADMAP.md. Default (no publish authority): verify and stage, then stop. 1. ✅ Run the completion gate — before declaring any work done, run bash tools/check-completion.sh. This script verifies lint, types, tests, coverage, and content quality in one shot and exits non-zero if anything fails. The Stop hook in .github/hooks/completion-gate.json and .claude/settings.json enforces this automatically for…

  • Reads credentials
  • Commits and pushes

We split this CLAUDE.md into the rules it gives an agent

18 rules. About 0 are common, 6 are distinctive, and 12 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈6

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 12

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Verify each finding against current code before acting on it — an automated reviewer's claim can be stale (already fixed by a later commit) …

    line 85
  2. Very specific:

    After any such push, poll the run (gh run watch --exit-status, or an equivalent poll loop) until it reaches a terminal state — queued and …

    line 118
  3. Very specific:

    If the failure is transient infrastructure (runner provisioning, Service Unavailable/network errors resolving actions, a flaky step …

    line 125
  4. Very specific:

    If the failure reflects the actual change (a real test/lint/build failure), fix it like any other bug per the Recommendation Assessment …

    line 131
  5. Very specific:

    When a change adds or modifies something that only truly runs via such an external trigger: either (a) exercise it for real before …

    line 155
  6. Distinctive:

    Before creating any file:

    line 191
  7. Very specific:

    Check .agentharness-guarded-paths.json for guarded paths.

    line 192
  8. Distinctive:

    If the target location is guarded: stop and ask the user first.

    line 193
  9. Very specific:

    After receiving explicit permission: record the approved path in .agentharness-allowed-additions.txt, then create the file.

    line 194
  10. Distinctive:

    If the project has no guarded-paths config but has an established structure (src/, docs/, tests/, etc.), treat those directories as guarded …

    line 197
  11. Very specific:

    If the project appears new (empty or minimal), run python3 tools/analyze_structure.py .

    line 201
  12. Very specific:

    All work on this repository (agentharness)

    line 277
  13. Distinctive:

    All harnesses and projects consuming this harness

    line 278
  14. Very specific:

    Rigor tiers: Not all mandates apply to all code — see .github/CODING_GUIDELINES.md#rigor-tiers before assuming 80% coverage or full …

    line 339
  15. Distinctive:

    One source of truth per rule: If you find the same number/rule stated differently in two files, that's a bug — fix the duplicate, don't add …

    line 342
  16. Very specific:

    .env.sample not .env.example: Never hardcode secrets; always provide a sanitized sample file.

    line 345
  17. Very specific:

    One branch, one session: Before your first commit on any branch, acquire the multi-agent lock — tools/agent-lock.sh acquire "<feature>" …

    line 350
  18. Very specific:

    Do not capture that id with command substitution (ID="$(… acquire …)"): the recorded owner pid would be the substitution subshell, which …

    line 353

≈ “Common” is an estimate: at least 1 in 5 of the 25,680 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
CLAUDE.md

agentharness – Agent Router

This file is loaded into every session that touches this repo. Keep it short — everything else is one link away. Full index: MANIFEST.md. Planned-but-not-built: ROADMAP.md.

🤖 Agent Workflow Completion

Default (no publish authority): verify and stage, then stop.

  1. ✅ Run the completion gate — before declaring any work done, run bash tools/check-completion.sh. This script verifies lint, types, tests, coverage, and content quality in one shot and exits non-zero if anything fails. The Stop hook in .github/hooks/completion-gate.json and .claude/settings.json enforces this automatically for Claude Code and GitHub Copilot — the agent cannot stop until all gates pass.
  2. ✅ Create atomic commits locally — one logical unit per commit, clear message explaining WHY
  3. 🛑 Stop before pushing, opening a PR, or auto-implementing recommendations. Present a summary of what's staged and ask the user to confirm before publishing anything.

A local commit is not a durable safe-point in an ephemeral-container execution environment. If you have verified, committed-but-unpushed work and are about to block on AskUserQuestion or other unbounded human input, consider pushing to a remote branch (a scratch/WIP branch is fine) first — committed-but-unpushed work can be lost if the container is reclaimed during the wait, with no error at commit time and no warning until a later git log looks unfamiliar. This is disclosure of an existing risk, not a grant of publish authority: it does not authorize opening a PR or merging, and the default tier above still governs those.

Full publish authority (commit → push → PR, same as before) applies only when either is true:

  • .agentharness-publish-mode exists at this repo's root (a local, gitignored, per-operator flag — see "Publish authority" below), or
  • The user has explicitly granted standing authorization for this session or task in the current conversation. This always overrides the flag in either direction — explicit instructions in the request outrank a standing file the same way rigor-tier precedence already works (see patterns/profiles/README.md#precedence-order).

Under full publish authority, the original mandate applies as written: push to remote with tracking, create a PR with gh pr create, and never leave verified work uncommitted-and-unpushed — an agent claiming work is "complete" while it's only staged locally is incomplete.

Note on merge commits: Merging a branch into main locally (e.g., git merge --no-ff <branch> while checked out on main) is a form of committing to trunk, and the "Never commit to main directly" rule applies to it in full: never merge to main locally — always integrate through a PR on GitHub, never bypass it with a local merge commit.

Never merge a PR on CI status alone — wait for review comments, then address them, before merging. A green CI run says nothing about feedback left on the diff itself (human or automated, e.g. GitHub Copilot's code review). Use tools/safe-pr-merge.sh <n> — a PreToolUse hook (.github/hooks/claude-pr-merge-guard.sh) blocks a direct gh pr merge for Claude Code sessions, so this is enforced, not just asked for. AGENTHARNESS_PR_MERGE_BYPASS=1 overrides it when the wrapper itself is broken; say why in the PR. The checklist below is what the wrapper does — read it when diagnosing a refusal, or when merging from a client the hook does not cover:

  1. Give automated review time to post (its own check, separate from CI, e.g. "Copilot Code Review") — don't merge the instant CI turns green. Concretely: Check whether an automated reviewer is configured on this repo at all (e.g. by examining recent PRs' check-runs to see if a Copilot or bot review check-run has appeared). If none is configured, note this explicitly ("no automated reviewer configured on repo"); if one is configured, poll for new review comments and check-runs every ~30s for up to 20 minutes after CI goes green (observed Copilot review latency runs 10–20 minutes on some PRs). If the reviewer's check-run appears during that window, keep polling until it completes (allow up to ~30 minutes total) — a check-run that has started is a reason to keep waiting, not to stop. A single immediate check does not satisfy this step — the wait is the point, not just a verification of absence. Exception: if the automated reviewer's check-run has already reached a completed state (not merely started/pending) with zero comments attached, that completed run already is the wait — stop polling immediately rather than sitting out the rest of the window for a review that has demonstrably already finished and found nothing to say. tools/safe-pr-merge.sh implements this check.
  2. Fetch both comment types — issue-level (gh pr view <n> --json comments) and inline review comments (gh api repos/<owner>/<repo>/pulls/<n>/comments); the first call alone misses inline findings entirely.
  3. Verify each finding against current code before acting on it — an automated reviewer's claim can be stale (already fixed by a later commit) or simply wrong; confirm the premise, don't implement a "fix" on faith.
  4. Fix what's real and in scope per the Recommendation Assessment mandate below (scoped/low-risk directly; larger findings get scoped and confirmed like any other recommendation); note explicitly why anything is skipped rather than silently ignoring it.
  5. Reply to every comment. On the PR, reply to each review comment you fetched — issue-level and inline alike — with a short assessment and the action taken: the commit that addressed it, "already correct — no change (why)", or "skipped/deferred because …". This puts step 4's "don't silently ignore" on the thread where the reviewer left the finding, not only in a commit message or status file, so every decision is auditable next to the comment it answers. Use gh pr comment <n> for issue-level replies and gh api --method POST repos/<owner>/<repo>/pulls/<n>/comments/<id>/replies -f body=… for inline ones.

When starting or resuming work in a repo, check for stale PRs with unaddressed review comments — before doing anything else, run gh pr list --state open and examine any open PR (especially those opened more than a day ago) for review comments newer than the PR's last commit, or older comments with no replies. This catches PRs previous sessions left open without addressing feedback, which the PR-merge checklist alone misses.

Never report a push/merge as done while CI is still running or red — watch it through to an actual, current green before moving on or telling the user it's finished. "I pushed" and "CI passed" are different claims; only the second one means the work is safe. This applies to every CI-triggering push this mandate covers: opening a PR, pushing more commits to one, and merging into main.

  1. After any such push, poll the run (gh run watch --exit-status, or an equivalent poll loop) until it reaches a terminal state — queued and in_progress are not outcomes, and reporting either as "done" is the exact mistake this rule exists to prevent.
  2. On failure, read the actual log for the failed job(s) (gh run view <run-id> --log-failed) before deciding what to do next — don't guess from the job name.
  3. If the failure is transient infrastructure (runner provisioning, Service Unavailable/network errors resolving actions, a flaky step unrelated to this diff — not a real test/lint/type failure), rerun the failed jobs (gh run rerun <run-id> --failed) and re-poll. Retry up to 5 times; if it's still failing after that, stop and surface it to the user rather than silently retrying forever.
  4. If the failure reflects the actual change (a real test/lint/build failure), fix it like any other bug per the Recommendation Assessment mandate below, push the fix, and re-verify CI from a clean state — don't rerun a failing job hoping it passes the second time.
  5. A merge to main is not finished until main's own resulting CI run (the run the merge commit itself triggers, not just the PR's pre-merge run) is confirmed green — a PR's checks passing before merge doesn't guarantee the post-merge run on main will, and only the post-merge run reflects what's actually deployed/tagged from.

"Merged" and "confirmed working" are different claims for anything an externally fired trigger runs, not just for CI. The completion gate (lint/types/tests/coverage) and the CI-verification rules above are thorough about code-level and merge-level checks, but neither exercises a GitHub Actions trigger other than workflow_dispatch (an issues:, schedule:, pull_request_target, or webhook trigger), a cron job, or anything else pytest/bats structurally cannot simulate. Building an automated GitHub-webhook-triggered feature in this repo hit this gap three separate times in a row on the same feature: static checks passed every time, and each time only an actual live run (filing a throwaway test issue, watching a real webhook fire) surfaced a real bug — a duplicate-run race, an indefinite hang, a retry gap — that no unit test could have caught.

When a change adds or modifies something that only truly runs via such an external trigger: either (a) exercise it for real before presenting the work as done — e.g., file a throwaway test issue/PR/tag and watch the triggered run to completion — or (b) say explicitly in the PR body that live verification wasn't done this round and why. An honest "not live-tested" disclosure is not a substitute for the check — it's an open TODO the agent is expected to close out at the next opportunity, the same way an undisclosed CI failure would be, not a satisfied requirement.

Publish authority

Authority can now be scoped via a declarative .agentharness-authority.json contract (gitignored, per-operator, like the flag below). Define grants by operation, target branch glob, and expiration — operators can restrict authority to fix/* branches only, grant it for 48 hours while a feature ships, or revoke it mid-session. Precedence: explicit in-session instruction

.agentharness-authority.json > bare flag > default (verify-and-stage). A present contract overrides the bare flag. See docs/INTEGRATION.md's "Scoped Authority" section for the full contract format, operation vocabulary, and optional hard-block enforcement.

For simpler, all-or-nothing authority, touch .agentharness-publish-mode at this repo's root grants standing push/PR/auto-implement authority for every session that reads this file, until the flag is removed. It's gitignored (never committed) because it's a per-operator/per-machine authorization, not a repo-wide policy — see docs/DECISIONS.md for why this replaced the old always-on default, and docs/INTEGRATION.md for how to create/remove it or use scoped contracts instead.

📁 File Placement

In any project with .agentharness-guarded-paths.json, you must not create new files or directories in guarded paths without explicit user permission.

Before creating any file:

  1. Check .agentharness-guarded-paths.json for guarded paths.
  2. If the target location is guarded: stop and ask the user first.
  3. After receiving explicit permission: record the approved path in .agentharness-allowed-additions.txt, then create the file.

If the project has no guarded-paths config but has an established structure (src/, docs/, tests/, etc.), treat those directories as guarded by default and ask before adding to them.

If the project appears new (empty or minimal), run python3 tools/analyze_structure.py . --recommend to get structure recommendations, then present them to the user before creating anything.

The pre-commit hook (tools/check-file-placement.sh) enforces this deterministically — commits adding files to guarded paths without an entry in .agentharness-allowed-additions.txt are blocked. One standing exemption: docs/operational/harness-feedback.md — the harness-feedback skill already has its own standing authorization to create it without asking (see that skill's "no ask-the-user step" rule), so this hook doesn't re-block it even under a fresh guarded-docs config.

See patterns/file-placement-policy/POLICY.md for the full protocol and .claude/skills/file-placement-policy/SKILL.md for the condensed on-demand reference.

This whole policy is scoped to inside the project. It has no concept of "outside the repo entirely" — a real gap: a command intended to set an env var for the current shell once appended it directly to the user's ~/.bashrc instead, a file outside $(git rev-parse --show-toplevel) entirely, shared across every terminal the user opens. It was caught and reverted immediately, but nothing would have stopped it if it hadn't been noticed.

Never write to files outside the current project's working directory tree — shell rc files (~/.bashrc, ~/.zshrc, ~/.profile), global git config, ~/.config/* — without explicit user confirmation. Session-scoped environment variables needed for a multi-step task should be export-ed inline for the current shell only, never persisted to a dotfile, unless the user has explicitly asked for a durable environment change.

For Claude Code sessions, a PreToolUse hook (.github/hooks/claude-outside-repo-write-guard.sh, wired in .claude/settings.json) enforces the mechanical half of this automatically: it blocks Write/Edit calls whose target path resolves outside every git repository and outside the system temp directory. It only covers structured file writes — a Bash command redirecting output (>>) is not something this hook can reliably generalize-block without a high false-positive rate against legitimate commands, so that half stays a documented rule, not a technical gate.

🔍 Agent Recommendation Assessment

When an agent is asked to address/review/look into recommendations:

  1. Assess each item — evaluate positive vs. negative impact (complexity, effort, risk, benefit)
  2. Scoped, low-risk fixes — a bug fix, a correctness/security fix with one clear resolution, closing a gap in something already built:
    • ✅ Implement directly, regardless of effort — don't ask permission to fix it. Whether the fix gets published still follows the Agent Workflow Completion default above (verify + stage, or full publish if authorized).
  3. Anything larger — a new subsystem, a product-direction decision (target users, supported clients, distribution model), an architecture change, or a recommendation batch that amounts to a roadmap rather than a fix:
    • 🛑 Present a scoped summary and get explicit confirmation on scope before implementing. A review file recommending something is not the same as the user authorizing a multi-session build-out. Once scope is confirmed, that confirmation covers the agreed batch — don't re-ask item-by-item within it, but do re-check before expanding past what was agreed.
  4. If potential outcome is NEGATIVE or HIGH-RISK regardless of size:
    • 🚨 Escalate to user immediately — do not implement
    • Include: specific concern, risk analysis, request guidance
  5. Report status in <recommendations>-status.md with:
    • Timestamp (ISO 8601: 2026-07-11T14:30:00Z)
    • Summary of what was implemented (and, for a confirmed larger batch, what scope was agreed)
    • Rationale for positive/negative aspects of each recommendation
    • Link to PR(s)

This applies to:

  • Recommendations from reviews, audits, or assessments
  • All work on this repository (agentharness)
  • All harnesses and projects consuming this harness

Rationale: Recommendations only improve systems when they're acted on deliberately. Complexity is not a reason to decline a scoped fix — but silently treating an unbounded backlog as blanket authorization turns "assess recommendations" into unrequested product decisions the user never actually signed off on. The same logic applies one level up: a mandate that grants an agent standing remote-write authority by default is itself a product-direction decision the user should make explicitly, not inherit silently from a template — see "Publish authority" above.


📋 Completion Gate

Run bash tools/check-completion.sh before declaring any work done.

The gate runs all quality gates in one shot and exits 1 if any fail:

GateWhat it checks
content-qualityYAML validity, skill frontmatter schema, tested-snippet syntax
ruff-lintPython lint (E, F, I, UP rules)
mypyStrict type checking on src/
pytest-coverageTest suite + ≥65% branch coverage on src/agentharness/
shellcheckChanged .sh files have no issues
git-cleanNo uncommitted changes to tracked files

The Stop hook in .github/hooks/completion-gate.json (Copilot) and .claude/settings.json (Claude Code) enforces this automatically — the agent cannot stop until tools/check-completion.sh exits 0.

For projects consuming this harness via harness-link.sh init, install the completion gate with: harness-link.sh init --with-hook (the hook is bundled alongside trunk protection in .github/hooks/).


What This Repo Is

A single source of truth for git conventions, coding guidelines, testing standards, and (eventually) on-demand skills, so they're written once and referenced everywhere instead of drifting across projects. Full rationale: docs/ARCHITECTURE.md.

Where To Look

NeedRead
Full asset indexMANIFEST.md
Git workflow (branches, commits, secrets).github/BRANCHING_STRATEGY.md, .github/COMMITTING_GUIDELINES.md
Coding standards + rigor tiers.github/CODING_GUIDELINES.md
Testing (TDD, coverage, Playwright)patterns/testing/
Loggingpatterns/logging/
Python conventionslanguages/python/
Integrating this repo into a projectdocs/INTEGRATION.md, or just run tools/setup/harness-link.sh
First run in a project (what applies here?)agentharness bootstrap plan, and the project-bootstrap skill for the interview
What's planned but not builtROADMAP.md

Rules That Apply Regardless of What You're Working On

  • Rigor tiers. Not all mandates apply to all code — see .github/CODING_GUIDELINES.md#rigor-tiers before assuming 80% coverage or full Playwright suites apply to a prototype or one-off script.
  • One source of truth per rule. If you find the same number/rule stated differently in two files, that's a bug — fix the duplicate, don't add a third version.
  • .env.sample not .env.example. Never hardcode secrets; always provide a sanitized sample file.
  • Never commit to main directly. Branch protection enforces this for everyone except repo admins; agents should never rely on the admin bypass.
  • One branch, one session. Before your first commit on any branch, acquire the multi-agent lock — tools/agent-lock.sh acquire "<feature>" "<branch>" — and export the printed id as AGENTHARNESS_AGENT_ID. Do not capture that id with command substitution (ID="$(… acquire …)"): the recorded owner pid would be the substitution subshell, which exits immediately. Pass a stable AGENT_LOCK_PID instead, and read the id from the printed output — see the multi-agent-coordination skill for the exact pattern. Locks now carry a renewable lease, so a session whose acquiring process has exited still holds its lock; renew extends one that outlives the TTL. The pre-push hook blocks pushes to a branch whose lock another live session holds. Never force-push: a repo-wide GitHub ruleset rejects non-fast-forward pushes on every branch, so when a push is rejected, fetch and rebase instead.
  • Harness friction is a first-class finding. When using this harness, friction (hook failures, ambiguous guidance, violated mandates, mismatched tool output) discovered during any session must be addressed, logged locally to docs/operational/harness-feedback.md, and filed upstream to andr-ca/agentharness by default — without waiting for the operator to ask. See the harness-feedback skill. Skip upstream filing only if .agentharness-no-upstream-feedback exists at the repo root.

Operational Documents

Temporary/working docs (research notes, agent logs, planning) go in docs/operational/, tracked in git like everything else. See docs/operational/README.md for the promote/archive/delete workflow.

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.

Reviews can't be read right now.

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.