Bundle agent-discoverable AGENTS.md in the wheel (agent-docs A2)#72
Merged
Merged
Conversation
The wheel now ships a generated AGENTS.md at the installed package root (openarmature/AGENTS.md) for AI agents working in code that uses openarmature. Sections, in order: version-stamped self- reference header, TL;DR, capability summaries (spec §1+§2 of graph-engine / pipeline-utilities / llm-provider / observability / prompt-management), patterns from docs/patterns/*.md, hand-written non-obvious-shapes recipes, example index (one-liners + paths inside the source tree), discovery footer. Generator at scripts/build_agents_md.py reads from the pinned spec submodule via `git show <sha>:spec/...` (not the working tree) and refuses to regenerate unless the submodule HEAD is reachable from a v* tag — closes the "release ships a bundle pinned to draft spec text" failure mode. Spec text and patterns are pulled verbatim; the non-obvious-shapes file (docs/agent/non-obvious-shapes.md) and the TL;DR (docs/agent/tldr.md) are hand-curated by python. tests/test_agents_md_drift.py regenerates in-memory and diffs against the committed src/openarmature/AGENTS.md, failing the suite when the bundle is stale relative to its sources. Run on every PR via the standard pytest invocation. Bundle is 908 lines / 46KB at v0.22.1 — dense enough to be authoritative without ballooning past useful agent context budgets.
src/openarmature/__init__.py module docstring first line points at the bundled AGENTS.md so the file shows in standard IDE hover (Pylance / Pyright on `import openarmature`). README gets a "For AI agents" section with the discovery one-liner adopters can point their own AGENTS.md / CLAUDE.md at. Repo-root AGENTS.md gains a disambiguating note distinguishing the two AGENTS.md files in the project: this one orients agents working ON openarmature; the bundled src/openarmature/AGENTS.md orients agents in user codebases that USE openarmature. CHANGELOG Unreleased section gains an Added entry covering the bundle + discovery surface + drift check + the submodule-pin discipline that prevents draft spec text from leaking into a release bundle.
actions/checkout's submodule clone is shallow and doesn't carry tag refs. scripts/build_agents_md.py asserts the spec submodule HEAD is reachable from a v* tag (refuses to bundle draft spec text); tests/test_agents_md_drift.py runs that assertion and was failing on CI because the tags weren't fetched. git fetch --tags pulls just the tag refs into the existing shallow clone — no extra history needed since the HEAD commit is already present from the submodule checkout.
There was a problem hiding this comment.
Pull request overview
This PR adds an agent-discoverable, generated openarmature/AGENTS.md file to the Python package (wheel) and introduces a generator + drift test to keep the bundled content in sync with spec/docs/examples.
Changes:
- Add
scripts/build_agents_md.pyto generatesrc/openarmature/AGENTS.mdfrom pinned spec content + local docs + examples. - Add
tests/test_agents_md_drift.pyto regenerate in-memory and fail CI if the committed bundle drifts. - Add discovery pointers in
src/openarmature/__init__.py,README.md,CHANGELOG.md, and clarify the repo-rootAGENTS.mdaudience.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
scripts/build_agents_md.py |
Builds the bundled agent docs from spec/docs/examples with submodule pin checks. |
src/openarmature/AGENTS.md |
Generated agent documentation bundled into the package. |
tests/test_agents_md_drift.py |
Drift test to ensure committed bundle matches generator output. |
src/openarmature/__init__.py |
Adds docstring pointer to bundled AGENTS.md. |
README.md |
Adds “For AI agents” section with discovery command. |
docs/agent/tldr.md |
Source content for the bundle’s TL;DR section. |
docs/agent/non-obvious-shapes.md |
Source content for the bundle’s “Non-obvious shapes” section. |
CHANGELOG.md |
Documents the new bundled agent docs artifact. |
AGENTS.md |
Clarifies distinction between repo-root and packaged AGENTS.md. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
CodeQL / github-code-quality flagged implicit string concatenation in three list literals in scripts/build_agents_md.py (_capability_summaries, _patterns, _example_index). Switched to explicit + concatenation across all three sites — same intent (multi-line string assembly for readability), no possibly-missing- comma ambiguity. CoPilot flagged four bundle-quality issues: 1. _assert_pin_at_tag used reverse lexicographic sort, which gets multi-digit semver wrong (v0.10.0 < v0.9.0 lexicographically). Switched to git tag --sort=-version:refname for native version-aware ordering. No new Python deps. 2. Extracted spec sections retained ## 1. Purpose headings that were higher-level than the wrapping ### Capability: header. _extract_sections_1_2 now demotes ATX headings by two levels so the bundled markdown maintains a clean hierarchy. 3. Patterns were inlined verbatim with their original # headings (multiple H1s under the bundle) and relative ../concepts/...md / ../examples/...md links (broken in the installed wheel). New _transform_pattern_content demotes ATX headings by two levels and rewrites relative doc-tree links to absolute openarmature.ai/<section>/<name>/ URLs via _PATTERN_LINK_RE. 4. Bundle header / TLDR / discovery footer used openarmature.ai/capabilities/ for spec links, which isn't a real URL (.ai serves python docs; .org serves spec). Normalized those three sites to openarmature.org/capabilities/. The pattern files' existing .org URLs stay correct.
CI drift test failed because the generator emitted a trailing `\n\n` (``_discovery_footer`` ends with `\n` + the final `+ "\n"`), but the committed file got normalized to a single trailing `\n` by local pre-commit / editor settings. The generator now does ``"\n\n".join(sections).rstrip() + "\n"`` so output ends with exactly one final newline regardless of section-internal trailing whitespace. Absorbed spec's three strong-candidate non-obvious-shapes entries from the discuss-agent-discoverable-docs 07 review (option a — fold into PR #72 before merge rather than a follow-on): 1. Declare a non-clobbering reducer on accumulator list fields — highest "silent foot-gun" risk per spec ranking. Default ``last_write_wins`` silently clobbers prior contributions when multiple nodes append to a list. The fix is one ``Annotated[..., append]`` declaration on the state field; the diagnostic is non-obvious because the API doesn't complain. 2. Branch on ``Response.finish_reason`` before reading ``message.content`` — broadly applicable to any tool-calling pipeline. `tool_calls` finish reason carries the calls in ``message.tool_calls`` and leaves ``message.content`` empty; post-LLM logic reading ``content`` first misses the entire tool-calling path. 3. ``disable_llm_payload`` defaults to ``True`` — LLM-aware observability backends (Langfuse, Phoenix, Honeycomb LLM lens) need the flag flipped at observer construction. Per spec §5.5's "default-off by privacy" framing; the right default for general OA use, wrong default if you're wiring LLM-specific telemetry. Bundle grew from 908 to 973 lines, 46KB to 50KB. Still well within the 1500-2500-line target. Three new test_docs_examples illustrative snippets (the code samples in each entry) skip per the existing concept-page convention.
Three "reachable from" → "AT" wording fixes (build_agents_md.py module docstring, .github/workflows/ci.yml comment, CHANGELOG.md entry). The strict check (git tag --points-at HEAD) is the load-bearing invariant — a wheel built from a commit between two release tags would silently ship as if it were the prior tag. Wording now matches implementation; the check is unchanged. Module docstring's section-4 description previously said patterns were inlined "verbatim", which became stale when _transform_pattern_content landed earlier in this PR. Updated to describe both transforms (heading demotion + relative-link rewrite). _transform_pattern_content gains a second regex, _PATTERN_INTRA_LINK_RE, that rewrites pattern-to-pattern bare-name .md references to in-document anchors (e.g., `(bypass-if-output-exists.md)` → `(#bypass-if-output-exists)`). The demoted H3 heading slug matches the filename slug, so the anchor resolves cleanly in the bundled single-file context. Closes the broken pattern cross-link in tool-dispatch-as-node's "Cross-references" section.
6 tasks
chris-colinsky
added a commit
that referenced
this pull request
May 26, 2026
actions/checkout's submodule clone is shallow and doesn't carry tags. scripts/build_agents_md.py asserts the spec submodule HEAD is AT a v* tag (used by tests/test_agents_md_drift.py). ci.yml has had this step since PR #72; release.yml was missed, so the v0.9.0-rc1 tag's test job failed on the drift check. Build / publish jobs don't regenerate AGENTS.md (they package the committed file via hatchling), so the fix is only needed in the test job.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Ships a generated
AGENTS.mdatopenarmature/AGENTS.mdin the installed wheel, addressing agent-docs A2 from thediscuss-agent-discoverable-docscoord thread. AI agents working in user codebases that depend on openarmature can discover authoritative orientation without re-reading the source each session.The bundled file is 908 lines / 46KB at the current spec pin (v0.22.1). Sections in order:
AGENTS.md/CLAUDE.md.spec.mdin the pinned submodule.docs/patterns/*.md.tool_choice; drain timeout; three exception hierarchies).examples/*/main.py. Full code not bundled (300+ lines per example would balloon the file).Build pipeline + safety
Generator at
scripts/build_agents_md.py. Two build-time invariants:v*tag. Closes the "release ships a bundle pinned to draft (untagged) spec text" failure mode.git show <sha>:spec/..., not the working tree. Closes the "stale checkout produces stale bundle content" failure mode.CI drift catch via
tests/test_agents_md_drift.py— regenerates in-memory and diffs against the committed file. Runs as part of standard pytest; fails the PR if the committed bundle is out of date with its sources.Discovery surface
Three discovery paths per the coord thread's design:
AGENTS.md/CLAUDE.mdpoint at the bundled file.python -c "import openarmature; print(openarmature.__path__[0] + '/AGENTS.md')".__init__.pydocstring pointer. First line of the module docstring directs agents reading the import.README gains a "For AI agents" section with the discovery one-liner adopters can copy into their own
AGENTS.md/CLAUDE.md. Repo-rootAGENTS.mdgets a disambiguating note (the existing file orients agents working on openarmature; the bundled file orients agents working in code that uses openarmature — different audiences, both files coexist).Test plan
uv run pytest tests/— 804 pass, 75 skipped, 0 failures.uv run pytest tests/test_agents_md_drift.py -v— drift test green.uv build --wheel && unzip -l dist/*.whl | grep AGENTS.md— confirmopenarmature/AGENTS.mdships in the wheel (46KB).python -c "import openarmature; print(openarmature.__path__[0] + '/AGENTS.md')"— afterpip installof the built wheel, the file is at the printed path.src/openarmature/AGENTS.mdend-to-end; sanity-check the capability extractions and patterns content.mkdocs serve— verify the patterns docs source the bundle reads from still render unchanged.Out of scope (deferred to follow-on PRs)
openarmature.patterns.list()/get(name)) reading from the same payload.openarmature initCLI that writes the discovery pointer into a host project'sAGENTS.md/CLAUDE.md.Spec coordination
Plan + scope acked in
discuss-agent-discoverable-docs/05-spec-staging-and-a2-plan-ack.md. No spec text changes for any of A2/A3/A4/A5; the bundle reads from spec source via the pinned submodule.