Governance¶
This document describes how the OpenArmature specification is managed: how specs are organized, how changes are proposed and accepted, how versions are tracked, and how multiple language implementations are kept in sync.
Scope of this repository¶
This repository (openarmature-spec) holds the language-agnostic specification for OpenArmature. It does not
contain implementation code. Implementations live in separate repositories:
openarmature-python— reference Python implementationopenarmature-typescript— reference TypeScript implementation (planned; not yet started)
Both implementations target the specs in this repo. Behavioral conformance is verified by the conformance test suite, also in this repo as language-agnostic test fixtures.
The approach follows the pattern used by mature multi-language projects (OpenTelemetry, Language Server Protocol, JSON-RPC): a separate spec repo with markdown organized by capability, SemVer-versioned, with a conformance test suite as the source of truth for behavioral correctness.
Repository structure¶
openarmature-spec/
├── docs/
│ └── openarmature.md # Project charter — thesis, architecture, roadmap
├── spec/
│ ├── graph-engine/
│ │ ├── spec.md # Canonical spec for the capability
│ │ └── conformance/ # Language-agnostic test fixtures
│ ├── pipeline-utilities/
│ │ ├── spec.md
│ │ └── conformance/
│ ├── llm-provider/
│ │ ├── spec.md
│ │ └── conformance/
│ └── … # Additional capabilities as the spec grows
├── proposals/
│ ├── 0001-graph-engine-foundation.md
│ ├── 0002-…
│ └── … # Numbered RFC-style proposals
├── CHANGELOG.md # SemVer-tracked spec version history
├── GOVERNANCE.md # This document
└── README.md # Project intro
Charter vs spec vs proposal — three roles, three locations:
- Charter (
docs/openarmature.md) — living vision document. The thesis, architecture overview, design principles, and roadmap. Updated as the project evolves. Not immutable. - Spec (
spec/<capability>/spec.md) — canonical, current behavioral specification for a capability. Updated only through accepted proposals. Versioned via SemVer. - Proposal (
proposals/NNNN-*.md) — focused decision document for a specific change. Reviewed via PR, immutable once Accepted.
Proposal lifecycle¶
Format¶
Proposals are numbered sequentially: NNNN-short-kebab-title.md (zero-padded to 4 digits). They follow this template:
# NNNN: <Title>
- **Status:** Draft | Accepted | Withdrawn | Superseded
- **Author:** <name>
- **Created:** YYYY-MM-DD
- **Accepted:** YYYY-MM-DD (filled in on acceptance)
- **Targets:** spec/<capability>/spec.md (creates | modifies §X.Y | removes …)
- **Related:** NNNN, NNNN
- **Supersedes:** NNNN (if applicable)
## Summary
2–3 sentences. What is being proposed.
## Motivation
Why this change is needed. Reference the charter or earlier proposals if relevant.
## Detailed design
The actual proposed spec text, or a precise diff against the existing spec.
## Conformance test impact
Which fixtures need to be added, changed, or removed. New behaviors require new tests.
## Alternatives considered
Other approaches and why they were rejected. At minimum, "do nothing" should be considered.
## Open questions
Anything unresolved at the time of writing.
Lifecycle¶
- Draft. Author opens a PR adding the proposal under
proposals/. Status: Draft. - Review. Discussion happens on the PR. Proposal text is iterated.
- Accept. Maintainer merges the PR with
Status: AcceptedandAccepted: YYYY-MM-DDfilled in. The proposal text becomes immutable from this point — further changes happen via new proposals. - Implement spec change. A follow-up PR (or the same PR if small) updates the relevant
spec/<capability>/spec.mdandconformance/directory to reflect the accepted design. - Version bump.
CHANGELOG.mdis updated with the new spec version and a link to the proposal(s) that drove the change.
A proposal may also end as Withdrawn (author abandoned) or Superseded (replaced by a later proposal that references it).
When a proposal is required¶
Required for:
- Adding or removing a capability
- Adding, removing, or changing the behavior of a public type, function, or interface
- Changing conformance test expectations in a way that any implementation could fail
Not required for:
- Typo fixes, formatting, broken links
- Clarifications that do not change behavior (PATCH version bump, no proposal needed)
- Changes to charter, this governance doc, or README
Spec versioning¶
Spec changes follow SemVer at the whole-spec level (not per-capability):
- MAJOR — backwards-incompatible behavioral or interface change
- MINOR — backwards-compatible addition (new capability, new optional field, new behavior that does not break existing fixtures)
- PATCH — clarification, typo, or non-behavioral change
Each change is recorded in CHANGELOG.md with the version, date, summary, and links to the driving proposal(s).
Pre-1.0 versions (0.x.y) follow the same SemVer structure but with the explicit understanding that the spec is still
stabilizing and breaking changes may occur in MINOR bumps.
Multi-language consistency¶
Inspired by OpenTelemetry's library guidelines, with a smaller scope (two languages, not many).
-
Two-language prototype rule. Any new capability spec should be prototyped in both Python and TypeScript before the proposal is Accepted. This catches idiom mismatches early. (OpenTelemetry uses three categories — typed-OO + dynamic + structural — but Python and TypeScript cover dynamic + typed-functional well enough for our scope.)
-
Behavioral spec, not API-shape spec. The spec describes what happens, not the exact syntax. Each language uses its idiomatic API. Python decorators may correspond to TypeScript middleware functions; Python context managers may correspond to TypeScript
usingblocks. APIs MAY differ in syntactic shape; behavior MUST match conformance tests. -
Drift policy. If an implementation discovers a needed feature not in the spec, it does NOT add it unilaterally. The implementation must file a proposal first and wait for acceptance before shipping the feature. (This is the policy LangChain didn't have, which is why their Python and TypeScript APIs drift visibly enough that they publish a "differences page.")
-
Spec version declaration. Each implementation declares which spec version it targets in its package metadata (e.g., Python
pyproject.toml:openarmature_spec_version = "0.3.1"). The implementation MUST pass the conformance test suite for that version. -
Skip-ahead implementation. When a follow-on proposal supersedes parts of an accepted-but-unimplemented predecessor, implementations MAY skip the intermediate spec version and target the later one directly. Pre-1.0 SemVer permits breaking changes between MINOR versions, so this situation arises naturally when spec design iterates faster than implementation. The intermediate version remains in the spec history (CHANGELOG entry, accepted proposal text) for design documentation; no implementation effort is wasted on superseded contracts. Implementations that DO want to ship the intermediate version (e.g., for incremental release) MAY do so, but are not required to.
External-dependency adoption¶
OpenArmature normatively references several external specifications and APIs (OpenTelemetry semantic conventions, LLM provider wire formats, IETF RFCs, vendor SDKs). The following rules govern how OA adopts upstream changes.
Stable-only adoption. OA spec normatively adopts upstream attribute names, wire shapes, and protocol details ONLY when the upstream marks them Stable (or the equivalent maturity marker per the upstream's own governance — Released for IETF RFCs, Stable for OpenTelemetry semantic conventions, non-pre-release semver tags for SDKs, etc.).
Upstream attributes or shapes in Development, Experimental, Beta, or other pre-stable status MUST be mirrored to the
openarmature.* namespace until they reach upstream Stable. A follow-up OA proposal then migrates the normative
shape to the upstream name once it stabilizes.
Rationale. Spec text is durable; conformance fixtures track the wire shapes the spec mandates. Pre-stable upstream attributes can be renamed or removed by the upstream; pinning OA to them creates an implicit dependency on volatile state and forces every OA implementation to chase the upstream's churn.
Implementation constraint. OA implementations (e.g., openarmature-python, openarmature-typescript) MUST emit
the OA-namespace attribute names (not the upstream pre-stable names) when this spec mandates OA-namespace mirroring.
Jumping ahead to upstream attribute names before OA's normative shape stabilizes breaks cross-impl behavioral
consistency, which is the primary value of the multi-language consistency rules above.
Tracking. The compatibility tracking page (docs/compatibility.md) is the operational artifact recording pinned
versions, last-verified dates, and per-dependency notes for every external dependency OA references. The page is
freely editable per the carve-out below (small re-verification updates do not require a proposal). Normative spec
changes that flow from a re-verification (e.g., adopting a newly-Stable upstream attribute) DO require a proposal
per the standard discipline.
De-facto interoperability standard (narrow carve-out). Where an upstream attribute set is the de-facto
cross-ecosystem interoperability standard for its domain — recognized by the broad installed base of tools that
consume the signal — OA MAY adopt the recognized core names directly even while the upstream marks them
Development, when mirroring those names to openarmature.* would defeat the interoperability the names exist to
provide. This carve-out is currently scoped to the OpenTelemetry GenAI semantic conventions (gen_ai.*): every
GenAI-aware observability backend keys on the gen_ai.* names, so an openarmature.* mirror of the core attributes
would render OA's spans unrecognizable to precisely the tools the semconv targets. Newer or peripheral attributes
within the same convention that the installed base does not broadly recognize are still mirrored to openarmature.*
per the stable-only rule above, until they are Stable or demonstrably ubiquitous. Each use of this carve-out MUST be
recorded in docs/compatibility.md with the adopted names, their upstream status, and the interoperability
rationale. The carve-out does NOT extend to other dependencies without a proposal that makes the same
de-facto-standard showing.
Post-adoption upstream change (retention). Once OA has adopted an upstream name — whether at upstream Stable or
under the de-facto-standard carve-out above — a later upstream rename, removal, restructure, or status change does
NOT automatically change what OA emits. OA retains the adopted name, keeping its emitted surface stable for the
consumers and conformance fixtures that depend on it, and migrates to a successor name only through a deliberate
follow-on proposal, when the successor is itself worth adopting (it reaches Stable, or the ecosystem has demonstrably
moved to it). docs/compatibility.md records the divergence — the adopted name, the upstream successor, and that
migration is deferred. Rationale: spec text and conformance fixtures are durable; chasing upstream churn —
especially within a pre-stable convention that renames freely — would thrash every implementation for no consumer
benefit, which is the same volatility the stable-only rule guards against.
Conformance tests¶
Conformance tests live alongside their specs at spec/<capability>/conformance/ and are language-agnostic.
Format. Each test is a fixture pair plus a description:
spec/graph-engine/conformance/
├── 001-static-edge-flow.yaml
├── 001-static-edge-flow.md # description of what this test verifies
├── 002-conditional-edge-routing.yaml
├── 002-conditional-edge-routing.md
└── …
The YAML fixtures contain inputs (graph definition, initial state, sequence of events) and expected outputs (final state, observed call order, errors). The markdown describes intent and edge-case coverage.
Adapter responsibility. Each language implementation provides a thin adapter that loads the YAML fixtures and runs
them through its native test runner (Python: pytest; TypeScript: vitest). The adapter is implementation-private;
the fixtures are spec-public.
Test additions require proposals. New conformance tests that any implementation could fail are a behavioral spec change and require a proposal. Test additions that only verify already-specified behavior (regression coverage, clarification fixtures) do not.
Normative reference. The conformance-adapter capability spec (under spec/conformance-adapter/) is the
authoritative reference for the fixture YAML schema, the full directive vocabulary, the harness primitives implementations
MUST provide, and the assertion shapes adapters MUST honor. This section is the high-level overview; the capability spec
is where adapter authors look to know what each directive means at runtime. New proposals that add fixture directives
extend that capability spec's §5 Directive vocabulary the same way they extend any other capability spec. A readable
end-to-end explainer with worked examples ships at docs/conformance.md.
Decision making¶
Currently single-maintainer (Chris Colinsky). The maintainer accepts or rejects proposals after PR review.
This section will be updated as the project grows to describe a contributor model, working groups, or a steering committee — whichever fits when the contributor base warrants it. The OpenTelemetry and Rust governance models are likely templates.
Out of scope for this repo¶
- Implementation code (lives in
openarmature-pythonandopenarmature-typescript) - Performance benchmarks (each implementation owns its own benchmarking)
- User-facing tutorials and how-to docs (live with each implementation)
- Provider-specific integration code (sibling-package responsibility per the architecture in the charter)