Architecture
Current status: the local/mock validator runtime is the strongest implemented and tested surface. Federation between enterprise clusters is merged into the validator runtime and has passed a local two-cluster harness in mock mode; it is not deployed. The SDK, chain-backed settlement, a deployed enterprise registry, and EDS delivery integration remain experimental or target-state unless a linked evidence record says otherwise; the AEM 6.5 LTS read-only mount has one on AEM 6.5 LTS Integration.
Oak Chain is a distributed content repository that bridges Ethereum's economic security with Oak's enterprise content model.
What Oak Chain Is
- A headless validator system built on Oak internals.
- A consensus-driven content repository with wallet-scoped ownership.
- An API-first platform: each validator serves its own HTTP routes, and an edge worker publishes the read contract for remote clients. Route lists live in API.
What Oak Chain Is Not
- Not AEM.
- Not run through the Sling or Felix web console or JMX. The standalone validator has no OSGi runtime; operators use APIs, scripts and logs.
System View at a Glance
One diagram covering experience surface, consensus truth, settlement and addressing, and runtime control plane. Start here for the runtime topology; the rest of this page goes deeper into each plane.
Layers
Oak (storage)
Keeps the content tree as immutable segments in TAR files. Each validator applies every ordered write to its own store.
Aeron Cluster (consensus)
Elects a leader and orders every write within one cluster. Roles, the write path and failover timing: Consensus Model.
Ethereum (settlement)
Chain-backed modes (local and sepolia) verify payment events from the configured contract, after the validator checks the RPC's chain id and the contract's code. mainnet is refused. The default mock mode simulates payment. Chain-backed payments are not yet validated. Contract and pricing: Smart Contract.
IPFS (binaries)
The default store for binary bytes. Oak identifies a binary by the SHA-256 of its content, and IPFS addresses the stored bytes by CID. With encryption on, the CID is of the ciphertext. Consensus carries the blob ID and the CID (see Storage Architecture below).
Validator API
Each validator serves source routes for consensus and operations state, plus local diagnostic routes. Route list: API.
Edge API
oak-chain-edge-worker owns /ops/v1/*, the read contract for remote dashboards and clients, built from validator source routes.
Two Deployment Models
Oak Chain has two integration patterns because the constraints are actually different.
Why two models? We started with the hard constraints:
- Constraint 1: New apps don't need AEM's complexity → SDK model
- Constraint 2: Existing AEM customers can't migrate → Connector model
- Constraint 3: Both need the same validator infrastructure → Shared architecture
We do not force one path. The split is simple: SDK for net-new applications, Connector for entrenched AEM estates, one validator core underneath both.
Model 1: Blockchain-Native Applications (Top Flow)
For: New applications built from scratch or modern web/mobile apps
Integration Path: Application → Oak Chain SDK → Validators → Ethereum
How it works:
- Applications use the Oak Chain SDK (JavaScript/TypeScript) to interact with validators
- SDK source provides REST, SSE, and signing helpers; its write-side settlement contract is still being realigned
- Content writes go directly to validators via HTTPS API
- In a future chain-backed deployment, validators verify settlement evidence before Aeron/Raft admission
- Example: EDS (aem.live), React apps, Next.js sites, mobile apps
Best for:
- New projects without existing AEM infrastructure
- Modern JavaScript/TypeScript applications
- Edge Delivery Services (EDS) deployments
- Headless CMS architectures
Model 2: AEM Integration (Bottom Flow)
For: Existing Adobe Experience Manager customers
Integration Path: Validators → HTTP segment transfer → read-only /oak-chain mount in AEM 6.5 LTS
How it works:
- The Oak Chain Connector is one OSGi bundle and an opt-in tool (preflight, enable, verify, status, disable), applied with one restart; stock Oak, no fork
- Uses Oak's composite mount pattern to mount
/oak-chainread-only - Inside AEM, chain content is ordinary JCR, read by path through Sling and the JCR API
- The connector is read-only: AEM reads chain content, and writes under
/oak-chainare refused. Writes go through the validator API or the SDK - Validators serve Oak segments over HTTP (
/segments/,/journal.log,/manifest) fromoak-segment-consensus - Supported: AEM 6.5 LTS author (Java 17 or 21, Apache Oak 2.4.0), demonstrated on SP3. AEM as a Cloud Service and AEM 6.5 (non-LTS) are not supported
Best for:
- Organizations already running AEM
- Teams familiar with JCR/Sling APIs
- Reading chain content inside an existing AEM 6.5 LTS author
Understanding the Diagram
The diagram above shows both integration models side-by-side:
- Top flow (Model 1): blockchain-native applications such as EDS connect directly to validators over HTTPS
- Bottom flow (Model 2): existing AEM systems mount Oak Chain over HTTP segment transfer
- "Model 1" and "Model 2" labels: visual labels only, not functional nodes in the data path
- Shared binary storage: both models reference the same author- or validator-configured BlobStore
Both target paths converge on the same validator core. Chain-backed settlement and production integration remain deployment gates, not assumptions.
The Three Operational Planes
Oak Chain works best when you think of it as many sovereign validator clusters, not one giant consensus mesh.
Operationally, each validator cluster behaves like an AEM/Oak fiefdom:
- one local Aeron consensus boundary
- one authoritative writable repository
- one enterprise, owning the namespaces the federation directory lists for it
Everything else is a separate plane.
┌─────────────────────────────────────────────────────────────┐
│ Plane 3: Federation Directory │
│ Charter, directory epochs, namespace owners, endpoints │
├─────────────────────────────────────────────────────────────┤
│ Plane 2: Cross-Cluster Reads │
│ Lazy read-only mounts, HTTP segment transfer │
├─────────────────────────────────────────────────────────────┤
│ Plane 1: Intra-Cluster Consensus │
│ Aeron cluster, local writes, authoritative repository │
└─────────────────────────────────────────────────────────────┘
Visual companion: the three-plane model and the consensus sequence inside one cluster are explored end-to-end with code anchors in the Write Flow + Content Fabric visual. Open the write-flow plate for the consensus sequence; the content-fabric plate for the clusters-of-clusters model.
Plane 1: Intra-Cluster Consensus
Aeron consensus is local to one authoritative cluster.
Consensus never spans multiple clusters. A write must land on the cluster whose enterprise owns the namespace. Inside that cluster:
- validators elect a leader
- the leader verifies the write and payment
- Aeron replicates the command to followers
- the local authoritative repository commits the change
A write for another cluster's namespace is refused before it is queued. With a committed federation directory, the answer is 307 wrong_cluster with the owner's endpoints. On a cluster that uses static prefix routes, it is 307 wrong_shard. An unclaimed namespace answers 403 namespace_unclaimed (federated) or 503 shard_unclaimed (static routes). The full list is under Write routing and authority below.
Content Ownership
An Ethereum address is the namespace root.
/oak-chain/{L1}/{L2}/{L3}/0x{address}/...
{L1}/{L2}/{L3}- First 6 hex chars of the address (e.g.,74/2d/35)0x{address}- Full Ethereum address of the namespace{organization}- Optional organization/brand scope below the namespace rootcontent/- Standard AEM content root when used
Example:
/oak-chain/74/2d/35/0x742d35cc6634c0532925a3b844bc9e7595f0beb0/
├── PixelPirates/content/ ← Gaming brand
├── CryptoKitchenware/content/ ← eCommerce brand
└── PersonalBlog/content/ ← Personal content
Path segments are lower-case. A namespace segment is 0x followed by 40 lower-case hex characters, and the three levels above it must match the address. The levels give every namespace one fixed root, and no single node lists every namespace as a direct child. Remote mounts attach at these roots.
Without a federation directory, the leader accepts a write only under the signer's own address root. With a directory, the validator that receives the request, the leader's queue and replicated apply make the same decision from the committed directory: the namespace's own wallet or one of its enterprise's listed writers may write, and only while the enterprise is ACTIVE. Cluster operation and membership remain operator-governed.
Plane 2: Cross-Cluster Reads
Other enterprises' namespaces are mounted lazily and read-only.
Each validator mounts the namespaces of every other ACTIVE enterprise in the committed directory over HTTP segment transfer. Without a directory, it mounts the clusters named in its static prefix routes. Those remote mounts are:
- read-only
- outside Aeron and off the local commit path
- allowed to fail without making the local authoritative store unwritable
Reads under an unavailable mount answer 503 mount_unavailable, not empty content. This is how the network gets a shared read view without turning all clusters into one consensus system.
Plane 3: Federation Directory
The directory is replicated input to write authority. It is not a second consensus.
The federation directory answers:
- which enterprises exist, and their status
- which namespaces each enterprise owns, and which wallets may write them
- where each enterprise's validators are reachable
Each cluster commits the directory through its own log and reports it at GET /v1/federation. Every write decision it drives can be traced to the committed directory and to the error codes above. Signed announcements and gossip are not implemented. Details: Federation directory, below.
Supporting Concerns
Payment, economics, and visual naming are separate from the three planes.
- Cluster = economic unit
- Internal node distribution is off-chain
- A future chain-backed admission path verifies configured settlement evidence
Enterprise Federation
This section describes code merged into the validator runtime. It is not deployed: no registry runs on Sepolia or mainnet, and no federated production cluster runs. Configuration: oak-segment-consensus README.
Enterprise clusters
An enterprise runs one validator cluster. The registry design requires 3 or 5 validators. The validator runtime does not enforce the size; the harness ran 3 per cluster.
Each cluster commits a charter once, after genesis. The charter records the enterprise id, the blockchain mode, the chain id and the registry. The cluster id is keccak256(charter ‖ genesis integrity digest). A member configured for a different charter refuses writes with 503 charter_mismatch. GET /v1/federation and /health report the committed charter and whether this member's configuration matches it.
Status: merged, not deployed.
Namespaces
A namespace is an Ethereum address. Its content lives under /oak-chain/XX/YY/ZZ/0x<address>/, where XX/YY/ZZ are the first six hex characters of the address.
An enterprise holds one or more namespaces, usually one per business unit. A namespace may be written by its own wallet or by any wallet the enterprise lists as a writer. A listed writer may write into every namespace of its enterprise. A node created by a listed writer records the namespace, not the writer, as its owner. The zero address is reserved for genesis and cannot be claimed.
In the EnterpriseRegistry contract, an enterprise's admin wallet (a Safe) adds namespaces, sets writers and sets endpoints. Each namespace must sign its own claim (EIP-712 NamespaceClaim). An enterprise can hold at most 8 namespaces and 32 writers. Reference: the EnterpriseRegistry contract in oak-chain-smart-contracts.
Status: the contract is merged with tests. It is not deployed to Sepolia or mainnet.
Federation directory
The federation directory lists every enterprise: its status (PENDING, ACTIVE, SUSPENDED or RETIRED), signer set and threshold, member endpoints, namespaces and writers. Namespaces are disjoint across enterprises.
Each cluster's leader reads the directory and proposes it as a DIRECTORY_UPDATE command. Every member applies it to a hidden :directory node. A snapshot is accepted only if:
- it comes from the charter's chain and registry
- it has a higher
directoryEpoch - it names the committed snapshot's digest as
prevDigest
The directory comes from one of two sources:
- Static JSON file:
mockandlocalmodes only. - EnterpriseRegistry contract: the leader reads every view at one block, the finalized block on public chains and the latest on a local chain. It first checks that the RPC reports the charter's chain id and that the registry address holds the expected code. Mainnet requires a pinned code hash.
Status: the static source has run in the live harness. The registry reader has unit tests and an opt-in test against a local Hardhat chain. No registry is deployed.
Write routing and authority
Once a directory is committed, three places make the same decision from it: the validator that receives the request, the leader's queue, and replicated apply on every member.
202, queued307 wrong_cluster, with that enterprise's endpoints503 owner_unreachable403 namespace_unclaimed403 writer_not_authorized503 enterprise_inactivenamespace parameter on a cluster without a directory400 namespace_requires_federationApply rejects any mutation the committed directory does not allow, so every member skips it identically. This includes a write queued before a directory update that revoked the writer.
A cluster without a directory keeps the older rules: static prefix routes at ingress, and the own-address check in the leader's queue.
Status: unit tests, and the live harness smoke run (58 of 58 required assertions).
Reading another enterprise's content
Each validator mounts the namespaces of every other ACTIVE enterprise, read-only, at their address roots. Local and unclaimed paths stay on the local store. Each remote enterprise is one Oak mount.
A mount reads from the first listed endpoint that passes an identity check: GET {endpoint}/v1/federation must report the entry's enterpriseId, and its clusterId when the entry pins one. The check uses a 2 s connect timeout and a 5 s request timeout. A mount fails over in list order when an endpoint's circuit breaker opens. With no usable endpoint, reads under the mount answer 503 mount_unavailable instead of empty content. Remote reads stay off the local commit path. Mounts follow each new committed directory epoch.
Status: unit tests. The live harness failover run (30 of 30 required assertions) stopped the endpoint the other cluster was mounting from. Every mount failed over in about 3.3 s, and no read returned missing content.
Trust boundaries
- Inside a cluster: Raft ordering, crash-fault tolerant. Members trust the leader's directory read; apply checks the chain, registry and epoch fields but does not re-read the chain.
- Across clusters: a reader trusts the directory's endpoint list and the endpoint's own report of its enterprise. That report is not signed.
- Head attestations: the registry can anchor quorum-signed head attestations and record equivocation, but validators do not sign heads yet.
- What signatures cover: a write signature covers the submitted message. It does not cover the
namespaceparameter. A delete signature covers the content path. - Mock mode: signatures are checked for format only.
Evidence and limits
The harness is the federation 3x2 smoke and failover tests in oak-chain-infra. Both runs used one host, mock mode, a static directory file and the validator built from the enterprise-federation change (06e6ca7925).
clusterId in a live run503oak-chain tx --namespace command sends namespace.Cluster Topology
The network adds enterprises by adding clusters. Each enterprise cluster owns the namespaces the federation directory lists for its enterprise: one local writable repository, plus lazy read-only views of other enterprises' namespaces. Two federated clusters have passed a local harness on one host in mock mode; no multi-host or chain-backed federation has run.
graph TB
subgraph ClusterA["Cluster A"]
direction LR
LA["Leader +
Followers"]
SA["owned
read-write"]
MA["remote
read-only"]
LA --> SA
LA -.-> MA
end
subgraph ClusterB["Cluster B"]
direction LR
LB["Leader +
Followers"]
SB["owned
read-write"]
MB["remote
read-only"]
LB --> SB
LB -.-> MB
end
subgraph ClusterDots["..."]
direction LR
LD["Cluster 3..N-1"]
end
subgraph ClusterN["Cluster N"]
direction LR
LN["Leader +
Followers"]
SN["owned
read-write"]
MN["remote
read-only"]
LN --> SN
LN -.-> MN
end
SA <-->|"HTTP"| MB
SA <-->|"HTTP"| MN
SB <-->|"HTTP"| MA
SB <-->|"HTTP"| MN
SN <-->|"HTTP"| MA
SN <-->|"HTTP"| MB
style SA fill:#4ade80,color:#000
style SB fill:#4ade80,color:#000
style SN fill:#4ade80,color:#000
style MA fill:#64748b,color:#fff
style MB fill:#64748b,color:#fff
style MN fill:#64748b,color:#fff
style LA fill:#627EEA,color:#fff
style LB fill:#627EEA,color:#fff
style LN fill:#627EEA,color:#fff
style LD fill:#1a1a2e,color:#888
Each cluster is sovereign over its own namespaces and mounts other enterprises' namespaces read-only. Consensus stays local.
- A write into one of A's namespaces, sent to Cluster A → queued when the signer is that namespace's wallet or a listed writer of A
- The same write sent to Cluster B →
307 wrong_clusterwith Cluster A's endpoints
Clusters without a committed directory fall back to static prefix routes (oak.sharding.*), where each cluster owns a range of first address bytes, for example 00-7f. A first committed directory replaces those routes.
Scale limits
The directory lists namespaces explicitly. The registry allows at most 8 namespaces and 32 writers per enterprise. On the read side:
- Each remote enterprise is one mount.
- Resolving a path scans every mount.
- A composite root read touches every remote enterprise's root.
- Listing the children of
/,/oak-chainor a shard level scans every mounted namespace root once.
Current boundary: no scaling benchmark exists. Benchmark each deployment with its actual payloads, storage, and network topology. Cross-cluster reads today use:
- Lazy segment fetching (pull on demand)
- Mounts that follow the committed directory, checked every
oak.federation.pollMs(default 10 s)
Storage Architecture
Why Oak segments? Current evidence covers local/test validator stores. TB-scale operation remains an engineering target that requires deployment-specific validation.
Oak segments are immutable and the journal is append-only. Segment IDs are random UUIDs, not content hashes. The scale work is lazy segment fetching, member-local GC, and disciplined sync boundaries; no TB-scale public benchmark is currently claimed.
Oak Segments
Content stored in Oak's TAR segment format:
- Immutable segments
- Append-only journal
- CRC32 checksums per TAR entry
- Oak NodeStore content model; JCR access through Oak-based systems is a target
Binary References
Consensus stores the blob ID and the CID:
- Oak identifies a binary by the SHA-256 of its content and checks it on every read
- A CID addresses the stored bytes (the ciphertext when encryption is on)
- Binary bytes stay outside Oak segment consensus
- Validator-hosted IPFS is the default; an author can reference bytes on its own node by CID
- Availability requires a reachable node that holds the bytes, or IPFS Cluster replication
graph LR
subgraph Oak["Oak Segment Store"]
META[Metadata + blob ID + CID]
end
subgraph IPFS["IPFS nodes"]
BIN[Binary Content]
end
META -->|CID| BIN
style META fill:#627EEA,color:#fff
style BIN fill:#4ade80,color:#000
Run validator IPFS nodes in a private swarm (IPFS_NETWORK_POLICY=private). The default policy only warns. Without encryption keys, anyone who reaches a node and knows a CID can read the bytes.
Cross-Cluster Mounts over HTTP
Oak Chain content is mounted read-only over HTTP segment transfer: validators serve /segments/, /journal.log and /manifest. AEM 6.5 LTS author mounts it with the Oak Chain Connector's mount bundle, which carries its own HTTP client and Apache Oak 2.4.0 Segment Tar. Federated validator clusters mount each other with the consensus/mount/http package in oak-segment-consensus. They have passed a local harness on one host in mock mode and are not deployed.
Platforms (the validator's own OSGi bundle is not a drop-in for stock AEM or Oak; AEM uses the connector instead):
- Demonstrated: AEM 6.5 LTS author (SP3)
- Not demonstrated: Apache Sling and other Oak-based systems
- Not supported: AEM as a Cloud Service
The goal is horizontal read scaling without consensus overhead. See AEM 6.5 LTS Integration for setup instructions.
Next Steps
- Quickstart - Get running locally in 10 minutes
- Developer Guide - Map of all developer content
- Run a Validator - Join the network
- FAQ - Common questions answered