Skip to content

docs: extend AGENTS.md with conventions mined from PR reviews - #3776

Draft
julian-risch wants to merge 4 commits into
mainfrom
docs/agents-md-from-pr-reviews
Draft

docs: extend AGENTS.md with conventions mined from PR reviews#3776
julian-risch wants to merge 4 commits into
mainfrom
docs/agents-md-from-pr-reviews

Conversation

@julian-risch

@julian-risch julian-risch commented Aug 14, 2026

Copy link
Copy Markdown
Member

Related Issues

  • none

Proposed Changes:

Our AGENTS.md documents the mechanics — hatch per integration, tests, mypy, versioning — but none of the judgement reviewers apply across 100+ integration packages. That knowledge lives only in review comments.

This adds 129 rules mined with pydantic/braindump (see Scaling open source with AI) from 2,772 PR review comments written by deepset reviewers between 2025-07-01 and 2026-08-14. The hand-written sections of AGENTS.md are untouched; the mined rules follow underneath.

Layout. Everything lives in one root AGENTS.md (129 rules, ~5.1k tokens), with CLAUDE.md reduced to a one-line @AGENTS.md import.

An earlier revision split this across integrations/AGENTS.md plus two agent_docs/*.md topic guides, which would have cut the always-loaded size to ~2.1k. That was reverted for two reasons:

  • Topic guides are not memory files. The root AGENTS.md only links to them, so nothing loads them automatically — an agent has to choose to follow the link. Verified with canary fixtures: with file tools blocked the topic content is absent 3/3 while the root file is present. With tools available the agent did follow the link 3/3, but that test named docstrings explicitly and so matched the link's "when to check" text almost word for word; a vaguer real task matches less well.
  • The split bought little here. Nearly all work in this repo happens under integrations/, so the lazily-loaded file would have loaded almost always anyway.

The cost is ~5.1k tokens in every session rather than ~2.1k. The benefit is that no rule can be missed. The companion core PR keeps a nested layout, where rules divide cleanly by directory (test/, releasenotes/notes/, docs-website/) and group produced no topic files.

Claude Code reads CLAUDE.md, not AGENTS.md (docs), so the import is what puts the guidance in context. Codex and Cursor read AGENTS.md directly, so it stays the single source of truth.

Verified with canary fixtures (claude -p, file tools disabled so the model can only answer from loaded context):

Setup Canary in context?
CLAUDE.md = @AGENTS.md yes
AGENTS.md alone, no CLAUDE.md no — Claude Code does not read AGENTS.md on its own
CLAUDE.md = the old prose, tools disabled no — nothing is preloaded
nested sub/CLAUDE.md = @AGENTS.md, cwd at root, after reading sub/thing.py yes — loads lazily, which is what the split relies on
nested, cwd inside sub/ yes

For fairness: with Read enabled the old prose form did work — the model went and read AGENTS.md in 3/3 runs. The import's advantage is that it is deterministic and costs no tool-call round-trip, not that the old form was broken.

2,627 candidate generalisations collapsed into 379 deduplicated rules, of which 129 survived scoring and review. The clustering does useful work in a monorepo: conventions that recur across integrations (serialisation symmetry with __init__, warm_up() lifecycle, Secret resolution, filter policy, sync/async parity, protocol parameter order) generalise and survive, while per-integration one-offs score too low to appear. place assigned most rules to the root or to integrations/ rather than to individual packages, which is the outcome we want.

Handling the 3.0 boundary. The corpus mostly predates Haystack 3.0 (2026-07-20), so rules were filtered against the current tree before inclusion. This repo is the interesting case: it removed almost nothing of its own — it gained the ~45 component classes that moved out of core. So its staleness set is inherited from core rather than computed locally: guidance about APIs that left haystack and landed here stays valid, guidance about APIs that disappeared entirely does not. Verdicts: 343 current, 34 rewritten, 2 stale. A recency weighting demotes rules whose only supporting evidence is old.

How did you test it?

Markdown-only change, so no test suite applies. Verified instead:

  • No stale rule leaked. Every rule joined back to its verdict: 119 current, 11 rewritten, 0 stale, 0 unknown ids.
  • Symbol sanity. All 165 backticked identifiers in the block resolve against the current integrations/*/src/ tree — zero removed or relocated names.
  • Stale bucket read by hand (2 rules).
  • Extraction quality gated by a 50-comment smoke test before the full run.

Notes for the reviewer

  • What to actually review: the rules themselves. A rule you would not enforce in review should not be here. The files carry no provenance metadata: judge each rule on whether it reads as a convention this project actually holds, not on where it came from.
  • Five rules were generalised on review because clustering had pinned them to whichever integration the source comments discussed: WATSONX_API_KEY became "default each Secret from the provider's conventional env var" (it is one of ~10 such variables here), Elasticsearch bulk-write handling became "preserve documented bulk write/delete error behaviour" (DocumentStoreError is used by 17 stores), and the RagasEvaluator/Google GenAI example list became "refresh docs when model names or provider APIs change". One rule scoped entirely to integrations/amazon_bedrock/tests/ was dropped. Please flag any others that still read as too narrow for a repo-wide file.
  • The rules are weighted toward the highest-volume reviewers, so they reflect their emphases more than the team average.
  • Verification limitation worth knowing: every recent PR is inside the corpus, so I could not test against held-out reviews.
  • Companion PR against deepset-ai/haystack does the same for core.

Checklist

🤖 Generated with Claude Code

julian-risch and others added 2 commits August 14, 2026 20:11
Our AGENTS.md documents the mechanics -- hatch per integration, tests, mypy,
versioning -- but none of the judgement reviewers actually apply across 100+
integration packages. That knowledge lived only in review comments.

This adds 130 rules mined with pydantic/braindump from 2,772 review comments written
by the deepset team between 2025-07-01 and today, clustered and deduplicated across
PRs so that only repeatedly-enforced conventions survive. Rules that recur across
integrations (serialisation symmetry, warm_up lifecycle, Secret handling, filter
policy, async parity) generalise; per-integration one-offs do not and were dropped.

Because the corpus mostly predates Haystack 3.0, rules were filtered against the
current tree first. This repo removed almost nothing of its own -- it gained the ~45
component classes that moved out of core -- so the staleness check here is inherited
from core: guidance about APIs that left haystack but landed here stays valid, while
guidance about APIs that disappeared entirely does not.

Each <!-- rule:N --> marker traces back to its source review comments.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review feedback on the single-file version:

- Nested layout, as braindump generates it. The cross-integration rules move to
  integrations/AGENTS.md and the two topic guides stay as linked agent_docs/
  pages, so the root file carries only what applies repo-wide. Root drops
  5,755 -> 2,116 tokens (-64%).
- CLAUDE.md now imports AGENTS.md via '@AGENTS.md'. Claude Code reads CLAUDE.md,
  not AGENTS.md, and the previous prose ('read the AGENTS.md file...') only worked
  if the model chose to act on it. The import inlines the content at session start.
  integrations/ gets the same one-line CLAUDE.md, since nested memory files are
  picked up lazily.
- Dropped the inline <!-- rule:N --> markers, ~10% of every file for traceability
  nothing reads at runtime.

Note that most work in this repo happens under integrations/, so the split saves
less here than in core -- the win is mainly that repo-level work (CI, tooling,
docs) no longer loads 73 integration-specific rules.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@julian-risch
julian-risch force-pushed the docs/agents-md-from-pr-reviews branch from a34247e to 8a94655 Compare August 15, 2026 08:06
julian-risch and others added 2 commits August 15, 2026 11:47
…d rules

The <!-- braindump:begin/end --> comments existed so the mined block could be
replaced in place on a re-run. That anchor now lives in the generator instead, so
the shipped files carry no scaffolding.

Clustering preserves whichever example the source review comments happened to
discuss, which leaves some rules reading as if they only apply to one integration:

- 'preserve all runtime config, including Watsonx max_retries, ...' -> every
  constructor argument that affects runtime behaviour must round-trip.
- 'use WATSONX_API_KEY for Watsonx components' -> default each Secret from the
  provider's conventional env var. WATSONX_API_KEY is one of ~10 such variables
  here (COHERE_API_KEY, NVIDIA_API_KEY, JINA_API_KEY, HF_API_TOKEN, ...).
- 'preserve Elasticsearch bulk write/delete try/except behavior' -> preserve
  documented bulk write/delete error behaviour. DocumentStoreError is used by 17
  document stores, not just Elasticsearch.
- 'update ... Google GenAI model names and RagasEvaluator ragas.metrics.collections
  usage' -> refresh docstrings, cookbooks and integration docs when model names or
  provider APIs change.
- 'especially in integrations/mcp/src/haystack_integrations/tools/mcp/' -> dropped
  the path; the warm_up() rule is repo-wide.

Removed 'Update integrations/amazon_bedrock/tests/ with generator changes': it is
entirely about one integration, and the general form is trivial.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The split layout left 21 rules in agent_docs/*.md topic files that the root
AGENTS.md only linked to. Those are not memory files, so nothing loads them
automatically -- an agent has to choose to follow the link. Measured with canary
fixtures: with file tools blocked the topic content is absent 3/3 while the root
file is present, confirming it is a discretionary read rather than context.

With tools available the agent did follow the link 3/3, but that test named
docstrings explicitly and so matched the link's "when to check" text almost word
for word; a vaguer real task matches less well. A rule that loads every time beats
one that usually loads.

Folding integrations/AGENTS.md in too, rather than only the topic files: nearly
all work in this repo happens under integrations/, so the nested split saved
little. Core keeps its nested layout, where the rules divide cleanly by directory
(test/, releasenotes/notes/, docs-website/) and group produced no topic files.

Cost: ~5.1k tokens loaded every session instead of ~2.1k. The tradeoff is that
nothing can be missed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant