agentleFS
briandconnellybriandconnelly/amicus/AGENTS.md

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…

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
  1. Very specific:

    Use uv for every project and package operation (uv sync, uv run <cmd>).

    line 8
  2. Very specific:

    If you touched .github/workflows/, also run uv run python scripts/check_github_actions_pinning.py before you push.

    line 15
  3. Very specific:

    Never lower the coverage floor (fail_under in pyproject.toml).

    line 16
  4. Very specific:

    Never run -m integration tests unless the maintainer asked for it in the current session.

    line 17
  5. Very specific:

    Never weaken the guard in tests/conftest.py that makes the real backend binaries unreachable for unit tests.

    line 18
  6. Distinctive:

    Write one implementation plan per milestone and open one draft PR per plan.

    line 19
  7. Very specific:

    Never change .github/, AGENTS.md or CLAUDE.md inside a milestone plan.

    line 21
  8. Very specific:

    When a change touches a category in FINGERPRINT_COVERS (src/amicus/schemas/fingerprint.py), bump FINGERPRINT and regenerate the pins under …

    line 22
  9. Very specific:

    When a stored job result's shape changes, bump RESULT_FORMAT in the same file.

    line 23
  10. Very specific:

    Write commit messages and PR titles as Conventional Commits, type(scope)?!?: subject (scope optional, !

    line 24
  11. Very specific:

    When a change needs a new commit scope, extend scripts/check_commit_message.py in that same change.

    line 25
  12. Very specific:

    Never add a pull_request_target workflow.

    line 27
  13. Very specific:

    Never edit a sibling checkout (~/projects/codex-in-claude, ~/projects/moonbridge, ~/projects/claude-in-codex, ~/projects/pontonier).

    line 29
  14. Very specific:

    Never write a prompt input — every field in INPUT_FIELDS (src/amicus/request.py): question, task, extra_context, instructions_append, …

    line 30
  15. Very specific:

    No exemption reaches text that amicus itself, or anyone working in this repository, copies, derives or replays from a prompt anyone sent: …

    line 34
  16. Distinctive:

    Only the maintainer merges that PR, and only the maintainer pushes the tag.

    line 40
  17. Very specific:

    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 …

    line 42
  18. Very specific:

    Never push a v* tag unless a repository ruleset restricts creation, update and deletion of v* tags, with no agent identity permitted to …

    line 46
  19. Very specific:

    Never weaken the verify job in .github/workflows/publish.yml, and never let the pypi job stop depending on it.

    line 47
  20. Very specific:

    Never move a release check into the pypi job: GitHub holds every step of an environment job behind that environment's required reviewer, so …

    line 48
  21. Distinctive:

    Never describe the rule-20 record, in any document or output, as proof that the live gates ran.

    line 49
  22. Very specific:

    Import boundaries between layers are enforced by the import-linter contracts in pyproject.toml.

    line 64

≈ “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.

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

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

  1. Use uv for every project and package operation (uv sync, uv run <cmd>); never pip, poetry or conda.
  2. 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
  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 makes the real backend binaries unreachable for unit tests.
  7. 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.
  8. Unless you are the maintainer, never merge a PR and never approve your own PR; never commit to main.
  9. Never change .github/**, AGENTS.md or CLAUDE.md inside a milestone plan; those change only in a PR of their own.
  10. When a change touches a category in FINGERPRINT_COVERS (src/amicus/schemas/fingerprint.py), bump FINGERPRINT and regenerate the pins under tests/fixtures/ in their own commit.
  11. When a stored job result's shape changes, bump RESULT_FORMAT in the same file.
  12. 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 in scripts/check_commit_message.py.
  13. When a change needs a new commit scope, extend scripts/check_commit_message.py in that same change.
  14. Pin every uses: in a workflow to a full commit SHA with the version in a trailing comment.
  15. Never add a pull_request_target workflow.
  16. Under docs/, write Markdown with one sentence per line, where a semicolon or a colon joins clauses into one sentence rather than ending one.
  17. Never edit a sibling checkout (~/projects/codex-in-claude, ~/projects/moonbridge, ~/projects/claude-in-codex, ~/projects/pontonier).
  18. 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 a sha256 instead. 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 its CARRIERS string and surfaced on amicus_backends; the three that exist today are Kimi's handshake file, the kimi CLI's own session store, and Codex's -c developer_instructions argv token. Prompt text that a test or capture script assembles entirely from its own literals is exempt, including the build_*_prompt output committed in tests/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.
  19. Release in two PRs: the work lands with the version literals untouched, then a chore(release): PR moves them together and rolls ## [Unreleased] in CHANGELOG.md into a dated section. The literals are pyproject.toml, src/amicus/__init__.py, .claude-plugin/plugin.json, .codex-plugin/plugin.json and .mcp.json's --from pin, 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.lock mirrors the version rather than declaring it: regenerate it in that same PR with uv lock, or the uv lock --check hook 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, main declares a version that has no release.
  20. 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 under rule 5 — have all PASSED on that exact commit, with those passing outcomes recorded. The record is .release-evidence/live-gates.json, written by scripts/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.
  21. Never push a v* tag unless a repository ruleset restricts creation, update and deletion of v* tags, with no agent identity permitted to bypass it.
  22. Never weaken the verify job in .github/workflows/publish.yml, and never let the pypi job stop depending on it. Never move a release check into the pypi job: 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.
  23. 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.
  24. .claude-plugin/marketplace.json's plugin entry names a release that is already published, by ref and a sha equal 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 own chore(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.

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.