diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index cc9ce26..73cc803 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -10,6 +10,10 @@ "name": "agent-fleet", "source": "./plugins/agent-fleet" }, + { + "name": "agents-md", + "source": "./plugins/agents-md" + }, { "name": "crew", "source": "./plugins/crew" diff --git a/README.md b/README.md index caa2105..f9d5688 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ Or paste `4nrry/agent-plugins` into the Claude Desktop **Add marketplace** dialo | Plugin | What it is | |---|---| | [agent-fleet](plugins/agent-fleet/) | Rules for multi-agent work — model routing per phase, fan-out sizing, output schemas, and citation verification. Two hooks, because the prose alone measurably did not fire. | +| [agents-md](plugins/agents-md/) | Write, slim and audit a repo's AGENTS.md: what goes in, what comes out, per-tool limits (Claude Code, Antigravity, Codex), and a stdlib checker for missing scripts, dead paths, oversize files and the CLAUDE.md that hides AGENTS.md from Claude Code. | | [crew](plugins/crew/) | Cheap headless workers through three agent CLIs, without fighting Claude's harness: Claude writes the task, sets scope and gate, and reviews the diff; the worker runs one slice under its own CLI's hooks, installed for the run only. Backends: agy (Antigravity CLI, Gemini; default), opencode (free Zen models, weaker shell guard) and GitHub Copilot CLI (Free plan: `--model auto` only, paid in AI credits, no shell). The verdict never reads exit 0 as success — in agy 1.3.4 timeouts, denied actions and an unmet `--json-schema` all exit 0 (observed, n=1 each). One skill per backend plus a shared delegation doc, injected by a UserPromptSubmit hook when the prompt names the CLI, and a watcher that ends the background commands agy would otherwise wait 30 min for. | | [game-facts](plugins/game-facts/) | Pins the installed game's version before the agent answers from training memory. A UserPromptSubmit hook reads Steam appmanifests and injects appid, buildid and update date — so the version never has to be typed into the prompt. | | [homelab](plugins/homelab/) | Software you maintain yourself on a Linux box, where the official docs stop. A Palworld dedicated server (the config the server erases on shutdown), WireGuard through NetworkManager (the IPv6 leak that passes the IP test), and tarball installs (one versioned layout, and why a self-updating app must not live in /opt). Machine state stays out of the repo. | diff --git a/plugins/agents-md/.claude-plugin/plugin.json b/plugins/agents-md/.claude-plugin/plugin.json new file mode 100644 index 0000000..2376266 --- /dev/null +++ b/plugins/agents-md/.claude-plugin/plugin.json @@ -0,0 +1,11 @@ +{ + "name": "agents-md", + "displayName": "AGENTS.md", + "version": "0.1.0", + "author": { + "name": "4nrry", + "url": "https://github.com/4nrry" + }, + "license": "MIT", + "description": "Escrever, enxugar e auditar o AGENTS.md de um repositorio: o que entra (comando que existe, como provar que terminou, armadilha que falha em silencio, contrato com outro repo), o que sai (arvore, lista derivavel, historia, grito em caixa alta), e onde cada coisa mora quando nao cabe. Junta as regras das docs do Claude Code, do Antigravity, do Codex e do agents.md numa tabela de limites — inclusive as duas armadilhas que mais custaram aqui: um CLAUDE.md na pasta esconde o AGENTS.md do Claude Code, e o Antigravity nao le CLAUDE.md nem expande '@arquivo' solto. Traz um checador mecanico (stdlib, --self-test) que pega comando inexistente, caminho citado que nao existe, arquivo acima do teto e CLAUDE.md que sombreia, antes de gastar agente. Sem alegacao de melhoria: nao ha run records; a origem e uma auditoria de 19 repos em que verificadores baratos acharam 11 afirmacoes falsas em 16 rascunhos ja revisados." +} diff --git a/plugins/agents-md/README.md b/plugins/agents-md/README.md new file mode 100644 index 0000000..d5cc05f --- /dev/null +++ b/plugins/agents-md/README.md @@ -0,0 +1,27 @@ +# AGENTS.md + +Arquivo de instrucoes de agente cresce, envelhece e para de ser seguido. Numa +auditoria de 19 repositorios, os arquivos tinham ate 974 linhas, um deles +estava 159 commits atrasado em relacao ao codigo, e sete eram invisiveis para o +Antigravity porque viviam em `CLAUDE.md`. Este plugin e o checklist que saiu +dessa limpeza, mais um checador que pega o erro barato sem gastar agente. + +## Componentes + +| componente | o que faz | +|---|---| +| `skills/agents-md/` | O que entra, o que sai, forma, limites por ferramenta, como auditar barato e como manter. | +| `scripts/check_agents_md.py` | Checagem mecanica de um repo: teto de tamanho, `npm run` inexistente, caminho citado que nao existe, grito, `CLAUDE.md` que esconde o `AGENTS.md`, `GEMINI.md` com `@arquivo` que o Antigravity nao expande. `--self-test`. Sai 1 quando aponta algo. | + +## O que o checador nao sabe + +Caminho citado relativo a outro repo (contrato do backend vizinho, por exemplo) +aparece como inexistente: e falso positivo esperado, confira antes de mexer. +Fila, porta, env var e nome de modulo ficam fora do alcance de um regex; para +esses, a skill descreve um verificador barato por arquivo. + +## O que isto nao estabelece + +Nao ha run records. Os numeros acima sao da auditoria que originou o plugin, +nao de uma comparacao com e sem a skill; pela regra do `bench/PROTOCOL.md`, +isso proibe qualquer alegacao de melhoria. diff --git a/plugins/agents-md/scripts/check_agents_md.py b/plugins/agents-md/scripts/check_agents_md.py new file mode 100755 index 0000000..23c9be8 --- /dev/null +++ b/plugins/agents-md/scripts/check_agents_md.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +"""Mechanical checks for a repo's agent-instruction files. No model, no network. + +Usage: check_agents_md.py exit 1 when anything is flagged + check_agents_md.py --self-test +""" +import json +import pathlib +import re +import sys +import tempfile + +MAX_LINES, MAX_BYTES = 150, 10_000 +ANTIGRAVITY_FILE_CAP = 24_000 +SHOUT = re.compile(r"\b(CRITICAL|ALWAYS USE FIRST|YOU MUST|NEVER EVER)\b") +NPM_RUN = re.compile(r"\b(?:npm run|pnpm run|yarn run|bun run)\s+([a-z][\w:.-]*)") +TICKED_PATH = re.compile(r"`([\w./-]+/[\w.-]+\.[a-z]{1,6})`") +BARE_IMPORT = re.compile(r"^\s*@(?!\[)([\w./-]+)\s*$", re.M) + + +def check(repo: pathlib.Path) -> list[str]: + out = [] + agents = repo / "AGENTS.md" + for shadow in ("CLAUDE.md", ".claude/CLAUDE.md", "CLAUDE.local.md"): + p = repo / shadow + if agents.exists() and p.exists() and "@AGENTS.md" not in p.read_text(encoding="utf-8"): + out.append(f"{shadow}: exists, so Claude Code skips AGENTS.md (no @AGENTS.md import)") + gem = repo / "GEMINI.md" + if gem.exists(): + for m in BARE_IMPORT.finditer(gem.read_text(encoding="utf-8")): + out.append(f"GEMINI.md: '@{m.group(1)}' is not inlined by Antigravity (only @[label](path) is)") + pkg = repo / "package.json" + scripts = set() + if pkg.exists(): + try: + scripts = set(json.loads(pkg.read_text(encoding="utf-8")).get("scripts", {})) + except ValueError: + out.append("package.json: does not parse") + files = [agents] + sorted((repo / "docs" / "agents").glob("*.md")) + for f in files: + if not f.exists(): + continue + text = f.read_text(encoding="utf-8") + name = f.relative_to(repo).as_posix() + lines, size = text.count("\n") + (not text.endswith("\n") and bool(text)), len(text.encode()) + if f == agents and (lines > MAX_LINES or size > MAX_BYTES): + out.append(f"{name}: {lines} lines / {size} bytes (cap {MAX_LINES} / {MAX_BYTES})") + if size > ANTIGRAVITY_FILE_CAP: + out.append(f"{name}: over {ANTIGRAVITY_FILE_CAP} bytes, Antigravity truncates it") + for s in sorted(set(NPM_RUN.findall(text))): + if pkg.exists() and s not in scripts: + out.append(f"{name}: `npm run {s}` but package.json has no script '{s}'") + for p in sorted(set(TICKED_PATH.findall(text))): + if "<" in p or "*" in p: + continue + if not (repo / p).exists() and not (f.parent / p).exists(): + out.append(f"{name}: cites `{p}`, which does not exist") + for n, line in enumerate(text.splitlines(), 1): + if SHOUT.search(line): + out.append(f"{name}:{n}: shouting ({SHOUT.search(line).group(1)})") + return out + + +def self_test() -> int: + with tempfile.TemporaryDirectory() as d: + r = pathlib.Path(d) + (r / "src").mkdir() + (r / "src/main.ts").write_text("") + (r / "package.json").write_text('{"scripts": {"test": "jest"}}') + (r / "AGENTS.md").write_text("Run `npm run test`.\nSee `src/main.ts` and `src/gone.ts`.\nCRITICAL: x\n") + (r / "CLAUDE.md").write_text("old stuff\n") + (r / "GEMINI.md").write_text("@CLAUDE.md\n") + got = check(r) + want = ["CLAUDE.md: exists", "GEMINI.md: '@CLAUDE.md'", "cites `src/gone.ts`", "AGENTS.md:3: shouting"] + miss = [w for w in want if not any(w in g for g in got)] + bad = [g for g in got if "main.ts" in g or "npm run test" in g] + (r / "AGENTS.md").write_text("Run `npm run build`.\n") + (r / "CLAUDE.md").write_text("@AGENTS.md\n") + second = check(r) + if miss or bad or not any("'build'" in g for g in second) or any(g.startswith("CLAUDE.md") for g in second): + print("self-test FAILED", miss, bad, got, second) + return 1 + print("self-test ok") + return 0 + + +def main(argv: list[str]) -> int: + if argv[1:] == ["--self-test"]: + return self_test() + if len(argv) != 2 or not pathlib.Path(argv[1]).is_dir(): + print(__doc__.strip()) + return 2 + found = check(pathlib.Path(argv[1])) + for line in found: + print(line) + if not found: + print("ok") + return 1 if found else 0 + + +if __name__ == "__main__": + sys.exit(main(sys.argv)) diff --git a/plugins/agents-md/skills/agents-md/SKILL.md b/plugins/agents-md/skills/agents-md/SKILL.md new file mode 100644 index 0000000..bb25e13 --- /dev/null +++ b/plugins/agents-md/skills/agents-md/SKILL.md @@ -0,0 +1,109 @@ +--- +name: agents-md +description: Escrever, enxugar ou auditar o AGENTS.md (ou CLAUDE.md, GEMINI.md) de um repositorio — o que entra, o que sai, tamanho, onde cada coisa mora, e como checar que o arquivo nao mente sobre o codigo. Cobre os limites de cada ferramenta (Claude Code, Antigravity, Codex), o CLAUDE.md que esconde o AGENTS.md, e um checador mecanico que pega comando inexistente, ponteiro quebrado e arquivo grande demais sem gastar agente. Use quando a tarefa mencionar AGENTS.md, CLAUDE.md, GEMINI.md, .cursorrules, instrucoes do agente, "rules token budget", arquivo de instrucoes desatualizado ou gigante, ou /init. +--- + +# AGENTS.md que o agente segue + +Arquivo de instrucoes e contexto carregado em toda sessao. Cada linha custa +token em toda tarefa, e arquivo inchado faz o agente ignorar justamente a +regra que importa. O teste de toda linha: **se eu tirar isto, o agente erra?** +Se nao erra, sai. + +## Entra + +- Comandos exatos e que existem: instalar, rodar, o teste mais estreito, + lint/typecheck, migration. Agente roda o check que estiver listado. +- Como provar que terminou: o comando que da passou/falhou. Sem ele, "parece + pronto" e o unico sinal que o agente tem. +- Armadilhas que falham em silencio: o comando que passa sem testar nada, a env + var sem a qual tudo sobe errado, a config que precisa de restart. +- Contratos com outros repos que daqui nao se deduzem: fila/routing key, + header, formato de ID, porta exposta. +- Convencoes que fogem do padrao da linguagem ou do framework. +- Etiqueta do repo: branch base, nome de branch, squash ou nao, o que rodar + antes de commitar. +- Decisao de arquitetura com o porque, so quando o codigo nao explica sozinho. +- Mapa curto: onde moram as 3 a 5 coisas que se procuram toda hora. +- Ponteiro com gatilho para o que mora em outro arquivo: "antes de mexer em + X, leia `/AGENTS.md`" ou o `AGENTS.md` comum acima dos repos. + +## Sai + +- Arvore de diretorios, lista de endpoints, dump de schema, lista de + dependencias, descricao arquivo por arquivo. O agente le o codigo. +- Tutorial e documentacao de API: link, nao copia. +- O que muda toda hora: versao, contagem, "ultima atualizacao", estado de + sprint. E o primeiro trecho a ficar velho. +- Conselho obvio ("escreva codigo limpo", "use tipos"). +- Changelog e historia de ticket: o git guarda. +- Instrucao de uma ferramenta so ("use o MCP X primeiro"). +- Segredo, URL com token, dado de cliente. + +## Forma + +- Bullets curtos sob cabecalhos. Paragrafo denso e seguido pior. +- Concreto e verificavel: "rode `npm test -- foo`", nao "teste suas mudancas". +- Tom calmo, com o motivo. `IMPORTANT` em no maximo uma linha; se tudo grita, + nada se destaca, e modelos atuais aplicam frase agressiva demais. +- Duas instrucoes que se contradizem fazem o agente escolher no chute: revise o + arquivo da raiz contra os aninhados. +- Nota so para humanos vai em `` de bloco: o Claude Code a + remove antes de carregar. + +## Tamanho e onde mora + +| ferramenta | o que le | limite | +|---|---|---| +| Claude Code | `CLAUDE.md`; `AGENTS.md` nativo desde 2.1.277, **so se nao houver `CLAUDE.md` nem `CLAUDE.local.md` na pasta ou acima** | recomenda < 200 linhas; carrega ate 4 MiB | +| Antigravity | `AGENTS.md`, `GEMINI.md`, `.agents/rules/`; **nao le `CLAUDE.md`**; `@arquivo` solto nao e inlinado, so `@[label](path)` | 24 KB por arquivo (corta o resto); 20 mil tokens somando tudo que esta always-on | +| Codex | `AGENTS.override.md` ou `AGENTS.md`, da raiz do git ate o cwd | para de juntar em 32 KiB somados | + +- Meta: 60 a 100 linhas e menos de 6 KB. Teto: 150 linhas / 10 KB. +- `@import` nao economiza: o importado tambem carrega no inicio. +- Um arquivo so, `AGENTS.md`, para todas as ferramentas. Um `CLAUDE.md` ou + `CLAUDE.local.md` na mesma pasta ou acima esconde o `AGENTS.md` do Claude. +- O que vale para parte do codigo vai para um `AGENTS.md` aninhado na + subpasta (o mais proximo vence). Doc solto em `docs/` so se alguem o audita: + doc velho engana o agente que o le, e ninguem o confere contra o codigo. +- Procedimento de varios passos vira skill. Regra que nao pode falhar nunca + vira hook: o arquivo e orientacao, o hook e garantia. +- Arquivo global: o Claude Code le so `~/.claude/CLAUDE.md` (nao ha + `AGENTS.md` de usuario); o Antigravity le `~/.gemini/config/AGENTS.md` (ou + `GEMINI.md`). Sao dois arquivos: mantenha um e gere o outro a partir dele. +- O Claude Code procura `AGENTS.md` em todas as pastas acima do cwd; o + Antigravity e o Codex param na raiz do git. Um `AGENTS.md` comum acima dos + repos so chega a eles por ponteiro no `AGENTS.md` de cada repo. +- Workspace com varios repos abertos soma os arquivos de todos no Antigravity. + Abra o repo da tarefa, nao a pasta-mae, antes de cortar arquivo bom. + +## Auditar sem torrar uso + +1. Checagem mecanica primeiro, de graca: + + ```bash + python3 "${CLAUDE_PLUGIN_ROOT}/scripts/check_agents_md.py" + ``` + + Aponta: arquivo acima do teto, `npm run X` que nao existe no + `package.json`, caminho citado em crase que nao existe, palavras de grito, + `CLAUDE.md`/`CLAUDE.local.md` que escondem o `AGENTS.md`, `GEMINI.md` com + `@arquivo` que o Antigravity nao expande. Caminho relativo curto pode dar + falso positivo: confira antes de mexer. +2. Audite contra o codigo da branch padrao do origin, nao o checkout local + (que costuma estar atrasado): `git archive origin/ | tar -x -C `. +3. Para fatos que o script nao alcanca (fila, porta, env var, nome de modulo), + um agente barato (Haiku) por arquivo, que devolve **so** as afirmacoes + falsas com `path:linha`. Confira cada apontamento antes de aplicar: o + verificador acerta muito, mas nao sempre. +4. No Claude Code, `/doctor` sugere cortes e `/doctor prompt-audit` acha + comando inexistente e contradicao entre arquivos. + +## Manter + +- Revise no PR que muda comando, porta, fila ou layout. Arquivo velho e pior + que arquivo nenhum: o agente acredita nele. +- Acrescente uma linha quando o agente repete um erro, quando o review pega + algo que ele deveria saber, ou quando voce digita a mesma correcao de novo. +- Mudou uma regra? Veja se o comportamento mudou. Se o agente continua + ignorando, o arquivo esta longo demais ou a frase esta ambigua.