Skip to content

Bundle agent-discoverable AGENTS.md in the wheel (agent-docs A2)#72

Merged
chris-colinsky merged 6 commits into
mainfrom
feature/agent-docs-a2-bundled-agents-md
May 26, 2026
Merged

Bundle agent-discoverable AGENTS.md in the wheel (agent-docs A2)#72
chris-colinsky merged 6 commits into
mainfrom
feature/agent-docs-a2-bundled-agents-md

Conversation

@chris-colinsky
Copy link
Copy Markdown
Member

@chris-colinsky chris-colinsky commented May 26, 2026

Summary

Ships a generated AGENTS.md at openarmature/AGENTS.md in the installed wheel, addressing agent-docs A2 from the discuss-agent-discoverable-docs coord 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:

  1. Version-stamped self-reference header with pointers to the docs site, spec capabilities page, and the host project's own AGENTS.md / CLAUDE.md.
  2. TL;DR (hand-written, 3-5 sentences — what OA is and what it isn't).
  3. Capability summaries — §1 (Purpose) + §2 (Concepts) extracted from each capability's spec.md in the pinned submodule.
  4. Patterns — verbatim concatenation of docs/patterns/*.md.
  5. Non-obvious shapes — 5 hand-curated entries (FilesystemCheckpointer vs hand-rolled JSON; subgraphs vs conditional-edge spaghetti; explicit tool_choice; drain timeout; three exception hierarchies).
  6. Example index — one-line description + path for each examples/*/main.py. Full code not bundled (300+ lines per example would balloon the file).
  7. Discovery footer pointing back out.

Build pipeline + safety

Generator at scripts/build_agents_md.py. Two build-time invariants:

  • Submodule pin discipline. The build refuses to regenerate unless the submodule HEAD is reachable from a v* tag. Closes the "release ships a bundle pinned to draft (untagged) spec text" failure mode.
  • Read via 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:

  1. Project pointer. Host projects' AGENTS.md / CLAUDE.md point at the bundled file.
  2. Package-root scan. Curious agents find it via python -c "import openarmature; print(openarmature.__path__[0] + '/AGENTS.md')".
  3. __init__.py docstring 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-root AGENTS.md gets 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 — confirm openarmature/AGENTS.md ships in the wheel (46KB).
  • python -c "import openarmature; print(openarmature.__path__[0] + '/AGENTS.md')" — after pip install of the built wheel, the file is at the printed path.
  • Read src/openarmature/AGENTS.md end-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)

  • A3 — programmatic patterns API (openarmature.patterns.list() / get(name)) reading from the same payload.
  • A4openarmature init CLI that writes the discovery pointer into a host project's AGENTS.md / CLAUDE.md.
  • A5 — docstring audit pass for canonical-usage snippets in public APIs (parallel workstream, no dependency on A2's payload).

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.

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.
Copilot AI review requested due to automatic review settings May 26, 2026 01:08
Comment thread scripts/build_agents_md.py Fixed
Comment thread scripts/build_agents_md.py Fixed
Comment thread scripts/build_agents_md.py Fixed
Comment thread scripts/build_agents_md.py Fixed
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.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.py to generate src/openarmature/AGENTS.md from pinned spec content + local docs + examples.
  • Add tests/test_agents_md_drift.py to 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-root AGENTS.md audience.

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.

Comment thread scripts/build_agents_md.py Outdated
Comment thread scripts/build_agents_md.py
Comment thread scripts/build_agents_md.py
Comment thread src/openarmature/AGENTS.md Outdated
Comment thread src/openarmature/AGENTS.md Outdated
Comment thread src/openarmature/AGENTS.md
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.
Copilot AI review requested due to automatic review settings May 26, 2026 01:30
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.

Comment thread scripts/build_agents_md.py Outdated
Comment thread scripts/build_agents_md.py Outdated
Comment thread scripts/build_agents_md.py
Comment thread src/openarmature/AGENTS.md Outdated
Comment thread .github/workflows/ci.yml Outdated
Comment thread CHANGELOG.md Outdated
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.
@chris-colinsky chris-colinsky merged commit 6b5cc13 into main May 26, 2026
6 checks passed
@chris-colinsky chris-colinsky deleted the feature/agent-docs-a2-bundled-agents-md branch May 26, 2026 01:42
@chris-colinsky chris-colinsky mentioned this pull request May 26, 2026
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.
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.

3 participants