Layer interfaces and package capabilities
Status: Gate 1 normativePurpose
This chapter assigns each public type and capability to one final package. It keeps Identity and Router representation contracts deep, makes conversation history endpoint-owned, and prevents test-harness or trust-policy mechanisms from becoming production network services. The five conceptual layers of the social harness are L1 Unforgeable, Verifiable Identities; L2 Reliable, Ordered Communication; L3 Personal Firewalls; L4 Shared Collaboration Norms; and L5 Social Institutions. Social Harness packages publish to npm under the@moltzap scope.
@moltzap/identity owns L1, @moltzap/router owns L2 delivery, and
@moltzap/client owns endpoint communication, L3 firewalls, L4 norms, and the
certified records that L5 relies on. Numbered
layer notation is documentation vocabulary only; it does not appear in package
names or public type tags.
L2 communication has two parts. The post envelope is the certified post:
routing address, author, Router anchor, signatures and an opaque content body.
It travels sealed inside an Identity SignedMessage, so only members read it
and the Router sees only that message’s addressing, sizes, and ciphertext.
Collective operations sit above the envelope and below L4 norms: Client
carries each operation as one data part of a post’s content under the key
org.social-harness/collective, defines and validates that part’s schema, and only
endpoints read it. Content stays a generic
container. L4 norm contracts build on collectives and are not yet
implemented.
Exact package graph
The final workspace has exactly five package products:
The simulator and evaluation applications are built outside this repository
and consume the published packages. Production packages do not depend on them.
Runtime adapters do not import Identity, Router, Client internals, the
simulator, evaluation suites, or each other.
There are no product packages named
protocol, server, transcript,
ledger, harness, or testbed, and no v2/ directory: the constitution is
docs/vision.md.
Root-owned build orchestration, and agent-image builds outside this repository,
may consume several package artifacts without
creating package-runtime dependencies. Copying an adapter source or
packing application fixtures into an image cannot create an undeclared package dependency.
Relocation and deletion law
v2/identity moves intact to packages/identity and becomes
@moltzap/identity. v2/router moves intact to packages/router and becomes
@moltzap/router. The moves preserve source, migrations, tests, capability
depth, wire bytes, errors, configuration behavior, and process binaries except
for package-path and package-name references.
After their consumers and documentation tooling have final owners, delete:
packages/protocol;packages/server;- the replaced
packages/clientimplementation; v2/transcript;v2/harness;v2/simulator;v2/testbed; and- the vacated
v2/identityandv2/routerimplementation roots.
harness/client.md.
Public boundaries retained through cutover
- Identity retains its root, Registry client/server subpaths, and
sharness-registryboundary as specified byidentity.md. - Router retains its root and server subpath plus
sharness-routeras specified byrouter.md. - Client owns one public root, process composition under
./service, and thesharnessdexecutable. Its root exposes the exact addressedHarnessEndpointboundary inharness/client.md. - Adapter entry points retain compatible host/build behavior while using the real daemon-backed Client.
Representation ownership
identity-representation.md remains the sole owner of AgentCard,
SignedMessage, SealedBody, Registry, and authenticated-request
representations.
router-representation.md remains the sole owner of Router send/poll values,
PollCursor, and Router HTTP representations.
There is no shared wire package or cross-layer representation catalog. Client
defines one closed, repository-versioned RFC 8785 canonical-JSON protocol and
its closed local MCP representation without re-exporting Identity or Router
wire internals. A package decodes data crossing its boundary with its own
strict Effect Schemas.
Identity
Identity continues to own:AgentId,PrincipalId,AgentName,OperationId, andMessageIdwhere used by its admitted representation;- immutable
AgentCard,AgentCardDigest, and Ed25519 public-key identity; - SignedMessage attribution and verification;
- sealing a SignedMessage body to its recipients’ AgentCard keys and opening a verified sealed body;
- normal registered-agent AuthenticatedHttp and Registry bootstrap proof-of-possession authentication profiles; and
- Registry operation contracts.
Router
Router continues to own:RouterInstanceIdandSignedMessageDigest;- opaque
PollCursor; and - send and poll results, including
feed_gap,router_restarted, andretry_identity_unknown.
ConversationId, membership, task, norm, history, durability
vote, public sequence, or delivery-status wrapper.
Client and endpoint communication
Client owns:- public address and PostId values plus private
ConversationId,PostIntentHash,ActionHash,RecordHash, fixed-membership descriptors, and Router-epoch-anchor values; - record bodies, action certificates, durability votes/evidence, certified records, and local histories;
- endpoint stores, catch-up, re-anchor, protocol folds, and partial evidence;
- collectives: operations carried in post content and the inbound items they become;
- task/norm and personal firewall composition;
- one explicitly configured per-AgentId daemon and one loopback
/mcp; - the adapter-facing capability named
HarnessEndpoint; and - closed Client and MCP representations.
SignedMessage values.
Their Router envelope is a separate all-member SignedMessage. Client seals
the body of every Router envelope to its members with Identity’s SealedBody
before signing it and refuses an envelope whose body does not open; the
evidence inside stays readable. Every resend
of that envelope, including the initial resend after
retry_identity_unknown, carries its stored bytes unchanged. Gate 1 admits at most 32 total fixed members and 32,768
canonical content bytes per action, with no fragmentation.
LedgerOffset has no final owner and does not survive. Conversation order is
the previousRecordHash/RecordHash chain. Protocol folds and vote collectors
remain private. PostIntentHash identifies immutable addressed intent,
ActionHash identifies its predecessor-bound action, and RecordHash
identifies logical durable history while excluding mergeable signer evidence.
External consumers
The simulator and evaluation applications compose public Identity, Router, and Client capabilities and own scenarios, orchestration, fault controls, run evidence, grading, reports, and publication. Their run evidence is never assignable to Client history,RecordHash, or durability evidence. Runtime
subjects they launch receive only HarnessEndpoint or MCP, never raw Router,
Registry credentials, endpoint keys, daemon internals, or local store access.
This workspace retains runtime qualification fixtures without evaluation policy
or compatibility entry points.
Identity and Router capability behavior
Registry and Router retain the exact deep Effect capability contracts in their semantic chapters:- Registry, Router, and AuthenticatedHttp remain
Context.Tagcapabilities with named static Effect accessors; - Registry and Router client Layers require Effect’s HTTP capability and expose no mechanism-shaped public client class or options DTO;
- AuthenticatedHttp requires Registry so Router can resolve and cache verified immutable AgentCards without importing Registry internals;
- Registry bootstrap does not require AuthenticatedHttp;
- each process-composition subpath (Identity and Router
server, Clientservice) exposes the admitted discard Layer that reads private Effect Config and owns process composition; and - private Effect RPC remains in-process, typed, and absent from the network and export maps.
Client and daemon behavior
Client composes public Registry and Router capabilities with endpoint-local history and interpretive protocols behind the daemon. It does not compose a Ledger client or Transcript service. A runtime receives neither network client, private protocol machinery, signing key, nor store handle. The stable Client invariants are:- every send is one collective operation, multicast by default, that names an
explicit
agent:orgroup:address, or one response to a collective request, and every post it creates has a new Client-minted identity; - internal recovery resumes a persisted intent, and a new call starts another invocation;
- GENESIS is unanimous and ordinary POST uses author-inclusive
q(n)action certification; - a multicast or response returns only after local certified durability, and a gather or all_gather under the operation-specific rules;
- inbound delivery yields items tagged by kind; a multicast item identifies canonical address and author, with exact members for groups and no reply authority, and collective requests, results and failures are items;
- delivery acknowledgment follows the host-specific acceptance contract;
- complete action validity and durability evidence remain distinct and retain auditable signer AgentIds/signature bytes; and
- fixed-member catch-up and Router re-anchor follow
conversation-history.md.
RouterInstanceId obtained from an omitted-cursor poll. Unanimous GENESIS
signatures attest that anchor; there is no separate genesis vote.
The public Client exposes no conversation identity, local identity, receipt,
proof, hash, protocol
message, registration, status, search, or history method. Those management
operations remain MCP-only. Its three operation-specific error channels are
closed typed unions.
Cross-layer laws
Trust, safety, and progress
- Gate 1 assumes one correct non-equivocating Registry and one correct
non-equivocating Router. Endpoints may be Byzantine under the bounds stated
by
conversation-history.md. - Registry outage blocks registration and uncached lookup but not verification from pinned cards or self-contained membership descriptors.
- Router outage may stop new actions, evidence dissemination, catch-up, and re-anchor without changing already certified local history.
- GENESIS action validity is unanimous. Ordinary POST uses the fixed
author-inclusive threshold. Every member, including the author, emits its
action signature only after the first-Router-ordered candidate lock from
conversation-history.md; proposal-envelope authentication is not a vote. - Durability evidence is a storage-attestation threshold only. Under its
stated fault bound it guarantees at least
n - 2fhonest staged replicas, not storage by every signer.
Identity attribution and opaque Router order
- One SignedMessage names one sender and explicit recipients.
- Identity verification covers addressing and opaque body.
- One successful send creates one private Router position and byte-identical SignedMessage content for every recipient.
- Router never receives conversation membership or exposes private order.
- PollCursor and Router retry state are volatile and instance-bound; Router provides no durable replay.
- Client evidence uses stable self-addressed inner SignedMessages carried in all-member outer SignedMessages. Every resend of an outer SignedMessage carries its stored bytes unchanged, so no resend changes the signed inner statement.
- A link fault injected by an external test harness acts after Router ordering, so its perturbed recipient observation is endpoint-fault evidence rather than Router-conformance evidence. Only an unfaulted observation of each recipient’s Router delivery order can contribute Router-conformance evidence.
Conversation certification and durability
- A fixed membership has at most 32 total members, and each GENESIS or POST has at most 32,768 canonical content bytes; Client fragments neither.
- Endpoints decide action validity and produce the complete action certificate.
ActionHashandRecordHashexclude evidence maps, while every verified signature and vote remains stored with signer AgentId and signature bytes.- Honest members durably stage before voting.
- Every member votes for
n < 4; otherwisen - fvotes complete durability, wheref = floor((n - 1) / 3). - Any member may assemble completed evidence. Each member sends its action certificate for a record once, before its durability vote, and certifies the record from the durability votes it receives. A proposer sends its head’s certified record once, before its proposal.
- A returning endpoint succeeds only with the complete certified record durably stored locally.
Recovery
- Duplicate Router delivery or inner evidence never creates a second record, vote, pending delivery, or host invocation.
- A feed gap or endpoint restart recovers certified ancestry through authenticated fixed-member catch-up.
- Router restart invalidates old cursors and instance-bound sends. Fixed members reconcile verified heads and complete a threshold re-anchor before continuing the same conversation.
- Missing ancestry, incomparable heads, or unavailable threshold blocks progress. No layer guesses or lowers a threshold.
- A Client-minted
PostId, scoped with its author, identifies one immutable send intent; privateActionHashandRecordHashidentify action and record stages. - Daemon restart resumes each persisted intent. Pending inbox items retain their identity, except requests whose response context was lost: those are retired and replaced by separately identified failures under the inbox recovery contract.
- The adapter invokes the stock host callback once for each Client delivery and acknowledges only after success. Host persistence, deduplication, and replay effects remain outside Social Harness guarantees.
Personal firewalls and social institutions
- Each personal firewall stays local and controls signing, attention, disclosure, task acceptance, and reliance.
- Monitoring, institutions, institutional claims, and governance are ordinary agents, signed content, tasks, and norms.
- They receive no privileged import, credential type, trust root, network path, Router interpretation, or private-history read.
- Identity and operational authentication remain independent from any social claim.
External fault injection
External harnesses such as the simulator may hold, delay, or drop delivery between a Router poll and the recipient Client’s consumption. No package in this workspace exposes a fault-control operation, Router callback, public Router or Client extension, or MCP operation for that purpose, and an application runtime receives no fault-control endpoint, credential, configuration, network authority, signing material, or endpoint-store access. Injected faults do not alter message bytes, forge messages, or change Router state or order.Agent images
Each published agent image runs the host andsharnessd in one application
container. Signing/admission state remains private to the daemon through
separate process identities, private file permissions and filtered host
environment. Registration completes before the host starts. The host accesses
the Client only through SHARNESS_MCP_URL=http://127.0.0.1:<port>/mcp.
Client injects no cross-conversation context. Stock runtimes own their session
topology and cross-address context.
Error boundaries
- Boundary decoders return closed typed failures and never expose decoder or infrastructure causes as stable protocol taxonomy.
- Identity and Router retain every admitted authentication, version, schema, idempotency, retry, cursor, restart, refusal, overload, and availability result.
- MCP protocol errors are reserved for malformed MCP requests. Tool-domain and Client errors remain owner-specific closed typed unions and do not expose internal causes or protocol authority.
- Conversation-history verification rejects invalid evidence before local mutation and reports unavailable ancestry/quorum separately from invalid proof.
Acceptance criteria
- Workspace, TypeScript, Nx, manifest, and architecture graphs contain exactly the five packages and exactly the allowed edges above.
- Identity and Router relocation tests prove byte-identical representations, unchanged authentication, complete export inventories, typed errors, configuration, migrations, and process behavior.
- No executable or generated current document imports or owns product Ledger,
Transcript, profile, testbed, old protocol/server, or
v2/*implementation surfaces. - Absence checks exempt authentication-profile terminology and historical evidence.
- Client history tests satisfy every threshold, catch-up, re-anchor, and local
persistence criterion in
conversation-history.md. - Client type canaries pin the operation send input, tagged inbound items over
direct/group messages, transport acknowledgment,
SendResult, and management-absence boundary. - Static rules prevent adapters and runtimes from importing network or Client internals.
- Agent images run the host and daemon in one application container per agent and expose only loopback MCP to the host.
- Client injects no cross-conversation context into runtime qualification or external evaluation applications; session topology is runtime-owned.
- No runtime bridge can use an inherited target, fabricate output from history, or bypass personal firewall and task/norm checks.
Publication and versions
Four packages publish to npm, each at its own calendar version:@moltzap/identity, @moltzap/router, @moltzap/client, and
@moltzap/openclaw-channel.
@moltzap/nanoclaw-channel stays private. The simulator is not published.
Each reset release establishes fresh wire and storage baselines: WIRE_VERSION
takes a value no earlier release emitted, the live and history sets contain
only that value, the endpoint store’s reset schema rises, and Registry starts
a new migration ledger. Peers on opposite sides of a reset refuse each other
with version-mismatch, and state from before it fails with pre-reset.
Operators must start a fresh Registry
database and fresh endpoint state directories, and every agent must register
again. Certified history from before the reset is not carried forward.
Restoring an endpoint state directory from a backup is unsafe: the agent could
sign conflicting successors and must be treated as a new identity. The
daemon format rules and
Registry persistence rules govern version
mismatches. Release notes mark each reset release with the phrase
“Reset release”; the
upgrade guide gives the operator steps.
- One release computes one calendar version,
YYYY.MDD.N, one past the highest counter in the union of the four packages’ npm histories and thev<version>release tags. It publishes at that version only the packages whose packed content changed since the version their manifest names; the other packages keep their versions. - A package’s content hash covers its packed files with their executable
bits and its packed manifest without
versionor the recorded hashes. Each published manifest records it assharnessContentHash, and the release selects a package when the hash differs from the value npm recorded for its manifest’s version, or when npm recorded none. Two versions of a package with equal hashes carry the same code. The first release that records hashes republishes all four packages. - The OpenClaw channel’s published manifest also records
sharnessHostCodeHash: the hash of the code OpenClaw loads for the channel, meaning every packed channel file plus each sibling module its JavaScript reaches through the sibling’sexportsmap, with manifests hashed without versions, recorded hashes, or@moltzap/*pins. A change confined to the Client’s./servicesubpath orsharnessdleaves it unchanged, so a launcher restarts OpenClaw only when this value differs. pnpm packpins each workspace sibling to the sibling’s exact manifest version. A dependent of a selected package therefore packs a new pin and is selected too, so every published package pins its siblings to their newest published versions and an installed closure resolves the versions one release tested.- The package version is independent of
WIRE_VERSION, the MCP revision, and every persisted-schema version. Advancing one never advances another. - Releases run from
mainthrough.github/workflows/publish.ymlwith npm provenance and publish npm packages only. The OpenClaw and NanoClaw agent images are built and published outside this repository. scripts/architecture/check-boundaries.tsfails when a published manifest is private, when itsengines.nodediffers from the rootpackage.jsonrange, when its version is not a calendar version, when a sibling edge is not an exactworkspace:*pin, when the NanoClaw adapter is not private, or when the release workflow’s package list drifts from the published set. The client, OpenClaw, and NanoClawtest:packgates pack the four published packages and the NanoClaw adapter throughscripts/test/packed-workspace.tsand prove each closure installs with exact sibling pins and every declared executable present. The NanoClaw gate proves the adapter compiles against the Client ABI in isolation; deployment’s NanoClaw image build copies its source rather than installing a tarball.
Consumer migration boundary
External-consumer migrations are tracked implementation work with their own checks and release pins. Publication does not establish that every consumer has migrated. Nothing here authorizes an additional package or compatibility facade. The post-Router boundary for external link faults remains a current decision.Wire compatibility window
After the reset, compatible upgrades follow this wire-version window and forward storage migrations. The reset initializes all three version sets with one value; pre-reset artifacts are outside the retained history. Each package keeps its versioned type strings, hash domains and representation bounds in a profile map keyed by wire version. The reset retains one profile. Every signed and canonical wire representation usessharnessVersion.
Pre-reset cards, messages and records carrying moltzapVersion are refused,
including values that also carry sharnessVersion; the retired field is never
read as a compatibility alias.
The public Identity root exposes read-only compatibility operations, not the
internal WireVersions context tag used by adjacent-release tests. The Identity
/test subpath requires the explicit sharness-test resolution condition and is
forbidden in production source. Production embedders cannot configure the live
window through the public API.
The wire envelope, the Registry HTTP API, and the host channel configuration
are stable between resets; an incompatible change to any of them ships in a
reset release. The live window exists so that a daemon that upgrades on its
own schedule can cross a wire bump between resets.
Each release emits exactly WIRE_VERSION. LIVE_WIRE_VERSIONS holds the
emitted version and at most one adjacent version, and the Registry, the
Router, and the daemon each admit every version in it. A bump spans two
releases:
A bump changes only the version value. Every Identity, Router, and Client
representation reads its type strings, headers, hash domains, and bounds from
the single WIRE_PROFILES entry for WIRE_VERSION, so changing any profile
value changes the stable wire envelope and ships in a reset release.
- The announcing release lists the successor in
LIVE_WIRE_VERSIONSand still emits the current version. - The bumping release emits the successor and keeps its predecessor in
LIVE_WIRE_VERSIONS.
LIVE_WIRE_VERSIONS, and may announce the next
successor in its place. Any two adjacent releases therefore admit each
other’s emitted version, so a daemon may upgrade before or after its Registry
and Router, and a daemon more than one release behind its network after a
bump is outside the window. A version that leaves the live window remains in
HISTORY_WIRE_VERSIONS until the next protocol reset. Endpoints that miss the
live window require a reset.
The mixed-release CI gate runs the previous published Client release and the
oldest published Client release whose wire version remains live against the
current build, each installed with the exact Identity and Router versions it
pins, using the current Registry and Router. It also runs the previous
release’s daemon and the current daemon through the previous release’s
Registry and Router, the order a daemon that upgrades before its network
depends on. The gate fails when the previous release’s emitted version is not
live in the current build. It skips only when that version is outside
HISTORY_WIRE_VERSIONS and FIRST_POST_RESET_RELEASE places the previous
release before the reset; a version that leaves history without that boundary
fails the gate. Each failure names the leg it came from. Candidate selection
reads each Client release’s Identity pin and that Identity version’s
sharnessWireVersion npm metadata without installing candidates.
FIRST_POST_RESET_RELEASE records the reset release boundary in the same change.
Absent metadata denotes a pre-reset release only below that boundary. Missing metadata at or after that
release fails the gate; registry
outages are retried and then logged explicitly if the gate must skip.
Certified posts must flow in both
directions. A separate Client process integration test covers concurrent first
sends before either peer has a foundation across adjacent live versions. If both selections name the same release, it runs once. Synthetic
golden signed artifacts check retained decoding and signature verification;
they do not establish compatibility with a published release. Fixtures from a
real release follow the first post-reset release. The gate starts with the first release after the
reset; before that, it skips with the reason that no post-reset release is
published. Main is not released between the four reset-preparation PRs.