You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add openarmature CLI and patterns API (agent-docs A3+A4) (#73)
* Add openarmature CLI and patterns API
Two new agent-discovery surfaces that complement the bundled
AGENTS.md from the previous release cycle:
- openarmature.patterns exposes list() and get(name) reading the
same patterns content as the bundled file via importlib.resources.
Useful in sandboxed environments that can import openarmature but
can't freely read arbitrary package paths.
- openarmature CLI registers init (writes a discovery pointer block
into the host project's AGENTS.md / CLAUDE.md) and docs (prints
the bundled AGENTS.md path). The same surface is reachable as
python -m openarmature via __main__.py for environments where
the [project.scripts] entry point doesn't land cleanly.
The CLI's pointer block is sourced from a canonical
src/openarmature/_pointer_block.md so editing what init writes
doesn't require touching Python code. init uses a comment marker
(<!-- openarmature-init -->) for idempotency so renaming the
visible heading doesn't fool the re-run detection.
The generator at scripts/build_agents_md.py now emits per-pattern
.md files under src/openarmature/_patterns/ with a
programmatic-only transform (no heading demotion; intra-pattern
links rewritten to absolute openarmature.ai URLs). The drift test
extends to cover the new directory.
__init__.py advertises all three discovery surfaces (bundled
AGENTS.md, programmatic patterns API, CLI). README's "For AI
agents" section mentions the CLI and the patterns API.
* Add UTF-8 encoding and zipimport guard in CLI
Address two issues raised in PR #73 review:
- _apply_init_to_file now reads and writes project AGENTS.md /
CLAUDE.md with an explicit encoding="utf-8" on every
read_text / write_text call. The platform default text
encoding is not UTF-8 on Windows (cp1252), which would
produce UnicodeDecodeError on UTF-8 content in existing
files or mojibake when writing the pointer block.
- _bundled_agents_md_path now uses importlib.resources.as_file
to resolve the bundled AGENTS.md and raises RuntimeError
with a clear message when the install isn't filesystem-backed
(pure zipimport). Previously the function would print a
non-existent path that the caller would then fail to open.
cmd_docs handles the RuntimeError by printing the message to
stderr and exiting with code 2. The docstring now claims
only wheel and editable installs (the realistic shapes for
this distribution) rather than implying "or zipped".
Copy file name to clipboardExpand all lines: CHANGELOG.md
+6-1Lines changed: 6 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,7 +8,12 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). The
8
8
9
9
### Added
10
10
11
-
-**Bundled agent documentation at `openarmature/AGENTS.md`.** The wheel now ships a generated `AGENTS.md` file at the installed package root, agent-discoverable via `python -c "import openarmature; print(openarmature.__path__[0] + '/AGENTS.md')"`. Sections include a TL;DR, capability summaries pulled from the pinned spec submodule's §1 (Purpose) + §2 (Concepts), the patterns docs, hand-written non-obvious-shapes recipes, and a one-line example index. Generator lives at `scripts/build_agents_md.py`; the committed file is CI-drift-checked by `tests/test_agents_md_drift.py`. The submodule pin discipline (build refuses unless the submodule HEAD is AT a `v*` tag via `git tag --points-at HEAD`) prevents draft (untagged) spec text — or text from a commit between two release tags — from leaking into a release bundle. Adopting projects can point their own `AGENTS.md` / `CLAUDE.md` at this path so agent sessions in their codebase find it automatically.
11
+
-**`openarmature.patterns` programmatic API.** Two-function surface (`list() -> list[str]`, `get(name: str) -> str`) exposing the same patterns content shipped in the bundled `AGENTS.md`. Each pattern is returned as a standalone markdown document: no heading demotion (patterns keep their original `# Title`), and relative `../concepts/...md` / `../examples/...md` / intra-pattern links are rewritten to absolute `openarmature.ai` URLs at build time so cross-references resolve outside the source tree. Useful for agents in sandboxed environments that can `import openarmature` but can't freely read arbitrary package paths. Content lives at `src/openarmature/_patterns/<slug>.md`, generated alongside the bundled `AGENTS.md` and drift-checked by `tests/test_agents_md_drift.py`. Unknown names raise `KeyError` with a message listing the known names.
12
+
-**`openarmature` CLI** registered as a `[project.scripts]` entry point with two subcommands:
13
+
-`openarmature init` appends a discovery pointer block (the `python -c "..."` one-liner + `openarmature docs` recipe) into the current project's `AGENTS.md` and `CLAUDE.md` so agent sessions opening the project find the bundled OpenArmature docs. Creates files when absent, appends when they exist, and skips re-runs via a `<!-- openarmature-init -->` comment marker. Flags: `--force` (re-append despite the marker), `--dry-run` (print what would be written), `--cwd PATH` (operate against a path other than the current directory).
14
+
-`openarmature docs` prints the absolute path to the bundled `AGENTS.md`. Equivalent to the README discovery one-liner but ergonomic to type and remember.
15
+
- The same surface is reachable as `python -m openarmature ...` via `src/openarmature/__main__.py`, so environments where the `[project.scripts]` entry doesn't land cleanly (some `pip install --target` layouts, path-shadowed venvs) still work as long as the package is importable.
16
+
-**Bundled agent documentation at `openarmature/AGENTS.md`.** The wheel now ships a generated `AGENTS.md` file at the installed package root, agent-discoverable via `python -c "import openarmature; print(openarmature.__path__[0] + '/AGENTS.md')"`. Sections include a TL;DR, capability summaries pulled from the pinned spec submodule's §1 (Purpose) + §2 (Concepts), the patterns docs, hand-written non-obvious-shapes recipes, and a one-line example index. Generator lives at `scripts/build_agents_md.py`; the committed file is CI-drift-checked by `tests/test_agents_md_drift.py`. The submodule pin discipline (build refuses unless the submodule HEAD is AT a `v*` tag via `git tag --points-at HEAD`) prevents draft (untagged) spec text — or text from a commit between two release tags — from leaking into a release bundle. Adopting projects can point their own `AGENTS.md` / `CLAUDE.md` at this path so agent sessions in their codebase find it automatically (or use `openarmature init` to do the wiring automatically).
12
17
-**`FanOutInstanceProgress.result_is_error` field** (proposal 0027, accepted in spec v0.21.0). Explicit boolean discriminator on each per-instance entry in `CheckpointRecord.fan_out_progress` — `True` for `collect`-mode error contributions (roll forward into `errors_field`), `False` for success contributions (roll forward into `target_field`). The engine reads the explicit field on resume rather than inferring routing from `result`'s shape; the previous structural heuristic (`_looks_like_error_record`) is removed. Backward-compat path on load: pre-0027 records that omit the key default to `False`.
13
18
-**Strict `CheckpointRecordInvalid` on fan-out count drift** (proposal 0029, accepted in spec v0.22.0). When the resumed run's resolved instance count differs from the saved `fan_out_progress` entry's `instance_count`, the engine raises `CheckpointRecordInvalid` before any fan-out instance work runs on the resumed path. Replaces the pre-0029 pad/truncate behavior which silently dropped `completed` contributions on shrink (breaking §10.11.1's exactly-once guarantee) and dispatched unsaved work on grow.
14
19
-**`tool_choice` parameter on `Provider.complete()`** (proposal 0025, accepted in spec v0.20.0). Optional discriminated-union value constraining the model's tool-calling behavior — one of `"auto"`, `"required"`, `"none"`, or a `ForceTool(name=...)` record. Validation runs pre-send: `"required"` and `ForceTool` both demand non-empty `tools`, and `ForceTool.name` must appear in the supplied list; violations raise `ProviderInvalidRequest` (§7's existing category — no new error category). When `tool_choice` is `None` (the default) the wire field is omitted and the provider's own default applies, preserving pre-0025 behavior exactly. The `OpenAIProvider` maps the spec shape onto OpenAI's wire shape per §8.1.1 (the `ForceTool.type="tool"` renames to wire `type="function"`).
The file ships with the package and covers capability contracts, common patterns, non-obvious shapes, and an example index. Adopting projects can point their own `AGENTS.md` / `CLAUDE.md` at this path so agent sessions in their codebase find it automatically.
207
+
Or use the convenience CLI:
208
+
209
+
```bash
210
+
openarmature docs # print the path to the bundled AGENTS.md
211
+
python -m openarmature docs # same, via the module entry point
212
+
```
213
+
214
+
The file ships with the package and covers capability contracts, common patterns, non-obvious shapes, and an example index. Adopting projects can run `openarmature init` from the project root to append a discovery pointer block into their own `AGENTS.md` / `CLAUDE.md` so agent sessions in their codebase find the bundled file automatically.
215
+
216
+
The same patterns content is also available programmatically:
0 commit comments