Skip to content

Latest commit

 

History

History
153 lines (119 loc) · 6.01 KB

File metadata and controls

153 lines (119 loc) · 6.01 KB

AGENTS.md

Orientation for coding agents working in this repo — i.e., agents contributing to openarmature itself. README.md covers what the project is and how to use it; this file covers things that aren't obvious from reading the code.

Two AGENTS.md files in this project. Different audiences.

  • This file (./AGENTS.md, at the repo root) — for agents working on the openarmature codebase. Package layout, test layout, tooling, spec-submodule discipline, commit conventions.
  • src/openarmature/AGENTS.md (shipped in the wheel) — for agents working in user codebases that depend on openarmature. Capability contracts, common patterns, non-obvious shapes, example index. Generated by scripts/build_agents_md.py from canonical sources; committed and CI-drift-checked.

Spec is the source of truth

This repo is a Python implementation of openarmature-spec. Behavior is defined by the spec; this repo executes it.

  • The spec lives at openarmature-spec/ as a git submodule pinned to a released tag. Don't edit files in the submodule.
  • The pin tracks the latest Accepted spec version, not the tip of openarmature-spec/main. main may contain Draft proposals merged into the spec text; only Accepted releases ship normative behavior, and the implementation conforms to the pinned Accepted release.
  • Behavior changes that aren't already in the Accepted spec require a proposal in the spec repo first, not a PR here.
  • To bump the spec submodule after a new Accepted release: cd openarmature-spec && git checkout <tag>, then bump the three places that track the version (below).

Spec proposal lifecycle

Proposals travel Draft → Accepted in the spec repo (see openarmature-spec/GOVERNANCE.md for the format and flow). Proposals live in openarmature-spec/proposals/; canonical spec text in openarmature-spec/spec/<capability>/.

When implementing a feature, read the relevant Accepted proposal first — don't infer behavior from existing impl alone. Draft proposals don't ship; their text may change before acceptance.

Three places hold the spec version — keep them in sync

  • tool.openarmature.spec_version in pyproject.toml
  • __spec_version__ in src/openarmature/__init__.py
  • The submodule commit (must match a released spec tag, e.g. v0.10.0)

tests/test_smoke.py asserts the first two match. The third is enforced by convention.

Package layout

  • src/openarmature/graph/ — graph engine (State, GraphBuilder, CompiledGraph, edges, projections, fan-out)
  • src/openarmature/llm/ — LLM Provider Protocol + OpenAIProvider; HTTP error classification + retry helpers
  • src/openarmature/checkpoint/ — checkpointing protocol + in-memory and filesystem backends
  • src/openarmature/observability/[otel] extra; OTel observer + log bridge + correlation primitives
  • src/openarmature/middleware/ — pipeline-utility middleware

Test layout

  • tests/conformance/ — runs the spec's YAML fixtures against the engine via an adapter. Drives most of the behavior coverage.
  • tests/unit/ — fills coverage gaps the conformance suite doesn't reach: edge_exception, reducer_error, state_validation_error, SubgraphNode.run, projection variants, frozen-state mutation, etc.
  • tests/test_smoke.py — version sync.

Tooling

  • uv for everything. Don't use pip directly.
  • Pyright strict mode is enforced (pyproject.toml). Annotations are not optional.
  • Ruff for lint + format. Pre-commit hook runs ruff format automatically — the file you committed may not be the file in the next diff.
  • pytest-asyncio with asyncio_mode = "auto"async def test_... works with no decorator.

Common commands

uv run pytest -q                            # all tests
uv run pytest tests/conformance/ -v         # spec conformance only
uv run ruff check . && uv run ruff format   # lint + format
uv run pyright src/ tests/                  # type check
uv run mkdocs serve                         # preview the docs site locally

Branch + commit conventions

Branch names use <type>/<kebab-case-description> (3–5 words). Allowed types:

  • feature/ — new functionality
  • fix/ — bug fixes
  • refactor/ — restructuring without behavior change
  • chore/ — tooling, deps, config, housekeeping
  • schema/ — data model changes

For ticketed work, embed the ID: feature/PROJ-123-short-description.

Commit subjects follow the 50/72 rule — subject ≤ 50 chars (hard cap 72), imperative mood, capitalized, no trailing period. Body wrapped at 72 columns. Body explains what and why, not how.

Docs

User-facing docs live in docs/ and build via MkDocs Material; the deployed site is at openarmature.ai. CI build + deploy is in .github/workflows/docs.yml. Local preview: uv run mkdocs serve.

Engine design notes that are easy to miss

  • State is frozen=True AND extra="forbid". Nodes that return an undeclared field surface as a state_validation_error, not a silent drop.
  • Conditional edges over-approximate at compile time (a conditional from node X is treated as reaching every node), so the unreachable-node check is sound but not tight.
  • Each node has exactly one outgoing edge. Branching is via conditional edges, not multiple statics.
  • END is a distinct sentinel object, not a reserved string. Use the exported END constant.

In scope / out of scope

In scope:

  • Graph engine + the spec's runtime contract.
  • Pipeline utilities (rate limiting, structured-output retry helpers).
  • Observability via OTel observer (under [otel] extra).
  • Checkpointing (in-memory + filesystem backends).
  • LLM Provider Protocol + the canonical OpenAI implementation.

Out of scope, deferred to sibling packages at v1.0:

  • openarmature-otel — eventual extraction of the OTel observer for projects that don't want it in core.
  • openarmature-eval — evaluation framework.

Behavior changes outside the Accepted spec require a spec proposal first.