Skip to content

Commit 0dc808b

Browse files
docs: expand README, add CLAUDE.md orientation
1 parent fccce00 commit 0dc808b

2 files changed

Lines changed: 109 additions & 0 deletions

File tree

CLAUDE.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# CLAUDE.md
2+
3+
Orientation for Claude Code sessions in this repo. The `README.md` covers what the project is and how to use it; this file covers things that aren't obvious from reading the code.
4+
5+
## Spec is the source of truth
6+
7+
This repo is a Python implementation of [`openarmature-spec`](https://github.com/LunarCommand/openarmature-spec). Behavior is defined by the spec; this repo executes it.
8+
9+
- The spec lives at `openarmature-spec/` as a git submodule pinned to a released tag. Don't edit files in the submodule.
10+
- To bump the spec: `cd openarmature-spec && git checkout <tag>`, then bump the three places that track the spec version (see below).
11+
- Behavior changes that aren't already in the spec require a proposal in the spec repo first, not a PR here.
12+
13+
## Three places hold the spec version — keep them in sync
14+
15+
- `tool.openarmature.spec_version` in `pyproject.toml`
16+
- `__spec_version__` in `src/openarmature/__init__.py`
17+
- The submodule commit (must match a released tag, e.g. `v0.1.1`)
18+
19+
`tests/test_smoke.py` asserts the first two match. The third is enforced by convention.
20+
21+
## Test layout
22+
23+
- `tests/conformance/` — runs the spec's YAML fixtures against the engine via an adapter. Drives most of the behavior coverage.
24+
- `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.
25+
- `tests/test_smoke.py` — version sync.
26+
27+
## Tooling
28+
29+
- `uv` for everything. Don't use `pip` directly.
30+
- Pyright **strict mode** is enforced (`pyproject.toml`). Annotations are not optional.
31+
- Ruff for lint + format. Pre-commit hook runs `ruff format` automatically — the file you committed may not be the file in the next diff.
32+
- `pytest-asyncio` with `asyncio_mode = "auto"``async def test_...` works with no decorator.
33+
34+
## Common commands
35+
36+
```bash
37+
uv run pytest -q # all tests
38+
uv run pytest tests/conformance/ -v # spec conformance only
39+
uv run ruff check . && uv run ruff format # lint + format
40+
uv run pyright src/ tests/ # type check
41+
```
42+
43+
## Engine design notes that are easy to miss
44+
45+
- `State` is `frozen=True` AND `extra="forbid"`. Nodes that return an undeclared field surface as a `state_validation_error`, not a silent drop.
46+
- 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.
47+
- Each node has exactly one outgoing edge. Branching is via conditional edges, not multiple statics.
48+
- `END` is a distinct sentinel object, not a reserved string. Use the exported `END` constant.

README.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,62 @@
11
# openarmature-python
2+
3+
Python reference implementation of [OpenArmature](https://github.com/LunarCommand/openarmature-spec) — a workflow framework for LLM pipelines and tool-calling agents.
4+
5+
**Status:** alpha. The graph engine module is implemented against spec v0.1.1; the other modules in the charter are not yet built.
6+
7+
## Install
8+
9+
Not yet on PyPI. For local use, install from a checkout:
10+
11+
```bash
12+
uv add --editable /path/to/openarmature-python
13+
```
14+
15+
## Quick example
16+
17+
```python
18+
import asyncio
19+
from typing import Annotated
20+
21+
from pydantic import Field
22+
23+
from openarmature.graph import END, GraphBuilder, State, append
24+
25+
26+
class S(State):
27+
log: Annotated[list[str], append] = Field(default_factory=list)
28+
29+
30+
async def hello(_state: S) -> dict[str, list[str]]:
31+
return {"log": ["hello"]}
32+
33+
34+
async def world(_state: S) -> dict[str, list[str]]:
35+
return {"log": ["world"]}
36+
37+
38+
graph = (
39+
GraphBuilder(S)
40+
.add_node("hello", hello)
41+
.add_node("world", world)
42+
.add_edge("hello", "world")
43+
.add_edge("world", END)
44+
.set_entry("hello")
45+
.compile()
46+
)
47+
48+
final = asyncio.run(graph.invoke(S()))
49+
print(final.log) # ['hello', 'world']
50+
```
51+
52+
See `tests/conformance/` for fixtures covering conditional routing, subgraph composition, and the canonical compile- and runtime-error categories.
53+
54+
## Spec
55+
56+
The spec lives in [`openarmature-spec`](https://github.com/LunarCommand/openarmature-spec) and is pinned here as a git submodule. Conformance fixtures from the spec are exercised by `tests/conformance/`.
57+
58+
The pinned spec version is recorded in `tool.openarmature.spec_version` (in `pyproject.toml`) and exposed as `openarmature.__spec_version__`.
59+
60+
## License
61+
62+
Apache-2.0.

0 commit comments

Comments
 (0)