Atom Software Architecture Document (SAD)
System architecture: Atom Software Architecture Document (SAD)
1. Context¶
1.1 System Purpose¶
Atom is the identity and publishing foundation (L1) of the Axios decentralized publishing stack. It answers exactly one question authoritatively: what is this thing, who owns it, and which immutable bytes does a given version resolve to — without a central registry and without trusting the publisher.
Positioning: the atom is the composition-unit layer — it sits above language package managers, not beside them. A cargo crate can be an atom; cargo manages the Rust dependency graph interior to one build action, while the atom carries the system-level intent — the full composite (package, environment, or system) with its dependency closure determined by the signed lock. There is one atom implementation; per-ecosystem handling (version dialects, fetch adapters, manifest readers) consists of internal plugins of that implementation, never co-equal per-ecosystem protocols. What an atom is at this layer — the composite duality, the metadata partition law, the signature-anchoring law, the reproducibility contract — is formalized in the Atom Model; what any storage backend must provide to host the plane is the Atom Backend Contract, with the git storage format as its reference instantiation. This SAD defers to both on semantics and owns the architecture.
Surety of source: an atom wrapping upstream sources derives its provenance from the curating repository — the anchor, claim, and publish chain of the set that packaged it — not from upstream's own release artifacts; upstream's bytes are pinned inside that signed intent, they do not sign it.
Atom owns:
- Identity — the
AtomId = (anchor, label)pair: a stable, algorithm-free, permanent name for an atom across all its versions and ownership changes. - Ownership — the signed claim→publish protocol (via Coz) that binds an owner to an identity and makes every published atom cryptographically accountable.
- Content-addressed storage — append-only publish/claim history over git objects, plus a digest-addressed store for cross-source colocation.
- Discovery — object-free version enumeration over advertised refs, and the set→mirrors indirection that makes resolution decentralized.
Atom does not own: evaluation or build (L3, eos), dependency resolution or the lock file as a whole (L4, ion), or key management and signing primitives (Cyphr/Coz, below L1). Atom defines the identity contract those layers consume; it never consumes them.
1.2 External Actors¶
1.3 System Boundaries¶
| Boundary | Inside Atom | Outside Atom |
| Identity | AtomId = (anchor, label); anchor = czd(charter₀), the founding charter's coz digest |
Key material, signature primitives (Coz/Cyphr) |
| Ownership | claim/publish protocol; claim/publish chains; the owner→identity binding | Owner identity systems (Coz tmb, Cyphr PR) — Owner is opaque |
| Storage | git-object encoding; registry + store ref layout; ingest | Build execution, artifact store (L3) |
| Discovery | object-free ref advertisement; set→mirrors indirection | Version semantics (VersionScheme is a trait; its per-ecosystem dialects are internal plugins above L1, §1.1) |
| Lock | the atom-required lock contribution ([lock-entry-sufficient]) |
The lock file as a whole, resolution, plugin/non-atom deps (L4) |
1.4 Layer Discipline¶
Atom is the bottom layer. atom-* crates MUST NOT depend on eos-* or ion-*.
Ion (L4) and Eos (L3) depend on atom; the reverse is forbidden
(layer-boundaries.md [boundary-downward-only]). The L3/L4 export surface is
AtomContent (a forgetful functor over AtomStore that drops ingest/contains);
consumers never see store-mutating operations.
1.5 Store / Registry Taxonomy¶
Registry and store are two ref namespaces over one git object database, with deliberately different semantics. They never collide; a single repository MAY serve both namespaces, but they are not conflated.
| AtomRegistry | AtomStore | |
| Purpose | resolution + acquisition by name | content-addressed colocation |
| Keyed by | label / version (human-readable) |
blake3(publish_czd) (digest) |
| Ref prefix | refs/atom/{pub,claims/pub,src}/… |
refs/atom/{d,dev,claims/d}/… |
| Mutability | append-only (tag/claim chains) | accumulating; digest refs immutable |
| Discovery | object-free ls-refs enumeration |
by digest only (no enumeration) |
Registries are what make decentralized bulk resolution possible (enumerate a project's atoms in one object-free query). Stores exist to hold and fetch atoms by digest across sources. Not every store is a registry (a bare mirror serves digests without resolution), and there is no requirement that a registry also be a store — the lock acquires content via the name namespace and reads everything else from the atom's self-describing git object (§6.7).
2. Container View¶
2.1 AtomRegistry¶
The append-only, name-keyed publishing surface. claim() stakes ownership of an
(anchor, label); publish() records a new signed publish tag at
refs/atom/pub/{label}/{version}. Implements AtomSource for object-free discovery.
Within a single registry, label is unique ([registry-ref-label-unique]).
2.2 AtomStore¶
The digest-keyed colocation surface. Atoms ingested from any number of sources/forks
coexist, keyed by blake3(publish_czd) — cryptographically distinct publishes
occupy distinct refs by construction, so colocation needs no coordination. Implements
AtomContent (and AtomStore's ingest/contains). A local store doubles as the
resolution cache: an atom fetched once is content-addressed for reuse.
2.3 AtomSource (Git Backend)¶
atom-git implements AtomContent/AtomStore over a git repository: it reads atom
commits, walks publish tag chains and claim chains, and verifies the anchor against
the set's founding charter (Anchor := czd(charter₀)). The git object DB is the
substrate; the registry/store refs are views over it. The obligations this
backend discharges — and the ones still open against it — are enumerated
in the Atom Backend Contract's
git-instantiation table (its Appendix A); a non-git backend evaluates
itself against that contract, never against this SAD.
2.4 Mirrors¶
A set (atoms sharing an anchor) carries a list of interchangeable mirror
registries. Repo identity is the anchor, not a URL; mirrors are interchangeable
because cross-mirror anchor/digest consistency is the tamper guard
([set-anchor-bijection], [atom-version-identity]). Mirrors are registries
(name-keyed); a consumer never resolves a czd directly from a mirror — it resolves by
name and computes/reads digests locally.
3. Component View¶
3.1 atom-core — Trait Surface¶
Defines the four traits and their algebraic relationships (atom-core/src/lib.rs):
AtomSource(:139) — discovery/metadata observation: resolve an atom's availability and metadata.AtomContent(:205) — extendsAtomSourcewith content access. The forgetful mapF_content → F_sourcedrops the content observer; this is the L3/L4 export surface (publishing-stack-layers.md §2.1a).AtomRegistry(:231) — extendsAtomSourcewith the signedclaim()/publish()operations (append-only).AtomStore(:271) — extendsAtomContentwithingest(dyn AtomContent)andcontains().ingesttakesAtomContent, notAtomSource— a store ingests content, not merely discovery handles.
3.2 atom-id — Identity Primitives¶
Anchor, Label, and AtomId = (anchor, label). The AtomId is the pair
itself — not a hash of it. No digest type is exported for identity (see §6.1).
3.3 atom-uri — URI Parsing¶
Parses atom: URIs into the coordinates (registry/set, label, version|revision).
The URI is a locator, not the identity ([uri-not-metadata]).
3.4 atom-git — Git Bridge¶
Implements AtomContent/AtomStore over git objects per git-storage-format.md:
charter-based anchor verification (Anchor := czd(charter₀)), atom-commit
snapshots, publish tag chains, claim chains, and the registry/store ref layouts.
4. Core Lifecycles¶
4.1 Claim and Publish¶
Publishing is gated on ownership: an unclaimed atom MUST NOT be published, so every
published atom has a coherent cryptographic owner. Ordering is enforced by data flow
(claim() returns a czd that publish() requires) and by temporal vector
(publish.now > claim.now).
4.2 Resolve and Acquire (name-anchored)¶
Acquisition is name-anchored: registries are name-keyed, and a published version
is the moving tip of an append-only publish tag chain peeling to an immutable atom
commit. The lock pins publish_czd; resolution locates that pin within the chain.
Content reproducibility is guaranteed by the chain-invariant core
(label, version, dig, src, path) ([tag-chain-semantic-immutable]): the chain may
grow (appended signing/meta), but the bytes a version resolves to cannot change.
4.3 Ingest¶
store.ingest(source) pulls an atom's objects (commit, tag chain, claim) into a
store, keyed by blake3(publish_czd). Ingest preserves identity and content exactly
([ingest-preserves-identity], [coz-bit-perfect]): resolve(store) ⊇ resolve(source) for the ingested atom ([store-accumulates]).
5. State Machine Models¶
5.1 Publish Tag Chain¶
5.2 Claim Chain¶
6. Cross-Cutting Concerns and System Invariants¶
The plane framing for everything below is the
Atom Model, cited rather than restated:
identity names the composite (the atom is its intent reification;
the composition its artifact reification — atom-model §2); every
signature offered across a trust boundary is anchored to an atom,
and publication is impossible unsigned, which is what makes every
published object trust-decidable (the anchoring law, atom-model §5);
publish-time metadata and post-build facts are partitioned by law, not
taste (atom-model §4 — the law §5.1's chain-variable class and §8.6's
carve-out obligation instantiate); and a publish carries a declared
reproducibility mode whose violation semantics are defined
(atom-model §6; the payload field is a pending atom-transactions.md
amendment, tracked in atom-model §8).
6.1 Identity is the Abstract Pair¶
Invariant [identity-content-addressed]: an atom's identity (AtomId) MUST be
determined solely by the pair (anchor, label), and MUST NOT depend on any key,
signature, signed message, or hash algorithm. The AtomId is not a hash of
(anchor, label) — it is the pair. ("Content-addressed" here means the anchor is
a content hash and identity is permanent; it does not mean the id is a digest.)
There is no AtomDigest of identity and no store-chosen algorithm agility at this
layer. Invariant [identity-stability]: the AtomId MUST NOT change across
versions, ownership transfers, or key rotations.
6.2 The Anchor¶
(Amended 2026-07-08 — the charter.) The anchor is the coz digest of the
atom-set's founding charter transaction: Anchor := czd(charter₀)
(atom-transactions.md [charter-anchor]) — backend-agnostic, since a charter
is a coz object regardless of backend. This replaces the earlier
genesis-commit derivation; the genesis commit is not lost — the charter's
src transitively pins it (a revision hash commits to its entire ancestry) —
but it no longer is the anchor. The anchor is: immutable
([anchor-immutable] — successor charters chain without changing it),
content-addressed over a signed, owned payload
([anchor-content-addressed]), unique (distinct charters yield distinct
anchors; two charters over the same history are two deliberately distinct
sets, [charter-fork-distinction]), and resolvable — a consumer locates
and verifies the founding charter from the source without trusting the
publisher; selecting among candidate charters is the consumer's recorded
trust decision ([anchor-resolvable], supersedes [anchor-discoverable]).
Git hash agility is handled by the charter, not by silence: a SHA-256 re-hash
rewrites history, so continuity across it is an explicit successor charter
([anchor-hash-agile], [charter-succession]); absent succession, the
re-hashed repository is a distinct atom-set.
6.3 Ownership: Claim Before Publish¶
Invariant [no-unclaimed-publish]: a publish MUST NOT exist for an AtomId with
no verifiable claim. The claim (a signed CozMessage) binds an opaque Owner to the
identity; [owner-abstract] keeps the owner framework-agnostic (Coz tmb, Cyphr
PR). The publish→claim binding ([publish-chains-claim],
[publish-claim-coherence]) is the sole mechanism tying a publish to its owner.
6.4 Claim Chains and Revocation (consolidated)¶
Revocation and re-ownership are fully specified across the storage and sourcing specs and are consolidated here:
- Claims form an append-only chain: a replacement claim's commit is parented to
the previous, and
refs/atom/claims/pub/{label}advances to the tip ([single-active-claim-registry],[claim-replacement-transition]). Reclaiming with new keys is the normal key-rotation path; existing publishes remain valid under the claim they referenced. - Revocation is carried in publish/claim tag metadata —
meta.supersedes: "update" | "revoke",meta.superseded-by— and carries cryptographic assurance precisely because the new claim chains to the previous (git-storage-format.md§extensible-meta). - Evaluation is verify-time at the chain tip: a resolver walks the claim chain;
the tip is the active claim. Two mirrors advertising the same atom@version with the
same
digbut differentczdare reconciled by chain ancestry — newest-in-chain wins; genuinely distinct ownership is a conflict and is rejected ([czd-divergence-handling]). Revocation is therefore an online check at the claim-chain tip, not a lock field.
6.5 The Lock Contribution (2-value)¶
The atom-required lock entry ([lock-entry-sufficient], [lock-capture]) is keyed
by AtomId = (set, label) and carries exactly two values: the resolved version and
the bare publish_czd (original algorithm — the lock represents the actual
cryptographic security the signature covers). set resolves to mirrors via a shared
[sets] → mirrors table.
- No hashed
id— the(set, label)pair is the identity and the map key. - No
rev— the atom commit is peelable from thepublish_czd's tag chain. digis not stored — it lives in the signed publish payload (the czd-pinned source of truth); on acquisition the peeled content-addressed sha MUST equalpayload.dig, or there is tampering.
blake3 wraps publish_czd only as the store-key reduction (§6.6), never in the
lock.
6.6 Store Keying¶
The store is keyed flat by blake3(publish_czd) — a uniform single-algorithm
keyspace reducing the multihash czd for multi-signer colocation. There is no
{version} delimiter (version lives inside the signed publish; git dedups content by
OID; the registry handles enumeration). Distinct publishes ⇒ distinct keys ⇒
colocation without coordination ([store-claim-disambiguation], recast off
claim_czd).
6.7 The Export Contract (self-describing git object)¶
The atom's git object is self-describing: the publish tag carries the signed
CozMessage (version, dig, src, path, and claim → owner) and peels to the
atom commit (the content). Consumers read behind the publish_czd, not from
copied lock fields:
- Eos reads what it needs (
dig, the content tree, version) directly from the atom's git object viaAtomContent. - Ion may derive wire-handoff fields from that same object at resolution time.
Nothing about the atom is copied into the lock beyond the (set, label) → {version, publish_czd} pointer. The L3/L4 boundary is AtomContent (the forgetful
functor dropping store-mutating observers). Note: ion-eos-contract.md
[handoff-atom-fields] carries only the minimal pointer (set, label, version, publish_czd); eos reads rev/dig/content from the self-describing git object.
(Earlier drafts mandated eos receive rev/id — that over-specification has
been realigned.)
6.8 Discovery is Object-Free¶
Version discovery is an ls-refs advertisement over refs/atom/pub/{label}/{version}
returning refname→OID with no object download — the standard git protocol-v2
primitive. This is spec-mandated; axios's own implementation is a build task (the
PoC's get_atoms proves the pattern). See Appendix D.
7. Wire and Storage Formats¶
| Concern | Governing spec |
| Git object encoding (atom commits, publish/claim tags, ref layout) | git-storage-format.md |
| Claim/publish protocol, payloads, identity, verification | atom-transactions.md |
| Sourcing, mirror sets, the lock contribution | atom-sourcing.md |
atom: URI grammar |
aliased-url-resolution.md |
Signing, CozMessage, czd |
Coz (below L1) |
8. Failure Modes¶
| # | Failure | Behavior |
| 8.1 | Claim name collision (label taken in registry) | claim rejected ([registry-ref-label-unique]) |
| 8.2 | Publish without/with-revoked claim | publish invalid ([no-unclaimed-publish], verify-time tip check) |
| 8.3 | Peeled content sha ≠ payload.dig | tamper/funny-business — reject the fetched atom |
| 8.4 | Mirror divergence (same atom@version, different dig) | conflict, reject ([no-conflicting-digest]) |
| 8.5 | Distinct-ownership czd divergence | reject unless same claim chain ([czd-divergence-handling]) |
| 8.6 | Moved publish-tag tip (metadata appended) | non-fatal: warn "metadata updated / key rotated" + optional czd bump, iff the new tag's VALUE for a policy-relevant overwrite-class field (signing identity — tmb, key, alg — or mode; atom-transactions.md [amendment-field-classification]) DIFFERS from the value established by the immediately preceding tag in the chain. This is a value-change check, not a field-presence check: every signed tag necessarily sets tmb and now (both overwrite-class), so a presence-based trigger would fire on every tip move, making the routine case unreachable. A routine re-sign that reuses the same key and mode is not a signing-identity or mode change even though tmb/now are necessarily re-set. now and meta value-changes are never themselves policy-relevant (every tag necessarily has a distinct now; a meta edit such as min-compatible is not an ownership signal) and never trigger this warning regardless of change. A tip move that changes no policy-relevant overwrite field's value — whether because it carries only append-class (fact) entries, or because it merely re-asserts the same signing identity and mode — is routine and MUST NOT trip this warning: ownership-relevant and routine tip moves are distinguished mechanically by whether a policy-relevant overwrite field's value changed (atom-model §4; atom-transactions.md [amendment-field-classification], [fact-kind-table]) |
9. Known Gaps and Future Explorations¶
| # | Gap | Notes |
| 1 | Object-free discovery unbuilt in axios | spec-mandated; PoC get_atoms proves the pattern |
| 2 | FsSource sentinel anchor value/encoding unconstrained | local atoms; needs a protocol-level constant |
| 3 | rev peel mechanism (locate commit from publish_czd; GC of an old chain tip) |
specify the failure mode when a serving mirror has GC'd |
| 4 | Cross-ecosystem VersionScheme adapters |
trait surface defined; concrete adapters are internal plugins of the one implementation, registered above L1 (one meta-PM, many version dialects) |
| 5 | Signed metadata append as the substrate's fact-publication channel (build records, interface manifests — HTC/L2, per ADR-0005 §Open Items, htc-sad.md §6.10) | Closed at the spec level, 2026-07-14: atom-model §4 gives the partition law; the mechanism is now defined — atom-transactions.md [amendment-field-classification] (identity/overwrite/append field classification), [fact-kind-table] (the concrete fact-kind list, derived/asserted, with authorization tier), and [fact-claim-owner-gated] (the builder≠claim-owner signer-authorization policy for claim-owner-gated facts — lifecycle markers plus runtime-requires — riding trust-model.md's existing SignerRole/[trust-owner-selector] machinery). The Rust implementation of this mechanism is separate, not-yet-landed work. |
10. Scope Boundaries¶
Out of scope for the atom layer:
- Build/evaluation (L3/eos) and the artifact store.
- Dependency resolution, the lock file as a whole, plugin/non-atom deps (L4/ion).
- Key management and signing primitives (Cyphr/Coz) —
Ownerandczdare opaque to atom. - Concrete version semantics —
VersionSchemeis a trait; its per-ecosystem dialects are internal plugins of the single implementation, above L1 (§1.1).
Appendix A: Terminology¶
| Term | Definition |
| Composite | The genus an atom reifies as intent: a package, environment, or system with its determined closure (atom-model §2) |
| Mode | The publish-carried reproducibility declaration, reproducible | witnessed (atom-model §6) |
| Anchor | czd(charter₀) — the founding charter's coz digest; immutable atom-set identity |
| AtomId | The abstract pair (anchor, label) — the identity, not a hash |
| Atom-set | Atoms sharing a common anchor |
| Label | Human-readable atom name (UAX #31) |
| OwnerRef | {kind, value} — a kind-tagged opaque identity digest (Coz tmb, Cyphr PR); kind names the identity framework (single-key implemented; hierarchical/rooted-identity reserved), value stays opaque to the protocol regardless of kind |
| Owner (claim) | ClaimPayload.owner — a single OwnerRef: the one identity accountable for a label |
| Owner (charter) | CharterPayload.owner — a non-empty SET of OwnerRefs: the team recognized under this anchor, flat and equally authoritative |
| Claim | Signed CozMessage binding an OwnerRef → (anchor, label) |
| Publish | Signed CozMessage recording a version; references a claim czd |
| czd | Coz message digest (multihash); publish_czd, claim_czd |
| dig | Hash of the reproducible atom snapshot (in the publish payload) |
| Revision (rev) | A specific commit in source history (peelable from the tag chain) |
| Version | Abstract version via VersionScheme (ecosystem-agnostic) |
Appendix B: Crate Map¶
| Layer | Crate | Kind | Purpose |
| L1 | atom-core |
Contract | Traits: AtomSource, AtomContent, AtomRegistry, AtomStore |
| L1 | atom-id |
Contract | Identity primitives: Anchor, Label, AtomId |
| L1 | atom-uri |
Contract | atom: URI parsing |
| L1 | atom-git |
Implementation | AtomContent/AtomStore over git objects |
Appendix C: Specification Cross-Reference¶
| SAD Section | Governing Specification |
| §4.1 Claim/Publish | atom-transactions.md §Transitions |
| §4.2 Resolve/Acquire | atom-sourcing.md, git-storage-format.md |
| §4.3 Ingest | atom-transactions.md [ingest-preserves-identity] |
| §5.1 Publish Tag Chain | git-storage-format.md [tag-chain-immutable], [tag-chain-semantic-immutable] |
| §5.2 Claim Chain | git-storage-format.md [single-active-claim-registry], [claim-replacement-transition] |
| §6 plane semantics | atom-model.md (composite duality §2, partition law §4, anchoring law §5, reproducibility contract §6) |
| §2.3 backend duties | atom-backend-contract.md (git instantiation: its Appendix A) |
| §6.1 Identity | atom-transactions.md [identity-content-addressed], [identity-stability] |
| §6.2 Anchor | atom-transactions.md [anchor-*] |
| §6.3 Ownership | atom-transactions.md [no-unclaimed-publish], [publish-claim-coherence] |
| §6.4 Revocation | git-storage-format.md §meta; atom-sourcing.md [czd-divergence-handling] |
| §6.5 Lock | atom-sourcing.md [lock-entry-sufficient], [lock-capture] |
| §6.6 Store Keying | git-storage-format.md store ref layout |
| §6.7 Export Contract | publishing-stack-layers.md §2.1a; ion-eos-contract.md (Appendix D) |
| §6.8 Discovery | atom-sourcing.md; git-storage-format.md registry refs |
Appendix D: Known Specification Drift¶
The keystone realignment — pair-only AtomId (no
AtomDigest/[digest-algorithm-agile]), the 2-value name-anchored lock, the flat
blake3(publish_czd) store, and name-anchored acquisition — has been applied across
atom-transactions.md, atom-sourcing.md, and git-storage-format.md, which are
aligned to this SAD. The 2026-07-08 charter amendment (Anchor := czd(charter₀),
atom-transactions.md [charter-anchor]) has likewise been propagated across those
specifications and this SAD (§6.2). One deliberate, explicitly marked gap remains:
the git backend's storage encoding and ref layout for charter transactions is not
yet specified (git-storage-format.md Open Questions #6) — tracked as
atom-milestone design work, not silent drift. (The L4 consequences — the ion lock
cross-references and the eos handoff — are tracked by ion-sad.md.)
The 2026-07-12 plane formalization (atom-model.md, atom-backend-contract.md)
obligates a set of spec amendments that are registered, not yet landed:
the reproducibility-mode publish field and fact-append items against
atom-transactions.md (atom-model §8), and the priority publish-CAS
SHOULD→MUST plus the seam/ancestry/immutability statements against
git-storage-format.md (backend contract Appendix B). Until those land,
the manifests in the two new documents are the authoritative drift record
for their items — deliberate, enumerated, not silent.
The 2026-07-14 owner-set amendment (atom-transactions.md
[owner-kind-required], [claim-owner-single], [charter-owner-set])
generalizes CharterPayload.owner from a single opaque digest to a
non-empty set of kind-tagged owner-references, and adds the
OwnerKind discriminator required to interpret any owner-reference's
value; ClaimPayload.owner stays a single owner-reference. This has
been propagated across atom-transactions.md and trust-model.md
([trust-owner-selector]'s claim/charter disambiguation) and into
this SAD's terminology (Appendix A). One deliberate, explicitly marked
gap remains: docs/specs/tla/AtomCharter.tla still encodes
single-owner charter semantics and has not been reworked for
set-valued ownership — atom-transactions.md's Verification section
names precisely which machine (TLC) rows this affects — tracked as
follow-on design work, not silent drift.
Appendix E: Stale Documentation¶
| Document | Issue | Corrected In |
alloy/atom_structure.als |
identity_content_addressed assertion name could be misread as hash-based |
Clarifying comment added; name kept to match the retained [identity-content-addressed] spec tag + evaluator linkage; body already correct |
tla/AtomTransactions.tla |
none — comment accurately reads "deterministic function of (anchor,label)" | No change needed; body and comment already correct |