agentic-dev-team CLAUDE.md

A contributor guide for developing the Agentic Dev Team plugin, a set of tools and workflows for Claude Code.

In plain words
What is it for?
Use it when modifying the plugin, preparing a release, opening a pull request, or checking its prerequisites and repository structure.
Why use it?
It defines the project’s branch, pull-request, release, and development rules so changes enter the shared codebase safely.

Instructions file

Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

agentmods
npx agentmods add instructions/bdfinst/agentic-dev-team/claude-md
Clone the repo
git clone --depth 1 https://github.com/bdfinst/agentic-dev-team
Per session 7,618 This file is loaded in full into every session.
When invoked 7,618 The same file — it is already loaded in full.
Security scan C 2 findings. Scan, not verified.
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5 $0.07618 $0.07618
Opus 5 $0.03809 $0.03809
Sonnet 5 $0.01524 $0.01524
Haiku 4.5 $0.00762 $0.00762

Measured 2d ago against content hash 3fdc7ff608de, method: parsed. Prices are Anthropic first-party input rates as of 2026-08-30, from the pricing page.

Security

Grade C, and why

agentic-dev-team CLAUDE.md scanned grade C with 2 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 2d ago.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Downloads and executes remote codehighSupply chain

curl | sh runs whatever the server returns today, which is not necessarily what it returned when this was reviewed.

- CLI: `jq`, `python3`, `uv` (macOS: `brew install jq python3 uv`; `uv` otherwise via `curl -LsSf https://astral.sh/uv/install.sh | sh`). `shellcheck` still lints repo-root shell (`scripts/audit-rules-vs-prompts.sh`, etc

Makes network callslowCapability

Not a fault in itself. Listed so you know the mod talks to something, and to what.

- CLI: `jq`, `python3`, `uv` (macOS: `brew install jq python3 uv`; `uv` otherwise via `curl -LsSf https://astral.sh/uv/install.sh | sh`). `shellcheck` still lints repo-root shell (`scripts/audit-rules-vs-prompts.sh`, etc
CLAUDE.md · 191 lines

How it starts

The opening of the file, as written. The whole thing — 191 lines — stays where its author put it; the contents beside it link to each section on GitHub.

Agentic Dev Team — Plugin Development

This is the marketplace repository for the dev-team Claude Code plugin.

Working Rules

  • Always work on a branch. Never commit directly to main. Every change — including documentation-only changes, gitignore tweaks, and one-line fixes — lands via a feature branch and a pull request. If a commit accidentally lands on main locally, reset main to origin/main and move the commit to a branch before pushing. Release commits authored by release-please are the only exception; they arrive as their own PR.
  • Always pull origin main before starting work. Run git fetch origin main at the start of every session and before branching, then cut new branches from origin/main directly (e.g. git switch -c <branch> origin/main) — never from a local main you haven't fast-forwarded. If your feature branch already exists and origin/main has moved, merge or rebase the fresh origin/main into it before continuing — don't let a branch drift behind main across a long-running session.
  • Squash-merge strategy. main is protected by a ruleset that forbids force-pushes. Use squash-merge for all PRs to keep main history clean: gh pr merge <num> --squash. Signed commits are not required.
  • Documentation-only PRs auto-merge. When the diff touches only *.md files (plus .gitignore, LICENSE, or other non-shipping metadata) and changes no code, agent, skill, or hook, arm auto-merge at PR-open time: gh pr merge <num> --auto --squash. Required checks still run; the PR lands the moment they pass. Any PR that touches code, agents, skills, hooks, eval fixtures, or marketplace manifests requires explicit human merge.
  • Deterministic tools over inference — never dispatch a skill or agent for work a tool can decide. If a question has a mechanical answer, the mechanism must produce it: a compiler, a test suite, a type checker, a linter, a parser, a schema validator, git itself. Agents and skills are for judgement — design trade-offs, review of intent, prose — not for facts a program can compute. This is a correctness rule, not a cost rule: a model's answer to a mechanical question is a guess that looks like a result, and it fails silently, in the confident direction. Prefer, in order: (1) run the real thing and read its output; (2) a deterministic script over its artifacts; (3) a model, only for what is left. Two rules follow from it, both learned the expensive way:
    • Verify a runtime property by exercising it at runtime. Static approximations of a runtime question rot into false assurance. The Python floor gate began as a hand-maintained denylist of post-3.8 APIs (the floor was 3.8 at the time); it reported the shipped tree clean while hooks/lib/cost_meter.py used PEP 584's dict | dict, which 3.8 rejects. A one-time manual run of the full suite on a real 3.8 interpreter — not something the gate itself did — found it in nine failing tests. The gate that replaced the denylist was, at first, still only a byte-compile + import pass (.github/workflows/plugin-tests.yml → "Python 3.10 floor", scripts/import_probe_shipped.py; see tests/repo/test_python_floor.py) — real progress over a hand-maintained list, but still one layer short of "exercising it at runtime": compiling and importing a module proves it parses and loads, not that every function body runs clean, so a runtime-only API used only inside a function (asyncio.to_thread in orchestrator.py, issue #1650) stayed invisible to it regardless of which version the floor was pinned to. chk_python_floor now closes that gap too, actually running a curated test slice over the shipped tree under the resolved 3.10 interpreter via uv run --python, not just compiling and importing it. That slice is declared once, as FLOOR_TEST_SLICE in tests/repo/test_python_floor.py, and held equal to chk_python_floor's actual pytest arguments in both directions — deliberately not re-enumerated here, because a copy of the list in prose is exactly what went stale when the coverage-discovery modules joined the slice (#1826) and nothing held this file to it. The floor itself later moved to 3.10 once the original OS-availability rationale expired (ADR 0031) — the gate's mechanism (the interpreter, not a list) is what survived that move unchanged.
    • A gate that cannot fail is worse than no gate. It reads as a guarantee and delivers none. engines.node sat at >=24 while this project's own containers ran Node 22, so npm ci failed, node_modules never installed, husky's hooks went inert, and scripts/ci-local.sh skipped eslint while still printing "All local CI checks passed." When you add a gate, make it fail on purpose once before you trust it.
    • A gate bounds only the case it can observe — say what the other end is. The floor gate above asks "does this still run on the OLDEST supported interpreter", which is a real question and answers only itself. For a long time nothing asked about the newest: content-guard-tests runs on the runner image's implicit system python3 (~3.12 on ubuntu-24.04, with no python-version pin anywhere in plugin-tests.yml), so the suite's green read as "works on Python" when it meant "works on 3.10 and whatever the runner happens to ship." main was consequently red on 3.13+ with every check green: coverage_discovery_js.py detected a malformed ** glob by catching ValueError from Path.glob, and CPython 3.13's pathlib rewrite stopped raising it, so the guard silently returned an empty result instead of a discovery_error (#1832, fixed in #1833). chk_python_ceiling / the Python ceiling job now names the other end (PYTHON_CEILING in scripts/ci-local.sh — one place, so a runner-image bump cannot move it silently), and runs the full pytest directory list rather than a curated slice like the floor job's. That choice is the point, not an optimization: when the regression landed, the offending test file was not in the floor slice, and it took a follow-up commit (#1836) to add the coverage-discovery modules to it — a curated list only covers what someone remembered to enumerate, and it lagged the very bug that motivated it. A ceiling gate on a slice would inherit that lag. Read its status honestly, though: it is currently listed in exempt in .github/required-status-checks.json, so it reports on every PR but does not block a merge — advisory by choice, not because it is path-filtered or opt-in like the other exemptions. Treat a red ceiling run as blocking by convention, and see #1837 for the ruleset edit that would make that automatic. Two transferable pieces: when a library's error behavior is your guard, validate the property explicitly in your own code instead — an exception is a contract that can be withdrawn; and do not add a pinned interpreter to content-guard-tests via actions/setup-python, which is the known-wrong fix (a prior attempt put it ahead of the system python3 for every other step in that job, breaking chk_md_references and silently degrading chk_hook_units's pytest guard to "skipped" — use uv, which never touches PATH).
    • The observed end is a PLATFORM too, not only a version. The two gates above bound the interpreter; nothing bounded the operating system, and every gate in this repo runs on ubuntu-* while every maintainer develops on macOS. .husky/pre-push created all five of its temp files with mktemp -t PREFIX, which GNU coreutils treats as a template honoring $TMPDIR and BSD/macOS treats as a literal prefix, ignoring $TMPDIR entirely (it resolves the per-user temp dir via confstr(_CS_DARWIN_USER_TEMP_DIR)). So the worktree-path snapshot landed where tests/repo/test_pre_push_ref_guard.py could not find it, two tests failed on every Mac, and — because pre-push runs the whole of ci-local.shevery local push from a Mac was blocked, which is precisely the pressure that turns --no-verify into a habit and disables the local CI mirror wholesale. CI was green throughout (#1993). Portable form: mktemp "${TMPDIR:-/tmp}/prefix-XXXXXX", with the Xs trailing — BSD substitutes only a trailing run, so foo-XXXXXX.log yields that name verbatim and the next call dies with EEXIST; the #1993 fix fell into that second trap while removing the first, and both are now pinned by tests/repo/test_mktemp_portability.py. Until a macOS CI leg exists (#1993), that grep is the only mechanism watching this end — so when a gate is green everywhere and broken in front of you, suspect the axis nothing runs on.
    • Review your own fix before calling it done — a green suite on code you just wrote is weak evidence. Tests written alongside a fix encode the same mental model as the fix, so they inherit its blind spots. The #1833 brace-glob fix passed all 71 tests, 15 of them written specifically for it; correctness-review and test-review, dispatched independently at the diff, both caught that brace balance was tracked only from the first { onward — so apps/}x{a,b} expanded to globs matching nothing, reintroducing the exact silent-zero failure the fix existed to remove. The parametrized case that looked like it covered this passed only because of an unrelated unclosed trailing brace. The same pass found two more real defects (an empty alternative failing the whole workspace, and per-alternative ** checking letting {**/x,**/y,**/z} slip past the cost guard). This is judgement, not mechanism, so no gate enforces it: dispatch the review agents at your own diff from the top-level session, and verify each finding by reproducing it before fixing.
  • A mechanical finding reported twice becomes a check. When a review agent reports the same mechanically-checkable finding class for the second time — and the check is expressible as a deterministic script — convert it into a CHECKS entry in plugins/dev-team/skills/code-review/scripts/repo_invariants.py in the same PR that fixes the finding. This is the ratchet that keeps the rule above from depending on memory. The mechanism has existed since #1608 precisely so mechanically-checkable repo facts stop being re-derived once per agent per round — #1629 found at least 4 of 8 follow-up review rounds were triggered by defect classes these checks catch — but until now growth of CHECKS depended on someone remembering to grow it. The trigger is deliberately the second report, not the first: one occurrence may be a one-off, two is a class, and converting at two makes the cost a single bounded conversion instead of an unbounded stream of re-derivations. Worked example: the "every module under a skill's scripts/ dir is named in that skill's docs" invariant shipped covering mutation-testing alone (#1600, where four separate agents rediscovered it); when the same class turned up in skills/code-review/scripts/ (#1981), the hardcoded single-skill check became a registry covering both rather than a copied second function.
  • Prefer Python over bash, repo-wide, unless bash is strictly required. This applies everywhere in the repo, not just shipped plugin code — new tests under tests/, new scripts/*, new CI helpers. Write .py (stdlib-only for anything under plugins/dev-team/) by default. Bash is acceptable only when the thing under test genuinely is a shell script, or for the unavoidable pre-Python bootstrap shim (install.sh's two-line trampoline). New .bats files are a review finding, not a style choice — see ADR 0014 and ADR 0015. If you find yourself adding a .bats file, port the assertions to test_*.py instead — see ### Script authoring — Python only below for the mechanical pattern.
  • Specs and plans are GitHub issues here, not files. When developing this repo (GitHub-connected — the normal case), a spec becomes an epic issue and each plan slice a sub-issue of that epic — create them by default, don't leave local drafts. Fall back to untracked files only when there is no GitHub connection: the spec at docs/specs/<slug>/spec.md and its plans under a docs/specs/<slug>/plans/ subdirectory (never a root-level plans/). This governs development of this plugin only — it is not shipped skill behavior imposed on people who use the plugin on their own projects.
  • PRs close the issues they address. Every PR body carries a closing keyword — Closes #N for each sub-issue the PR resolves, and Part of #<epic> (non-closing) for the epic — so merging the PR closes its slices. GitHub does not auto-close a parent/epic issue as a side effect of every sub-issue closing (it only tracks completion percentage); the epic-auto-close workflow (.github/workflows/epic-auto-close.yml, #987) is what closes the epic once its last sub-issue closes.

Read the full file on GitHub · 191 lines

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. 2d ago First seen · 191 lines · 7,618 tokens per session scan C 3fdc7ff608de

Subscribe to this mod's changes

agentic-dev-team CLAUDE.md is an instructions file published in the GitHub repository bdfinst/agentic-dev-team (277 stars, last pushed yesterday), licensed MIT. It adds 7,618 tokens to every session, about $0.0381 per session on Opus 5. A static security scan graded it C with 2 findings (downloads and executes remote code, makes network calls). No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-30.