amicus
AGENTS.md2 starsChanged 47 days agoMITView on GitHub
Rules for any agent or human working in this repository. The rules bind; the context after them explains and points elsewhere. 3. If you touched .github/workflows/, also run uv run python scripts/check_github_actions_pinning.py before you push. 4. Never lower the coverage floor (fail_under in pyproject.toml). 5. Never run -m integration tests unless the maintainer asked for it in the current session; when asked, run them as AMICUS_REQUIRE_LIVE=1 uv run pytest -m integration --no-cov. 6. Never weaken the guard in tests/conftest.py that…
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,774 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository7 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- .github/copilot-instructions.mdCopilot instructions
- agent-friendly-docsSkill
- agent-friendly-githubSkill
- agent-friendly-mcpSkill
- separating-context-from-constraintsSkill
- collaborating-with-amicusSkill
The file
Show its rules and text
We split this AGENTS.md into the rules it gives an agent
22 rules. About 0 are common, 3 are distinctive, and 19 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
19
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 8
Use uv for every project and package operation (uv sync, uv run <cmd>).
- Very specific: line 15
If you touched .github/workflows/, also run uv run python scripts/check_github_actions_pinning.py before you push.
- Very specific: line 16
Never lower the coverage floor (fail_under in pyproject.toml).
- Very specific: line 17
Never run -m integration tests unless the maintainer asked for it in the current session.
- Very specific: line 18
Never weaken the guard in tests/conftest.py that makes the real backend binaries unreachable for unit tests.
- Distinctive: line 19
Write one implementation plan per milestone and open one draft PR per plan.
- Very specific: line 21
Never change .github/, AGENTS.md or CLAUDE.md inside a milestone plan.
- Very specific: line 22
When a change touches a category in FINGERPRINT_COVERS (src/amicus/schemas/fingerprint.py), bump FINGERPRINT and regenerate the pins under …
- Very specific: line 23
When a stored job result's shape changes, bump RESULT_FORMAT in the same file.
- Very specific: line 24
Write commit messages and PR titles as Conventional Commits, type(scope)?!?: subject (scope optional, !
- Very specific: line 25
When a change needs a new commit scope, extend scripts/check_commit_message.py in that same change.
- Very specific: line 27
Never add a pull_request_target workflow.
- Very specific: line 29
Never edit a sibling checkout (~/projects/codex-in-claude, ~/projects/moonbridge, ~/projects/claude-in-codex, ~/projects/pontonier).
- Very specific: line 30
Never write a prompt input — every field in INPUT_FIELDS (src/amicus/request.py): question, task, extra_context, instructions_append, …
- Very specific: line 34
No exemption reaches text that amicus itself, or anyone working in this repository, copies, derives or replays from a prompt anyone sent: …
- Distinctive: line 40
Only the maintainer merges that PR, and only the maintainer pushes the tag.
- Very specific: line 42
Never push a v* tag unless the three live gates — tests/test_codex_live.py, tests/test_kimi_live.py and tests/test_claude_live.py, run …
- Very specific: line 46
Never push a v* tag unless a repository ruleset restricts creation, update and deletion of v* tags, with no agent identity permitted to …
- Very specific: line 47
Never weaken the verify job in .github/workflows/publish.yml, and never let the pypi job stop depending on it.
- Very specific: line 48
Never move a release check into the pypi job: GitHub holds every step of an environment job behind that environment's required reviewer, so …
- Distinctive: line 49
Never describe the rule-20 record, in any document or output, as proof that the live gates ran.
- Very specific: line 64
Import boundaries between layers are enforced by the import-linter contracts in pyproject.toml.
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.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.
Files
Agent working conventions
Rules for any agent or human working in this repository. The rules bind; the context after them explains and points elsewhere.
Rules
- Use
uvfor every project and package operation (uv sync,uv run <cmd>); never pip, poetry or conda. A change is done only when the gate passes:
uv run ruff check . && uv run ruff format --check . && uv run ty check && uv run lint-imports && uv run pytest- If you touched
.github/workflows/, also runuv run python scripts/check_github_actions_pinning.pybefore you push. - Never lower the coverage floor (
fail_underinpyproject.toml). - Never run
-m integrationtests unless the maintainer asked for it in the current session; when asked, run them asAMICUS_REQUIRE_LIVE=1 uv run pytest -m integration --no-cov. - Never weaken the guard in
tests/conftest.pythat makes the real backend binaries unreachable for unit tests. - Write one implementation plan per milestone and open one draft PR per plan; work that is not a milestone needs no plan, which covers a governance PR under rule 9 and a release PR under rule 19.
- Unless you are the maintainer, never merge a PR and never approve your own PR; never commit to
main. - Never change
.github/**,AGENTS.mdorCLAUDE.mdinside a milestone plan; those change only in a PR of their own. - When a change touches a category in
FINGERPRINT_COVERS(src/amicus/schemas/fingerprint.py), bumpFINGERPRINTand regenerate the pins undertests/fixtures/in their own commit. - When a stored job result's shape changes, bump
RESULT_FORMATin the same file. - Write commit messages and PR titles as Conventional Commits,
type(scope)?!?: subject(scope optional,!marks a breaking change), with an imperative lowercase subject and no trailing period, using only the types and scopes inscripts/check_commit_message.py. - When a change needs a new commit scope, extend
scripts/check_commit_message.pyin that same change. - Pin every
uses:in a workflow to a full commit SHA with the version in a trailing comment. - Never add a
pull_request_targetworkflow. - Under
docs/, write Markdown with one sentence per line, where a semicolon or a colon joins clauses into one sentence rather than ending one. - Never edit a sibling checkout (
~/projects/codex-in-claude,~/projects/moonbridge,~/projects/claude-in-codex,~/projects/pontonier). - Never write a prompt input — every field in
INPUT_FIELDS(src/amicus/request.py):question,task,extra_context,instructions_append,focus,target,evidence— to disk, to a worker's argv or to a log; it travels over the worker's stdin. This binds amicus's own handling and everything it commits, including host captures and eval prompt bodies, which are recorded as an id and asha256instead. A backend's own native carrier is exempt where no documented or observed way to avoid it has been found on the backend CLI release an amicus release is validated against, re-checked before every amicus release on the CLI versions its rule-20 evidence is recorded on, and the carrier is disclosed in itsCARRIERSstring and surfaced onamicus_backends; the three that exist today are Kimi's handshake file, the kimi CLI's own session store, and Codex's-c developer_instructionsargv token. Prompt text that a test or capture script assembles entirely from its own literals is exempt, including thebuild_*_promptoutput committed intests/fixtures/*_differentials.json; it stays verbatim, because a differential must show what changed and a hash cannot. No exemption reaches text that amicus itself, or anyone working in this repository, copies, derives or replays from a prompt anyone sent: that stays bound however it is later stored or relabelled. A backend's answer, and the result amicus builds from it — its parsed fields and, for a delegate, the diff captured from the worktree — is output, not a prompt input, even where it quotes or paraphrases one: amicus keeps it only on the job record (result.json, written through a staging file in the same directory), under the job retention the tool surface discloses (AMICUS_JOB_TTL, the per-workspace cap,amicus_job_consume_result), and writes it to no log, argv or other file; what this repository commits of an answer stays bound by the sentence before this one wherever the answer repeats a prompt anyone sent. - Release in two PRs: the work lands with the version literals untouched, then a
chore(release):PR moves them together and rolls## [Unreleased]inCHANGELOG.mdinto a dated section. The literals arepyproject.toml,src/amicus/__init__.py,.claude-plugin/plugin.json,.codex-plugin/plugin.jsonand.mcp.json's--frompin, which names the tag of the release being made; README's "Any other MCP client" example moves with that pin..claude-plugin/marketplace.json's pointer is NOT one of them; rule 24 governs it, and a release must not touch it.uv.lockmirrors the version rather than declaring it: regenerate it in that same PR withuv lock, or theuv lock --checkhook fails. Only the maintainer merges that PR, and only the maintainer pushes the tag. Push the matching tag before any other work follows that merge: until it exists,maindeclares a version that has no release. - Never push a
v*tag unless the three live gates —tests/test_codex_live.py,tests/test_kimi_live.pyandtests/test_claude_live.py, run under rule 5 — have all PASSED on that exact commit, with those passing outcomes recorded. The record is.release-evidence/live-gates.json, written byscripts/record_live_gate_evidence.py, naming that commit, each suite and its outcome; a terminal transcript or a recollection is not a record. A record showing a failed suite does not satisfy this rule; it is a reason not to tag. Push it as an annotated tag whose message is that record verbatim —git tag -a vX.Y.Z -F .release-evidence/live-gates.json --cleanup=verbatim <release-sha>— because.release-evidence/is gitignored and the tag is the only carrier that reaches the publish workflow. - Never push a
v*tag unless a repository ruleset restricts creation, update and deletion ofv*tags, with no agent identity permitted to bypass it. - Never weaken the
verifyjob in.github/workflows/publish.yml, and never let thepypijob stop depending on it. Never move a release check into thepypijob: GitHub holds every step of an environment job behind that environment's required reviewer, so a check placed there runs only after the approval it exists to inform. - Never describe the rule-20 record, in any document or output, as proof that the live gates ran. It is the maintainer's assertion, machine-checked for shape and for naming the tagged commit; the runs happen on the maintainer's machine and the record is written there.
.claude-plugin/marketplace.json's plugin entry names a release that is already published, byrefand ashaequal to that tag's peeled commit, never the one being released, and it may never name a version newer than the one the tree declares. A release PR under rule 19 leaves it untouched; advance it to the new tag in its ownchore(release):PR after that tag is published and its install has been checked, and a release is not complete until that PR merges. That PR is not a release: it needs no rule-20 evidence, because it moves a pointer to a tag that already exists.
Context
What this is
One MCP server for every second-opinion model: a verb-first tool surface with the backend as a parameter, built on FastMCP and its own in-tree backend SDK, amicus.sdk.
The package is amicus under src/; each backend is a plugin under src/amicus/backends/<id>/ behind the BackendPlugin seam in src/amicus/plugin.py.
amicus.sdk (under src/amicus/sdk/) is the backend-facing layer: the backend protocol and contract, the error vocabulary, annotations and preflight, the subprocess runtime with stream capping, redaction, path-alias sanitizing and a bounded JSON reader, and the conformance kit a plugin must pass before the registry will use it.
It was copied from pontonier v0.9.0, and amicus no longer depends on pontonier (ADR 0029).
ADR 0030 holds it to that role, so what only the server uses lives in the amicus package that owns it: the job store is amicus.jobs, worktrees and diff gathering are amicus.orchestration, and the fingerprint mechanics are amicus.schemas.fingerprint.
Import boundaries between layers are enforced by the import-linter contracts in pyproject.toml.
A backend's own prompt carriers (for Codex, the developer-instructions argv token and the stdin prompt; for Kimi, the handshake file and the CLI's own session store) are disclosed on amicus_backends.
Rule 18's exemption is bounded by evidence rather than by proof, because whether a closed-source CLI offers an alternative cannot be proven, only looked for: the condition is that none was found, documented or observed, and the looking is repeated before every amicus release, on the exact CLI versions the rule-20 evidence run uses.
It is tied to the release rather than to a change in a backend's supported-version set because that set is coarse: a kimi patch release still parses as its minor, and every claude 2.x release is covered by major 2, so a new CLI release can become supported without the set ever changing.
Kimi's handshake file exists because kimi ignores stdin.
Codex's argv token exists because codex exec --help (0.155.1) offers the prompt, on stdin, and no flag for developer-role instructions, which leaves the developer_instructions config value, set with -c on argv or from a config file; argv is the one that leaves nothing on disk.
Kimi's session store is different in kind: the CLI rather than amicus writes it, it outlives the run, and amicus does not delete it; the 0.43.1 probe that found no way to switch it off, and what that probe did not test, are recorded in docs/kimi-help/0.43.1/FINDINGS.md.
The gate
Rule 2 is the gate's single definition; other documents link here rather than restating it.
CI (.github/workflows/test.yml) runs exactly those commands on every supported Python version and is authoritative; the local hooks below are a convenience.
pytest excludes -m integration and -m network by default (addopts in pyproject.toml), so the gate never spends quota or runs the release checks that read PyPI and GitHub; opt into the latter with uv run pytest -m network --no-cov.
Rule 16 is in the gate through pytest: tests/test_check_sentence_per_line.py runs scripts/check_sentence_per_line.py over the committed docs/ tree.
How work is organized
The design spec is docs/superpowers/specs/2026-09-04-amicus-design.md; its "Milestones" table defines each milestone's scope and gate.
The execution model, docs/superpowers/plans/2026-09-04-amicus-execution-model.md, is the source of rules 7 and 8; rule 9 widens its rule 6 (workflows, CODEOWNERS, AGENTS.md) to the whole .github/ tree and CLAUDE.md, so every governance file changes the same way.
Each milestone is planned as docs/superpowers/plans/YYYY-MM-DD-amicus-M<n>-<slug>.md and executed task by task in a sibling worktree (~/projects/amicus-wt-<slug>) on a feat/ branch.
Decisions with lasting consequences are ADRs under docs/adr/.
The README's "Where things are" table indexes the rest.
Releases
Users add this repository as a plugin marketplace, and a host copies the plugin into a directory keyed by plugin.json's version, re-reading it only when that version changes.
ADR 0031 is shaped by that fact, established by probe on Claude Code and Codex, and it supersedes ADR 0015, which had assumed a host re-reads .mcp.json.
Under ADR 0015 the pin trailed the release, so an install taken before the pin-move PR, or anywhere mid-cycle, kept running an older server than its own skills (issue #117).
So .mcp.json names its own release, and from 0.4.0 the marketplace entry pins a published tag by ref and sha, so hosts install that self-consistent tag snapshot rather than main.
Rule 24's invariant, that the pointer users follow names an already-published release, moved with it from .mcp.json to the marketplace entry.
sha is required because a host serves sha over a disagreeing ref without complaint, and the v* ruleset's admin bypass means a tag can be moved.
uvx reuses a cached tool environment without querying any index, so the version in .mcp.json's requirement string is still what makes an existing install pick up a new server.
Rule 20 is a local pre-tag gate rather than a CI job: hosted runners have no authenticated codex, kimi or claude, so the evidence is recorded on the maintainer's machine against the exact commit to be tagged.
That evidence is an honest-mistake guard, not an attestation; it is a local file its author can write by hand.
Rule 21 covers creation as well as update and deletion because pushing a v* tag is by itself what triggers .github/workflows/publish.yml: an identity that can create one can publish a release without rules 19 and 20 ever being satisfied, and a moved tag silently changes what users install under a version they already trust.
That ruleset now exists — release tags, active, covering refs/tags/v* and restricting creation, update and deletion — and 0.1.0 was tagged under it.
Its bypass list is the part an agent here cannot check: the ruleset response seen from this repository's agent token carries no bypass_actors key at all.
GitHub omits that key from responses to requesters without sufficient permission on the ruleset rather than returning an empty list, so its absence is not evidence that nobody may bypass, and must never be reported as though it were.
docs/RELEASING.md reads that back with the maintainer's own token rather than assuming it, through scripts/release.py policy, which reports the bypass list unknown, and fails, under a token that cannot see it.
The executable procedure — preconditions, the evidence run, the environment approval pause and the post-tag checks — is docs/RELEASING.md; scripts/release.py scripts its mechanical steps, one subcommand per step, and never tags, pushes or merges.
Rules 20, 22 and 23 are shaped by what a CI job can and cannot establish, which is the subject of ADR 0014 and of issue #25 before it.
The verify job runs scripts/check_release_state.py on the tagged commit, and the two halves of that script are worth different amounts.
Its release-state coherence half proves what it reports: every version literal rule 19 names, the dated CHANGELOG.md section, and uv.lock are all facts of the tagged tree.
Its live-gate half checks only that the record carried on the tag is well formed, names this commit and asserts three passing suites — never that those suites ran, which is why rule 23 forbids saying otherwise.
Everything else rule 19 requires is a convention no CI job can prove: two PRs, an ordinary merge commit rather than a squash, the maintainer merging rather than an agent, and the tag pushed promptly after the merge.
Those are held by the platform controls around the release — rule 21's ruleset and the pypi environment's required reviewer — and by whoever runs the procedure, and this repository states that plainly rather than implying the workflow checks it.
Siblings
The four repositories named in rule 17 are deprecated and archived on GitHub, each at a final release: codex-in-claude 0.24.0, moonbridge 0.4.0, claude-in-codex 0.10.0 and pontonier 0.9.1.
amicus was ported from the first three, and amicus.sdk came from pontonier's v0.9.0 tag; amicus depends on none of them (ADR 0029).
The differential fixtures under tests/fixtures/ were captured inside the siblings' checkouts by scripts/capture_*_differentials.py, and each records the sibling commit it came from.
Re-running one means cloning that sibling back to the path rule 17 names and running the script inside it, as the script's docstring shows; rule 17 binds that clone like any other.
Local hooks
prek.toml mirrors the gate as Git hooks; install once with uv run prek install --prepare-hooks.
Pre-commit runs file hygiene, ruff, ty, import-linter, the Actions pinning-and-trigger check (rules 14 and 15), the one-sentence-per-line check and uv lock --check; pre-push runs pytest; commit-msg runs the Conventional Commits check.
Spend
amicus_consult, amicus_review_changes and amicus_delegate spend the selected backend's quota on every call, and so does the live gate in tests/test_codex_live.py.
Unit tests drive tests/support/fake_codex.py instead of the real CLI.
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
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.

