HPPR Core Specification
This file is assembled from hppr/spec/*.md. Edit the
source files, not this aggregate.
HPPR Specs
Tags: overview
HPPR is Hyper Plex Packet Repository.
Purpose
HPPR specifies a layered protocol for storing, signing, addressing, exchanging, and routing content-addressed packets.
The specs are written for implementers of packet libraries, repository daemons, clients, transports, and route-aware applications.
Architecture at a Glance
- Encoding and crypto: B64A and HSB3.
- Stored packet format: Blob, Plex, and Seal packets.
- Addressing: hash addresses and coordinates.
- Command messages and flows: session and message command execution.
- Transports: TCP/WebSocket/QUIB session flow; HTTP/UDP message flow.
- Repository service: commands, envelopes, ACL, Ring1/Ring2 auth, storage.
- Higher-level conventions: links, chunks, replication, admin workflows, routes, names, and attestations.
Reader Paths
| Reader | Start with | Then read |
|---|---|---|
| Packet-library implementer | 006, 009, 010 | 011, 012, 070 |
| Client implementer | 020, 030, 031, 032 | 033-036, 041-045 |
| Repository implementer | 040-045 | 050-060, 080-090 |
| Route/application implementer | 100 | 110 |
Conformance Profiles
MUST and SHOULD requirements apply to implementations claiming the relevant profile.
| Profile | Required specs |
|---|---|
| Packet profile | 006, 009, 010 |
| Repository client profile | 020, 030-035, 041-045 |
| Repository service profile | 040-045, 050-060, 080-090 |
| QUIB profile | 036 plus repository session-flow specs when used with hpprd |
| Route resolver profile | 100, 110 plus repository client profile |
Reading Order
The specs are numbered in recommended reading order. Tags describe each spec’s primary layer or role.
| No. | Spec | Tags |
|---|---|---|
| 006 | Base64-Ascend | packet, encoding |
| 009 | HSB3 Signatures | packet, crypto |
| 010 | Packets | packet, stored-format |
| 011 | Basic Packet Examples | packet, example |
| 012 | Create Examples | packet, example |
| 020 | Unified Resource Coordinate | packet, addressing |
| 030 | Command Messages | wire, command |
| 031 | Command Flows | wire, command-flow |
| 032 | HELLO and Endpoint Metadata | wire, command-flow, metadata |
| 033 | Via Syntax | wire, transport |
| 034 | HTTP Transport | wire, transport, message-flow |
| 035 | UDP Datagram Transport | wire, transport, message-flow |
| 036 | QUIB | wire, transport, session-flow |
| 040 | Repository Service | repo, overview |
| 041 | Repository Commands | repo, command |
| 042 | Repository Request Envelopes | repo, command-flow, auth |
| 043 | Repository Session Flow | repo, command-flow, session |
| 044 | Repository Message Flow | repo, command-flow, message |
| 045 | Repository Identity Text | repo, auth, client |
| 050 | Repository Access Control | repo, auth, policy |
| 051 | Ring1 Repository Authentication | repo, auth |
| 052 | Ring2 Group Authentication | repo, auth |
| 060 | Filesystem Repository | repo, storage |
| 070 | Packet Links and Chunks | packet, content-convention |
| 080 | Replication and Streams | repo, command, streaming |
| 090 | Admin and Join Conventions | repo, workflow |
| 100 | Content Routes | scheme, route |
| 110 | Routes, Names, and Attestation | scheme, route, name, attest |
Reference Implementation
hpprd is the reference daemon implementation. It
implements the repository service specs tagged
repo.
HPPR-006 · Base64-Ascend (B64A)
Tags: packet, encoding
B64A is an order-preserving Base64 variant.
Alphabet:
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~
Canonical form omits = padding and zero-fills
trailing bits.
Alphabet Mapping
0..9->'0'..'9'10..35->'A'..'Z'36->'_'37..62->'a'..'z'63->'~'
~ keeps the alphabet ASCII-sorted and path-safe.
Encoding Rules
- Pack bits like RFC 4648 Base64 (MSB-first 6-bit groups).
- Do not emit
=. - Zero-fill the final partial 6-bit group.
- Output length is
ceil(8*N/6)forNinput bytes.
Decoding and Validation
- Reject bytes outside the B64A alphabet.
- Decode first, then validate tail bits:
len % 4 == 2: low 4 bits must be zerolen % 4 == 3: low 2 bits must be zero
- Implementations should validate by decoding, not by regex.
Ordering Guarantees
- Equal-length strings compare exactly like decoded bytes.
- If one canonical string is a strict prefix of another, the shorter string sorts first.
Conformance
- MUST emit and accept only the B64A alphabet above.
- MUST forbid
=padding. - MUST zero-fill trailing bits and reject non-zero filler bits.
- SHOULD validate by decoding plus explicit tail checks.
Test Vectors
| Hex | B64A | Notes |
|---|---|---|
| (empty) | empty input | |
00 |
00 |
1 byte |
0000 |
000 |
2 bytes |
000000 |
0000 |
3 bytes |
FF |
~l |
tail 4 bits zero |
FF00 |
~l0 |
tail 2 bits zero |
000102 |
0012 |
exact 3 bytes |
Reject examples: 01, 001,
~m, ~l1, =, +,
/.
HPPR-009 · HSB3 Signatures
Tags: packet, crypto
HSB3 is a BIP-340 style Schnorr signature over secp256k1.
HSB3 uses BLAKE3-256 for all hashing and key derivation tags.
Reference code lives in rust/libs/hsb3.
Parameters
- Curve: secp256k1 (
y^2 = x^3 + 7 mod p) - Order:
n - Generator:
G - Hash primitive:
BLAKE3.derive_key - Tags:
hppr-🖧/auxhppr-🖧/noncehppr-🖧/challenge
Helper notation:
bytes(x): 32-byte big-endian encoding of scalar or field elementbeInt(b): integer from 32-byte big-endian bytestagged(tag, msg): first 32 bytes ofderive_key(tag, msg)
Key Generation
- Draw random 32-byte
d0; reject0andd0 >= n. - Set
d = d0, computeP = d*G. - If
P.yis odd, setd = n - dand recomputeP. - Private key is
d; public key isbytes(P.x).
The even-y convention is mandatory.
Deterministic Key Derivation
Derive a keypair from arbitrary secret bytes.
- Initialize BLAKE3 derive mode with tag
hppr-🖧/adhoc-key. - Feed secret bytes.
- Enter XOF mode.
- Rejection sample 32-byte candidates until
0 < d0 < n. - Apply the same even-
ynormalization as key generation.
Conformance:
- MUST use tag
hppr-🖧/adhoc-keyexactly - MUST use XOF rejection sampling
- MUST apply even-
yconvention - MUST reject empty secret
Signing
Inputs:
msg32: BLAKE3-256 digest of message bytes- private key
d auxRand32: fresh random 32 bytes
Rules:
auxRand32MUST be unique per signature- explicit all-zero aux input is invalid
Algorithm:
t = tagged(aux, auxRand32)mask = t xor bytes(d)k0 = tagged(nonce, mask || Px || msg32) mod n; rejectk0 = 0R = k0*G; ifR.yodd thenk = n-k0, elsek = k0e = tagged(challenge, bytes(R.x) || Px || msg32) mod ns = (k + e*d) mod n- signature bytes are
bytes(R.x) || bytes(s)
Text form uses B64A.
Verification
Inputs: signature r||s, public key Px,
and msg32.
- Parse
r,s; rejectr >= pors >= n. - Recover
PfromPxand take even-yroot. e = tagged(challenge, bytes(r) || Px || msg32) mod nR' = s*G - e*P; reject infinity or oddy.- Accept iff
R'.x == r.
Conformance
Implementations:
- MUST use the three UTF-8 tags exactly
- MUST use BLAKE3-256 message digests
- MUST preserve even-
yconvention in keygen/sign/verify - MUST emit 64-byte signatures and 32-byte public keys
- MUST reject invalid scalars and coordinates
- MUST use constant-time scalar and point operations
- MUST NOT reuse
auxRand32
HPPR Packet Format
Tags: packet, stored-format
© R.A.Sol
Every stored packet starts with a markline:
🖧: <hash-text>
<hash-text> is the packet type, BLAKE3-256
digest encoded in B64A, and .H3 format suffix. It
identifies the canonical payload after the first LF.
HPPR stored packet types:
- Blob: raw bytes
- Plex: metadata + embedded Blob
- Seal: signature + embedded Plex
Shared Rules
- Canonical payload is everything after the markline LF.
- Hash text format is
T.<b64a>.H3whereTisB,P, orS.1 In this spec, digest means the raw 32 BLAKE3 bytes and hash text means the textualT.<b64a>.H3form. - Header syntax is
<Name>: <value>with exactly one space after:. - Header values are non-empty.
- Header names and values are UTF-8 NFC.
- Control bytes are forbidden in headers:
0x00..0x1Fand0x7F. - Header line length limit is 1024 bytes, excluding trailing LF.
- Line endings are LF only. CR and CRLF are invalid.
- Whitespace is data. Never trim.
Blob
🖧: <hash>
Data-Length: <len>
<data exactly <len> bytes>
Rules:
<hash>MUST start withB..- Canonical payload is
Data-Length, blank line, then<len>data bytes. Data-Lengthis base-10 with no leading zeros, except0.- Readers MUST consume exactly
<len>bytes. - Blob data is opaque.
- Blob
Data-Lengthmax is 32 MiB.
Plex
🖧: <hash>
Group: <group>
API: <api>
Key: <key>
TAI: <tai>
[Extra headers]*
🖧: <blob_hash>
Data-Length: <len>
<data>
Rules:
<hash>MUST start withP..- Required headers appear exactly once, in this order:
Group,API,Key,TAI. - Extra headers follow
TAI. - Canonical payload is all Plex headers plus the full embedded Blob packet, including Blob markline and data bytes.
TAI Format
TAI format:
<seconds>:<subseconds>
Rules:
- 10 digits,
:, then 9 digits - no spaces
- subseconds are nanoseconds
TAI seconds use International Atomic Time. Timestamp generation applies the TAI-UTC offset in force for the generation instant.
Header Validation
General:
- Header names MUST NOT contain
:. - Header values MAY contain
:.
Group:
- non-empty
- case-sensitive
- max 56 bytes
- MUST NOT contain
/,{,},|,# - MUST NOT equal
.or..
API:
- non-empty; at least one segment is required
- case-sensitive
- MUST NOT start with
/ - MUST NOT end with
/ - split by
/into segments - each segment is non-empty
- each segment max 128 bytes
- segment MUST NOT contain
{,},| - segment MUST NOT equal
.or.. - total
APIvalue max 1014 bytes
Key:
- non-empty; at least one segment is required
- MUST NOT start with
/ - MUST NOT end with
/ - split by
/into segments - each segment is non-empty
- each segment max 128 bytes
- segment MUST NOT contain
{,},| - segment MUST NOT equal
.or.. - total
Keyvalue max 1014 bytes
Extra Headers
Extra-header ordering is canonical:
- sort by header name using bytewise ascending order
- same-name headers MUST be consecutive
- same-name header order is user-defined and hash-significant
Reserved header names (MUST NOT appear as extra headers):
Data-LengthGroupAPIKeyTAISeal-BySeal-Sig🖧⋯🖧
Limits:
- at most 512 extra headers
- each extra header line max 1024 bytes (excluding LF)
Seal
🖧: <hash>
Seal-By: <verification-key>
Seal-Sig: <signature>
🖧: <plex_hash>
Group: <group>
API: <api>
Key: <key>
TAI: <tai>
[Extra headers (sorted)]*
🖧: <blob_hash>
Data-Length: <len>
<data>
Rules:
<hash>MUST start withS..- Canonical payload is
Seal-By,Seal-Sig, then full embedded Plex. Seal-Byformat isV.<b64a>.H3(48 chars).- Signing secrets use
&.<b64a>.H3. Seal-Sigis an 86-char B64A text signature.- Signature algorithm is HSB3 over the Plex digest.
Packet-shaped Command Envelopes
Wire protocols may define packet-shaped command envelopes that
are not stored packets. The generic Null command packet uses
markline 🖧: 0.H3 and is defined in 030-COMMAND-MESSAGES.md. Null
packets are command envelopes and response envelopes only. They are
not Blob, Plex, or Seal packets and are never stored in repository
storage.
Limits
- Blob data: 32 MiB (
Data-Lengthmax) - Extra headers per Plex: 512
- Header line length: 1024 bytes (excluding LF)
APIvalue: 1014 bytesAPIsegment: 128 bytesKeyvalue: 1014 bytesKeysegment: 128 bytesGroupvalue length: 56 bytes
Parsing
- Read markline and verify the type prefix in the hash text.
- Blob:
- read
Data-Length - consume exact data bytes
- verify Blob hash
- read
- Plex:
- read required headers in required order
- read extra headers with canonical ordering checks
- parse embedded Blob
- verify Plex hash
- Seal:
- read
Seal-By,Seal-Sig - parse embedded Plex
- verify Seal hash
- verify signature
- read
Reject on any of the following:
- invalid UTF-8 or non-NFC header text
- forbidden control bytes
- CR or CRLF line endings
- size or count limit violations
- required-header order violations
- extra-header ordering violations
- hash mismatch
- signature verification failure
Trailer-hash Format
Trailer-hash format supports streaming when the final hash is only known at the end.
Open marker:
⋯🖧: <type>[ <coordinate>]
Close marker:
⋯🖧: <hash>
Rules:
<type>is one ofB,P,S.- Exactly one opening marker is allowed per packet.
- Double-open, triple-open, and nested-open sequences are invalid.
- Trailer-hash is a transport transformation only. Packet hashes are unchanged.
Seal trailer example:
⋯🖧: S //<group>/<api>//<key>/|/seal/<verification-key>
<escaped data>
⋯🖧: B.<blob-hash>.H3
Group: <group>
API: <api>
Key: <key>
TAI: <tai>
[Extra headers]*
⋯🖧: P.<plex-hash>.H3
Seal-By: <verification-key>
Seal-Sig: <signature>
⋯🖧: S.<seal-hash>.H3
Additional rules:
- Escape data by replacing each
⋯🖧:with⋯⋯🖧:before sending. - Unescape after data extraction by reversing that replacement.
- Data ends at the first
\n⋯🖧:sequence. - Validate all headers and hashes using the same canonical rules.
- To convert to standard packet form:
- remove leading
⋯markers - insert Blob
Data-Length - restore standard nested packet layout
- verify hashes and signature
- remove leading
Both sides buffer full packet bytes to compute and verify hashes.
Thin Format
Thin format stores only part of a packet.
- Thin Seal stores:
- Seal markline
Seal-BySeal-Sig- embedded Plex
🖧:hash line
- Thin Plex stores:
- Plex markline
- Plex headers
- embedded Blob
🖧:hash line
- Blob is already minimal and is effectively thin by definition.
Thin packets omit embedded content bytes and rely on nested hashes for reconstruction.
Digest computation always requires full packet bytes. Implementations MUST resolve thin references before hash verification.
Thin format is for storage and transfer when inner packets are already present.
HPPR Basic Packet Examples
Tags: packet, example
This file shows one Blob, one Plex, and one Seal packet in readable form. The hashes and signatures below are shortened placeholders; these examples show shape only and are not conformant packet bytes.
Blob Example
🖧: B.EXAMPLE_BLOB_HASH.H3
Data-Length: 34
HPPR Quickstart
This is Blob data.
Plex Example
🖧: P.EXAMPLE_PLEX_HASH.H3
Group: a-group
API: some-api
Key: our-collection/item
TAI: 1640995200:000000000
+Link: source B.EXAMPLE_BLOB_HASH.H3
X-Custom: header value
🖧: B.EXAMPLE_BLOB_HASH.H3
Data-Length: 25
This is embedded blob data.
Seal Example
🖧: S.EXAMPLE_SEAL_HASH.H3
Seal-By: V.EXAMPLE_VERIFIER.H3
Seal-Sig: EXAMPLE_SIGNATURE_B64A
🖧: P.EXAMPLE_PLEX_HASH.H3
Group: a-group
API: some-api
Key: our-collection/item
TAI: 1640995200:000000000
🖧: B.EXAMPLE_BLOB_HASH.H3
Data-Length: 22
This is signed content.
Reference Script for 011 Examples
Tags: packet, example
This script generates the examples used in
011-PACKETS-BASIC-EXAMPLE.md.
#!/bin/bash -e
blob_msg="HPPR Quickstart
HPPR packets are content-addressed using BLAKE3.
This Blob contains raw markdown data."
plex_msg="Plex
This is a plex packet with metadata and links."
seal_msg="Seal
This is a signed packet that wraps a plex packet."
#- Deterministic test-only signatures.
export _UNSAFE_VULNERABLE_HPP_HSB3_DETERMINISTIC_AUX_SEED="examples"
export HPPR_SIGNING_SECRET="&.ydejWAbshBxyrcKILG3bXkD7fU5c72LtHvLJRfzGXal.H3"
tai="1640995200:000000000"
out="./spec/011-PACKETS-BASIC-EXAMPLE.md"
#- Blob
echo -n "$blob_msg" | mkpac --blob > "$out"
blob_hash=$(head -n 1 "$out" | awk '{print $2}')
#- Plex
echo -n "$plex_msg" | mkpac \
--group a-group \
--api some-api \
--key our-collection/item \
-t "$tai" \
-H "+Link: source $blob_hash" \
-H "X-Custom: header value" \
-H "Multiple-Values: B" \
-H "Multiple-Values: A" \
>> "$out"
#- Seal
echo -n "$seal_msg" | mkpac \
--seal-with "$HPPR_SIGNING_SECRET" \
--group a-group \
--api some-api \
--key our-collection/item \
-t "$tai" \
>> "$out"Unified Resource Coordinate
Tags: packet, addressing
© R.A.Sol
HPPR supports two address forms:
- by hash:
////<hash> - by coordinate:
//<group>/<api>//<key>
Hash addresses are immutable. Coordinate addresses are time-dependent and may resolve to different packets as new packets are stored.
A versioned coordinate pins one exact packet.
Terms
- API: the application-facing protocol surface in Plex or Seal packets.
- Key: the durable record, document, object, stream, or path inside an API.
- Coordinate: a string prefixed with
//://<group>/<api>//<key>.
Coordinate Syntax
Coordinate form:
//<group>/<api>//<key>
Rules:
<group>is one path segment.<api>is one or more slash-separated non-empty segments.<key>is one or more slash-separated non-empty segments.- The first
//starts the coordinate. - The second
//separates API from Key. - The delimiter is coordinate syntax. It is not stored in the
APIorKeyheader values.
Examples:
| Coordinate | Group | API | Key |
|---|---|---|---|
//u/docs//index.html |
u |
docs |
index.html |
//lab.eu/chat/message//room-7/1 |
lab.eu |
chat/message |
room-7/1 |
//lab.eu/chat//message/room-7/1 |
lab.eu |
chat |
message/room-7/1 |
The API/Key boundary is a design choice. API names should be finite, developer-defined protocol surfaces. Key names may be unbounded, data-defined, or instance-specific.
Version Selectors
Multiple packets can share one coordinate. Add
/|/... to select a version.
- Top-coordinate: no
|, resolves to the latest packet. Example://g/a//k - Versioned-coordinate: includes type path, TAI,
and hash. Example:
//g/a//k/|/plex/<tai>/<hash>
Example
Packet:
🖧: P.EXAMPLE~HASH~EXAMPLE~HASH~EXAMPLE~HASH~EX.H3
Group: a-group
API: some-api
Key: our-collection/item
TAI: 1640995200:123000000
...
Addresses:
- Direct hash:
////P.EXAMPLE~HASH~EXAMPLE~HASH~EXAMPLE~HASH~EX.H3 - Top-coordinate:
//a-group/some-api//our-collection/item - Versioned-coordinate:
//a-group/some-api//our-collection/item/|/plex/1640995200:123000000/P.EXAMPLE~HASH~EXAMPLE~HASH~EXAMPLE~HASH~EX.H3
Get resolution
In the tables below, <key> is the Key header
value and does not end with /. The
<api> value does not end with /.
The tip is the latest packet at a coordinate.
Tie-break order is highest TAI, then highest hash.
| Path | Gets |
|---|---|
//<group>/<api>//<key> |
tip |
//<group>/<api>//<key>/ |
tip |
//<group>/<api>//<key>/| |
tip |
//<group>/<api>//<key>/|/plex |
Plex tip |
//<group>/<api>//<key>/|/plex/<tai> |
Plex tip at tai |
//<group>/<api>//<key>/|/plex/<tai>/<hash> |
exact Plex |
//<group>/<api>//<key>/|/seal |
Seal tip |
//<group>/<api>//<key>/|/seal/<verifier> |
Seal tip for signer |
//<group>/<api>//<key>/|/seal/<verifier>/<tai> |
signer Seal tip at tai |
//<group>/<api>//<key>/|/seal/<verifier>/<tai>/<hash> |
exact Seal |
List resolution
LIST operates over two trees: the API tree and the Key tree for one exact API.
| Path | Lists |
|---|---|
//<group>/ |
top-level API segments |
//<group>/<api>/ |
API child segments, plus // when Key tree exists
for exact API |
//<group>/<api>// |
Key roots for exact API |
//<group>/<api>//<key>/ |
Key children, plus |/ when present |
//<group>/<api>//<key>/|/ |
plex/ and or seal/ |
//<group>/<api>//<key>/|/plex/ |
TAIs |
//<group>/<api>//<key>/|/plex/<tai>/ |
hashes |
//<group>/<api>//<key>/|/seal/ |
signer verification values |
//<group>/<api>//<key>/|/seal/<verifier>/ |
TAIs |
//<group>/<api>//<key>/|/seal/<verifier>/<tai>/ |
hashes |
The // child in API listings is a boundary marker.
It means packets exist under the exact API and their Key roots can
be listed with //<group>/<api>//.
Parsing
Parsers MUST treat hash addressing as a separate branch before coordinate parsing.
hash-address = "////" hash-text
coordinate = "//" group "/" api "//" key [version-selector]
////<hash>is a hash address.//<group>/<api>//<key>is a coordinate.
Reject malformed coordinates including:
- missing API/Key delimiter:
//g/api/key - empty API:
//g//key - empty Key:
//g/api// - extra API/Key delimiter inside Key:
//g/api//key//extra
| is forbidden in API and Key segments, so
/|/ unambiguously starts version selection.
HPPR Command Messages
Tags: wire, command
© R.A.Sol
HPPR endpoints exchange command messages. A command service defines the command names it accepts, the request envelope it requires, and the authorization rules for each command.
A command message is a packet or packet-shaped envelope carrying:
- a command name in
API - command arguments in the Blob data or Null packet data
- service-specific identity and authorization material in the envelope
Command names that belong to HPPR itself start with
🖧, for example 🖧GET and
🖧HELLO.
Null Command Packets
The sentinel hash 0.H3 is never computed or
verified.
Use 0.H3 for:
- generic
🖧HELLOrequest and response packets - error responses
- trusted local command envelopes where a service explicitly accepts them
Null packets are never stored in repository storage.
🖧: 0.H3
[Header: value]*
Data-Length: <len>
<data>
Header rules follow 010 for format, encoding, control bytes, line endings, and line length. Differences from Plex:
- Any header name is allowed.
- Required Plex header order does not apply.
- Header count max is 512.
Data-Lengthis the final header before the blank line.- Data max is 34 MiB (32 MiB payload + 2 MiB envelope overhead).
Command Services
A command service chooses:
- the command names it accepts
- the command flows it exposes (031)
- the accepted request envelope for each flow
- the success response shape
- which commands enter a streaming result mode
- the authorization rules for each command
The HPPR Repository Service defines the standard repository command set in 041.
HELLO Command
🖧HELLO requests command-flow capabilities and
endpoint metadata.
A transport MAY deliver equivalent greeting metadata earlier in
connection setup. The 🖧HELLO command remains the
generic capability query and refresh operation when the endpoint
accepts it.
The generic Null HELLO request is:
🖧: 0.H3
API: 🖧HELLO
Data-Length: 0
HELLO response headers are defined in 032.
Errors
Generic network errors are Null packets. Data starts with one status line:
ERROR <TYPE> <detail>keeps the connection openFATAL <TYPE> <detail>closes the connection
Trusted or local endpoints MAY add
Status: ok|error|fatal as an endpoint convention.
Clients may use Status when present, but parsing the
ERROR or FATAL data prefix is the generic
error rule.
Standard generic error types:
NOT_FOUNDFORBIDDENTOO_LARGEINVALIDINTERNAL
Services MAY define additional error types and details.
Example:
🖧: 0.H3
Data-Length: 21
ERROR NOT_FOUND missing
HPPR Command Flows
Tags: wire, command-flow
© R.A.Sol
A command flow defines how an endpoint accepts HPPR command messages.
The command name says what operation is requested. The command flow says how the request is framed, what state the endpoint may rely on, and what result modes are available.
Envelope and Principal
Each command flow has an accepted request envelope. The envelope is the packet shape that carries the command and its arguments.
A service interprets the envelope to produce a command principal. The principal is the identity or capability used for authorization. The flow defines the state available to validate the envelope; the service defines what the resulting principal means.
Session Command Flow
The session command flow has connection-local state.
It uses 🖧HELLO or transport handshake metadata to
create connection-local binding state, then requires a session-bound
request envelope for every non-HELLO command.
A session flow is the right fit when:
- replay resistance depends on connection state
- a command needs an authenticated principal
- a stream command continues after its initial request packet
Message Command Flow
The message command flow accepts one complete HPPR request message and returns one complete HPPR response message. It has no connection-local session state.
A message-flow request does not rely on prior per-connection
🖧HELLO state. Message requests are replayable unless
the service’s accepted envelope adds its own replay rule.
A message flow is the right fit when:
- a public read can stand alone
- an object-capability endpoint treats possession of the endpoint as authority
- a transport such as HTTP or UDP carries one independent exchange
Result Modes
A command’s result mode describes what happens after the request envelope is accepted. The five modes below are the generic vocabulary used by command specs, including streaming commands.
Single-response packet
The endpoint reads one request packet and returns one response packet.
Most commands use this mode.
Acknowledged stream
The endpoint returns an initial success response, then keeps the connection open and writes a command-defined stream.
Repository 🖧WATCH uses this mode.
Negotiated raw packet exchange
The endpoint returns a negotiation response. Both peers then transfer raw packet bytes according to the command’s negotiated plan.
Repository 🖧EXCHANGE uses this mode.
Relay mode after response
The endpoint returns an initial success response, then treats the rest of the connection as command-defined relay bytes.
Repository 🖧STREAM_PUB uses this mode.
Relay mode without response
The endpoint accepts the request and immediately treats the connection as command-defined relay output, with no success response packet.
Repository 🖧STREAM_SUB uses this mode.
Generic Rules
- the flow’s accepted envelope defines the request shape and response mapping
- the service defines command availability
- stream commands are available only when the service and flow explicitly accept the command’s result mode
- transports such as HTTP and UDP MAY expose message flow
The HPPR Repository Service defines concrete repository envelopes and flow behavior in 042, 043, and 044.
HPPR HELLO and Endpoint Metadata
Tags: wire, command-flow, metadata
© R.A.Sol
🖧HELLO returns endpoint metadata. It tells the
client which command flow this endpoint uses, which commands are
accepted on that flow, and which other transport endpoints are
reachable.
The generic HELLO request packet is defined in 030.
HELLO Response Shape
A HELLO response is a Null packet:
🖧: 0.H3
Command-Flow: session|message
[Session-Commands: <command-entry> *( " | " <command-entry> )]*
[Message-Commands: <command-entry> *( " | " <command-entry> )]*
[Allow-Null-Command: 0|1]
[Transport: <via> [hints...]]*
[Header: value]*
Data-Length: 0
Other HELLO headers are endpoint-specific or service-specific.
The HPPR Repository Service adds repository fields such as
Session-ID, Repo-Name,
Seal-By, and PHC in 043 and 044.
Command-Flow
Command-Flow names the command execution flow
advertised by this HELLO response.
Known values:
| Flow | Meaning |
|---|---|
session |
connection-local HELLO session, session-bound non-HELLO requests |
message |
one complete request message returns one complete response message |
Rules:
Command-Flowappears at most once.- value is exactly
sessionormessage. sessionmeans connection-local session state exists and non-HELLO commands use a session-bound request envelope.messagemeans one complete request message returns one complete response message and no connection-local session binding is used.
Command Capability Headers
Command capability uses flow-specific command-list headers:
Session-Commands: 🖧GET 1 | 🖧STORE 1 | 🖧WATCH 1
Message-Commands: 🖧HELLO 1 | 🖧GET 1 | 🖧INGEST 1
Rules:
- A session-flow HELLO emits
Session-Commandsand does not needMessage-Commands. - A message-flow HELLO emits
Message-Commandsand does not needSession-Commands. - A HELLO response does not use command-list headers to describe commands on another transport endpoint. Clients query that endpoint’s own HELLO if they need exact command support there.
- Each command-list header appears zero or more times only if line splitting is needed; normal output uses one header.
- Header value is a
|separated list of command entries. - A command entry format is
<command> <version> [options...]. - Future per-command options append inside that command entry.
- Duplicate command names within the selected command list are invalid.
- Option tokens in command-list headers MUST NOT contain the exact
separator string
|. - Unknown option tokens are ignored by clients that do not understand them.
- Malformed command entries make the HELLO capability advertisement invalid.
Formal grammar:
Session-Commands = command-entry *( " | " command-entry )
Message-Commands = command-entry *( " | " command-entry )
command-entry = command-name SP version *(SP option)
version = non-empty base-10 integer
option = non-empty token without SP or the literal separator " | "
Allow-Null-Command
Allow-Null-Command is a boolean capability for
trusted local command envelopes.
Rules:
- absent means
0. Allow-Null-Commandcontrols non-HELLO Null command request packets.- Generic Null
🖧HELLOremains the discovery request for endpoints that support HELLO, even whenAllow-Null-Commandis absent or0. 1means the endpoint accepts trusted local Null command request packets for non-HELLO commands.- This capability is for local object-capability endpoints, not public network repository listeners.
Allow-Null-Commandis independent ofCommand-Flow; a local object endpoint can still run message flow.
Transport
Transport advertises reachable transport
endpoints:
Transport: tcp:4777 flow=session
Transport: quib:4776 flow=session
Transport: ws:4778 flow=session
Transport: http:4778 flow=message path=/hppr
Transport: udp:4777 flow=message
Rules:
- first token is always the via string or transport endpoint.
- following tokens are transport hints.
- known flow hints are
flow=sessionandflow=message. - HTTP path is written as
path=<absolute-path>. path=applies only to HTTP unless another transport spec defines it.- unknown hints are ignored.
- flow hints describe the command flow reachable at that transport endpoint, not the current endpoint.
- hostless transport forms are resolved against the already-known host as in 033.
Common Endpoint Headers
The following headers are common conventions. Services define whether they are required for that service.
| Header | Meaning |
|---|---|
Seal-By |
endpoint or repository verifier, or 0 when none
exists |
Format |
packet and envelope format identifier; value
H3 |
Status |
endpoint status; ok indicates success or
readiness |
Extension |
endpoint extension token; semantics are endpoint-specific |
Via Syntax
Tags: wire, transport
© R.A.Sol
A via string identifies a transport endpoint.
Grammar
Full form:
scheme+host[:port]
Bare form (auto-negotiate transport):
host[:port]
Hostless form (used in HELLO Transport headers where
host is already known):
scheme[:port]
HELLO transport header value:
via *(SP hint)
Known hints:
flow=session
flow=message
path=<absolute-path>
Unix domain socket:
unix+<absolute-path>
Schemes
| Scheme | Default port | Transport |
|---|---|---|
tcp |
4777 |
TCP plaintext |
quib |
4776 |
QUIB encrypted (036) |
ws |
4778 |
WebSocket |
udp |
4777 |
UDP datagram message flow |
http |
80 |
HTTP POST request |
auto |
4777 |
Auto-negotiate (equivalent to bare form) |
Host
Host is a hostname, IPv4 address, or bracketed IPv6 address.
IPv6 bracket form: [::1] or
[::1]:port.
Port
Port is optional. When omitted, the scheme default applies. Bare
form defaults to 4777.
Hostless Resolution
Hostless forms appear in HELLO Transport headers.
The client fills in the host from its existing connection.
Examples:
tcp— TCP on default port, same hostudp:4777— UDP on port 4777, same hostquib:4776— QUIB on port 4776, same host
HELLO Transport Hints
A Transport HELLO header starts with a via string or
transport endpoint. Any remaining space-separated tokens are hints
about that endpoint.
Known command-flow hints:
flow=session— endpoint runs session command flowflow=message— endpoint runs message command flow
HTTP path hint:
path=<absolute-path>— HTTP request path, default/hppr
path= applies only to HTTP unless another transport
spec defines it. Unknown hints are ignored. Flow hints describe the
command flow reachable at that transport endpoint, not the current
endpoint that produced the HELLO.
Examples:
Transport: tcp:4777 flow=sessionTransport: quib:4776 flow=sessionTransport: ws:4778 flow=sessionTransport: http:4778 flow=message path=/hpprTransport: udp:4777 flow=message
Display Form
The canonical display form is:
scheme+host:portwhen a scheme is sethost:portfor auto-negotiateunix+<path>for Unix sockets
Examples
| Input | Scheme | Host | Port |
|---|---|---|---|
tcp+10.0.0.1 |
tcp | 10.0.0.1 | 4777 |
tcp+10.0.0.1:9000 |
tcp | 10.0.0.1 | 9000 |
quib+1.1.1.1:4776 |
quib | 1.1.1.1 | 4776 |
udp+10.0.0.1 |
udp | 10.0.0.1 | 4777 |
http+example.com:8080 |
http | example.com | 8080 |
ws+example.com |
ws | example.com | 4778 |
auto+example.com |
auto | example.com | 4777 |
example.com |
auto | example.com | 4777 |
example.com:9000 |
auto | example.com | 9000 |
tcp:4777 |
tcp | (from context) | 4777 |
udp |
udp | (from context) | 4777 |
unix+/tmp/hppr.sock |
— | — | — |
HTTP Transport
Tags: wire, transport, message-flow
© R.A.Sol
The HTTP endpoint carries one complete HPPR request packet in one HTTP POST request and returns one complete HPPR response packet.
Via: http+host[:port] (033). Default port:
80.
Advertised in HELLO or equivalent endpoint greeting metadata as:
Transport: http:<port> flow=message path=/hppr
Protocol
POST /hppr
Content-Type: protocol/hppr
Accept: protocol/hppr
<raw HPPR request packet>
Rules:
- the default endpoint path is
/hppr - the HTTP path selects only the HPPR packet endpoint; command, auth, target, and payload remain inside the HPPR request packet
- successful HTTP parsing returns
200 OKwithContent-Type: protocol/hppr, including HPPR Null error packets for protocol-level errors - malformed HTTP uses HTTP errors such as
400,405,411,413, and415 Transfer-Encodingand chunked request bodies are not accepted- the connection closes after each response
- stream commands are not accepted
The entity media type is protocol/hppr.
Implementations must treat it as an explicit HPPR convention and
must not apply text, mail, or CRLF normalization.
Repository HTTP Message Flow
Repository HTTP is a message-flow endpoint. Its concrete request envelope and command set are defined in 044.
Repository HTTP HELLO is capability/provisioning discovery and does not create a usable session binding.
HTTP listeners are explicit. all transport binding
does not expose HTTP. A repository service advertises
Transport: http:<port> flow=message path=/hppr
only when an HTTP listener is active.
UDP Datagram Transport
Tags: wire, transport, message-flow
© R.A.Sol
UDP is a single-datagram message-flow transport for fast bounded lookups.
Via: udp+host[:port] (033). Default port:
4777.
Advertised in HELLO or equivalent endpoint greeting metadata as
Transport: udp[:port] flow=message.
Supported Commands
UDP is a stricter message-flow subset:
🖧GET🖧HEADERS
UDP returns INVALID for 🖧LIST,
🖧INGEST, 🖧STORE, and all other
commands.
Protocol
No explicit HELLO round-trip runs on UDP itself. Each exchange is one request datagram and one response datagram.
Request is one endpoint-defined message-flow request envelope (031) in a single UDP datagram.
The HPPR Repository Service envelope is defined in 044.
Response is one datagram: raw packet bytes on success, Null packet on error. Unrecoverable failures produce no response.
QUIB
Tags: wire, transport, session-flow
© R.A.Sol
HPPR QUIB transport uses a custom crypto layer instead of TLS 1.3.
Primitives:
- Key agreement: secp256k1 ECDH
- Key derivation: BLAKE3
derive_key - QUIC payload encryption: ChaCha20-Poly1305
- QUIC header protection: ChaCha20 (RFC 9001 §5.4.4 pattern)
- MAC: BLAKE3 keyed hash
No TLS, no X.509, no rust ring. Both peers must run
this crypto.
Handshake
Two-message exchange inside QUIC Initial CRYPTO frames. Both
messages travel in the Initial encryption space. After ECDH
completes, each side writes a single 0x00 confirmation
byte into Handshake CRYPTO to signal readiness, then upgrades to
Data-space keys.
Message 1 (client to server, Initial CRYPTO)
client_ephemeral_pubkey (33 bytes, SEC1 compressed secp256k1)
client_transport_parameters (variable)
Message 2 (server to client, Initial CRYPTO)
server_ephemeral_pubkey (33 bytes, SEC1 compressed secp256k1)
encrypted_hello_length (2 bytes, big-endian u16)
encrypted_hello (variable, ChaCha20-Poly1305)
server_transport_parameters (variable)
The entire Message 2 is sent in a single CRYPTO frame. The client derives the shared secret from the server’s ephemeral pubkey, then decrypts the hello and parses transport parameters in one step.
Transport parameters use QUIC transport-parameter wire encoding.
Reference implementation note: the Rust implementation uses
quinn-proto’s TransportParameters::write and
TransportParameters::read helpers for this
encoding.
Encrypted HELLO Payload
The server encrypts a HELLO payload into Message 2 using
hello_key from the key derivation XOF stream (offset
256, see Key Derivation).
Encryption uses ChaCha20-Poly1305 with a zero nonce (unique key per connection).
Plaintext is the active service’s HELLO advertisement packet. At
minimum it follows the generic HELLO metadata from 032: Command-Flow, the
selected flow-specific command-list header, optional
Transport headers, and any service-specific greeting
headers.
Because the handshake is already connection-scoped, a service MAY omit a normally explicit session header here and derive equivalent binding from the transport instead.
The HPPR Repository Service sends its HELLO response payload here
with Command-Flow: session, Repo-Name,
Seal-By, optional PHC, repeated
Transport, Session-Commands, and
Allow-Null-Command: 0, and omits
Session-ID because it derives the session id from QUIB
keying material.
The encrypted hello includes a 16-byte Poly1305 tag appended to the ciphertext.
Post-handshake stream bootstrap
QUIB keeps standard QUIC endpoint roles:
- the client initiates the connection (
connect) - the server accepts the connection (
accept)
All application streams are client-initiated. The HELLO payload is delivered during the handshake, so no server-initiated stream is needed.
- client reads the decrypted HELLO payload
- client derives any service-defined connection binding from keying material
- client opens a bidirectional stream and sends commands
- server accepts streams and dispatches commands
Reference implementation note: the Rust implementation exposes
the HELLO payload through handshake_data(), uses
accept_bi() for server streams, and uses
open_bi() for client command and auxiliary streams.
Service Session Binding
service_session_binding is 32 bytes from the key
derivation XOF stream offset 288 (see Key Derivation).
Higher-layer services MAY map this value into a connection-bound session token or other transport binding.
The HPPR Repository Service maps it to
Session-ID: Q#<b64a> and uses it in place of the
TAI-based session ids used on other transports.
The 🖧HELLO command remains available as an optional
application-level request for capabilities refresh or
service-specific status queries.
Key Agreement
shared_point = ECDH(client_ephemeral_secret, server_ephemeral_pubkey)
shared_bytes = shared_point.x (32 bytes, big-endian)
Both sides generate fresh ephemeral secp256k1 keypairs per connection.
Key Derivation
All keys for a connection are derived from the ECDH shared secret using a single BLAKE3 XOF stream:
stream = BLAKE3.derive_key_xof("hppr-🖧/quib/keys", shared_bytes)
Stream layout (368 bytes):
| Offset | Length | Name |
|---|---|---|
| 0 | 32 | hs_c2s_packet |
| 32 | 32 | hs_s2c_packet |
| 64 | 32 | hs_c2s_header |
| 96 | 32 | hs_s2c_header |
| 128 | 32 | c2s_packet |
| 160 | 32 | s2c_packet |
| 192 | 32 | c2s_header |
| 224 | 32 | s2c_header |
| 256 | 32 | hello_key |
| 288 | 32 | service_session_binding |
| 320 | 12 | hs_c2s_iv |
| 332 | 12 | hs_s2c_iv |
| 344 | 12 | c2s_iv |
| 356 | 12 | s2c_iv |
Handshake keys (hs_*) protect the Handshake packet
space. Data keys protect the 1-RTT (Data) packet space.
Each packet key has a sibling IV derived from the same XOF stream. The IV is used in nonce construction (see Payload Encryption below).
The protocol performs two key upgrades during handshake: Initial
to Handshake, then Handshake to Data. Each side writes a
0x00 confirmation byte into Handshake CRYPTO when
returning 1-RTT keys, ensuring the peer receives a Handshake-space
packet and completes the transition to Data.
Reference implementation note: quinn-proto drives these upgrades
through the write_handshake callback.
QUIC Key Update
Each direction derives 44 bytes via BLAKE3 XOF from the current packet key:
stream = BLAKE3.derive_key_xof("hppr-🖧/quib/update", current_packet_key)
next_packet_key = stream[0..32]
next_iv = stream[32..44]
Both key and IV are replaced. Header keys are not updated.
QUIC Payload Encryption
ChaCha20-Poly1305 (RFC 8439).
Nonce construction (12 bytes), following the TLS 1.3 pattern (RFC 9001 §5.3):
nonce = IV XOR (0x00000000 || BE64(packet_number))
The IV is the 12-byte sibling value derived alongside the packet key (from the XOF stream for initial/handshake/data keys, or from the key update XOF for rotated keys). The packet number is encoded as an 8-byte big-endian integer and XORed into the last 8 bytes of the IV.
Tag length: 16 bytes, appended to ciphertext.
Limits:
- Confidentiality: 2^62 QUIC packets
- Integrity: 2^36 decryption failures
QUIC Header Protection
ChaCha20 mask generation per RFC 9001 §5.4.4.
Input: 16-byte sample from encrypted payload at offset
pn_offset + 4.
counter = LE_u32(sample[0..4])
nonce = sample[4..16]
mask = ChaCha20(hp_key, counter, nonce, zeroes)[0..5]
Apply mask:
- Long headers:
header[0] ^= mask[0] & 0x0f - Short headers:
header[0] ^= mask[0] & 0x1f header[pn_offset .. pn_offset+pn_len] ^= mask[1..1+pn_len]
Sample size: 16 bytes.
Initial QUIC Keys
Before handshake completes, both peers derive identical keys from the destination connection ID using a single BLAKE3 XOF stream:
stream = BLAKE3.derive_key_xof("hppr-🖧/quib/initial", dst_cid)
Stream layout (152 bytes):
| Offset | Length | Name |
|---|---|---|
| 0 | 32 | c2s_packet |
| 32 | 32 | s2c_packet |
| 64 | 32 | c2s_header |
| 96 | 32 | s2c_header |
| 128 | 12 | c2s_iv |
| 140 | 12 | s2c_iv |
Initial keys use the same ChaCha20-Poly1305 and ChaCha20 algorithms as 1-RTT keys. Initial protection is not secret (the CID is on the wire).
Retry Integrity
Retry tags use BLAKE3 keyed MAC with a fixed public key, truncated to 16 bytes.
tag = BLAKE3.keyed_hash(RETRY_KEY, len(orig_dst_cid) || orig_dst_cid || retry_pseudo_packet)[..16]
RETRY_KEY is a fixed 32-byte constant compiled into
both peers:
8a 3f c1 7b 52 e6 d9 04 ab 1e 73 f0 28 95 dc 46
b3 67 0a 5d e4 89 f1 3c 7e b2 05 6f d8 a1 43 97
This mirrors RFC 9001’s public retry integrity key. The tag is tamper-detection, not a secret.
HMAC
BLAKE3 keyed hash with 32-byte output.
mac = BLAKE3.keyed_hash(key, data)
Verification compares all 32 bytes.
Token Encryption
Address validation tokens use per-token derived ChaCha20-Poly1305.
Key derivation:
aead_key = BLAKE3.derive_key("hppr-🖧/quib/token-aead", master_key || random_bytes)
Seal and open use a zero nonce. Each token has a unique derived key, making nonce reuse impossible.
Export Keying Material
output = BLAKE3.derive_key(label, shared_bytes || context)
label is interpreted as a UTF-8 string for the
BLAKE3 context parameter. Output length is variable via BLAKE3
XOF.
Peer Identity
The peer identity is the peer’s ephemeral SEC1 compressed secp256k1 public key (33 bytes).
For clients, the HELLO payload is the active service’s greeting packet. For the HPPR Repository Service this includes the repo verifier and advertised capabilities.
Reference implementation note: the Rust implementation exposes
the peer public key through peer_identity() and the
transport greeting through handshake_data().
No 0-RTT
Early data is not supported.
Reference implementation note: the Rust implementation returns
None from early_crypto.
Context Strings
All BLAKE3 derive_key / XOF context strings used by
this spec:
| Context | Use |
|---|---|
hppr-🖧/quib/keys |
XOF for all handshake/data keys, IVs, hello key, service session binding |
hppr-🖧/quib/initial |
XOF for initial keys and IVs |
hppr-🖧/quib/update |
XOF for key update (packet key + IV per direction) |
hppr-🖧/quib/token-aead |
Token AEAD key derivation |
HPPR Repository Service
Tags: repo, overview
© R.A.Sol
The HPPR Repository Service is the standard authenticated packet repository layer built on the packet and wire protocols.
hpprd is the reference daemon implementation of
these specs.
The Model
A repository stores packet versions at coordinates.
Clients send commands to retrieve, list, store, watch, replicate, and stream those packet versions. Commands arrive through a command flow. The accepted request envelope establishes a principal. The repository evaluates that principal against policy and then performs the command.
The story is:
- packet bytes prove content and signatures
- coordinates name packet versions
- command messages ask a service to do work
- command flows define how requests are accepted
- repository envelopes bind commands to principals
- Ring1 and Ring2 load identity state
- ACL maps principals and coordinates to
read,write, andlist - storage materializes the abstract packet repository
- replication, streams, admin, and joins are repository commands and conventions layered on the same model
Repository requests are interpreted in this order:
- transport receives one command message;
- command flow determines available state;
- request envelope determines principal;
- command catalog determines semantics;
- Ring1/Ring2 and ACL rules determine authorization;
- storage or streaming machinery performs the command.
Conformance Boundary
Repository service conformance covers:
- repository command semantics (041)
- authenticated request envelopes (042)
- session command flow (043)
- message command flow (044)
- repository identity text (045)
- ACL rule format, evaluation, and storage (050)
- Ring1 repository authentication (051)
- Ring2 group authentication (052)
- filesystem repository layout (060)
- replication and live streaming (080)
- bootstrap and join workflow conventions (090)
Underlying packet data is defined in 010, addressing in 020, and command-flow vocabulary in 030, 031, and 032. Higher-level data schemes are defined in 100 and 110.
Index
- 041 – Repository Commands
- 042 – Repository Request Envelopes
- 043 – Repository Session Flow
- 044 – Repository Message Flow
- 045 – Repository Identity Text
- 050 – ACL
- 051 – Ring1
- 052 – Ring2
- 060 – Filesystem Storage
- 080 – Replication and Streams
- 090 – Admin and Join
HPPR Repository Service Commands
Tags: repo, command
© R.A.Sol
The HPPR Repository Service stores packets, resolves URCs, enforces repository policy, and exposes repository commands over accepted wire endpoints.
Wire message shape, Null packets, HELLO, command flows, and errors are defined in 030, 031, and 032. Repository envelopes are defined in 042.
Security Model
HPPR validates packets at the packet layer, not the channel layer.
- markline hash proves packet bytes are unchanged
- Seal signature proves which verifier signed the packet
Repository authentication, authorization, session binding, and accepted request envelopes are service behavior.
Command Summary
| Command | Payload | Response | Result mode |
|---|---|---|---|
🖧HELLO |
none | capability advertisement | single-response packet |
🖧GET |
<urc> (020) |
full packet bytes | single-response packet |
🖧HEADERS |
<urc> |
markline + headers to blank line | single-response packet |
🖧LIST |
<urc-coordinate> |
LF-separated children, sorted | single-response packet |
🖧STORE |
complete packet bytes | LF-separated stored hashes | single-response packet |
🖧ADD |
headers, blank line, data | LF-separated stored hashes | single-response packet |
🖧WATCH |
<urc-coordinate-prefix> |
stream of +/- change events |
acknowledged stream |
🖧TIPS |
<urc-coordinate-prefix> |
LF-separated tip coordinates | single-response packet |
🖧DETACH |
hash | success response | single-response packet |
🖧AUDIT |
implementation-defined filter | audit log stream | acknowledged stream |
🖧MEMBERS |
member URC | LF-separated expanded members | single-response packet |
🖧INGEST |
full top-level Seal packet | LF-separated stored hashes | single-response packet |
🖧EXCHANGE |
NEED/HAVE lines | negotiated packet transfer | negotiated raw packet exchange |
🖧STREAM_PUB |
<coordinate-prefix> |
OK then relay input | relay mode after response |
🖧STREAM_SUB |
<coordinate-prefix> |
relay output | relay mode without response |
Flow Availability
| Command | Session | HTTP message | UDP message | Trusted local Null |
|---|---|---|---|---|
🖧HELLO |
yes | yes | no | yes |
🖧GET |
yes | yes | yes | yes |
🖧HEADERS |
yes | yes | yes | yes, if exposed |
🖧LIST |
yes | yes, when advertised | no | yes, if exposed |
🖧STORE |
yes | no | no | yes, if exposed |
🖧ADD |
yes | no | no | no |
🖧WATCH |
yes | no | no | no |
🖧TIPS |
yes | no | no | no |
🖧DETACH |
yes | no | no | no |
🖧AUDIT |
yes | no | no | no |
🖧MEMBERS |
yes | no | no | no |
🖧INGEST |
yes | yes, when advertised | no | no |
🖧EXCHANGE |
yes | no | no | no |
🖧STREAM_PUB |
yes | no | no | no |
🖧STREAM_SUB |
yes | no | no | no |
Endpoint HELLO command lists are authoritative for a concrete endpoint.
Envelope Summary
Envelope layouts are defined in 042. This table summarizes which envelope families can carry each command.
| Command | Session envelope | Message envelope | Auth source | Response type |
|---|---|---|---|---|
🖧HELLO |
initial Null, then session Seal | HTTP Null or trusted local Null | endpoint/session | HELLO Null packet |
🖧GET |
Ring1, Ring2, or anyone Seal | public message Seal, UDP message, trusted local Null | request principal or local capability | raw packet bytes |
🖧HEADERS |
Ring1, Ring2, or anyone Seal | public message Seal, UDP message, trusted local Null when exposed | request principal or local capability | packet headers |
🖧LIST |
Ring1, Ring2, or anyone Seal | public message Seal when advertised, trusted local Null when exposed | request principal or local capability | Null/command response data |
🖧STORE |
Ring1, Ring2, or anyone Seal | trusted local Null when exposed | request principal or local capability | stored hash list |
🖧ADD |
Ring1, Ring2, or anyone Seal | none | request principal | stored hash list |
🖧WATCH |
Ring1, Ring2, or anyone Seal | none | request principal | acknowledged event stream |
🖧TIPS |
Ring1, Ring2, or anyone Seal | none | request principal | tip coordinate list |
🖧DETACH |
Ring1 ring0 Seal | none | Ring1 ring0 | success response |
🖧AUDIT |
Ring1 ring0 Seal | none | Ring1 ring0 | acknowledged audit stream |
🖧MEMBERS |
Ring1, Ring2, or anyone Seal | none | request principal | expanded member list |
🖧INGEST |
Ring1, Ring2, or anyone Seal | public message Seal when advertised | submitted packet signer | stored hash list |
🖧EXCHANGE |
Ring1, Ring2, or anyone Seal | none | request principal | negotiated raw packet exchange |
🖧STREAM_PUB |
Ring1, Ring2, or anyone Seal | none | request principal per segment | relay input after OK |
🖧STREAM_SUB |
Ring1, Ring2, or anyone Seal | none | request principal | relay output without OK |
Authorization Mapping
Repository session flow applies ACL evaluation per 050:
| Command | ACL check |
|---|---|
🖧GET |
read |
🖧HEADERS |
read |
🖧LIST |
list |
🖧STORE |
write |
🖧ADD |
write |
🖧INGEST |
packet-authorized Ring2 write |
🖧WATCH |
list |
🖧TIPS |
list |
🖧DETACH |
Ring1 ring0 |
🖧AUDIT |
Ring1 ring0 |
🖧MEMBERS |
read |
Ring1 behavior is defined in 051. Ring2 behavior is defined in 052.
🖧STORE
🖧STORE payload is complete packet bytes starting
with a markline.
Repository session flow applies these rules:
- top-level Blob packets are rejected for client writes
- blob data for client writes must be wrapped in Plex or Seal so write policy can target the packet versioned coordinate
- write authorization applies to the authenticated requester and
does not require that requester to match any
Seal-Byinside the stored packet - thin packets may reference existing nested packets by hash
- request
Data-Lengthmay be up to 34 MiB
Thin packets may reference existing nested packets:
- thin Plex may reference existing Blob with
🖧: B.<hash>\n - thin Seal may reference existing Plex with
🖧: P.<hash>\n
Response data lists stored hashes from outermost to innermost:
S.seal~hash.H3
P.plex~hash.H3
B.blob~hash.H3
- storing a Seal returns 3 lines
- storing a Plex returns 2 lines (Plex, Blob)
🖧ADD
Input is LF-separated headers, blank line, optional data.
Type selection:
Seal-Bypresent: create Seal- else if any Plex header present: create Plex
- else: create Blob
Defaults:
Group: uAPI: indexKey: rootTAI: now
Seal-By selectors for packet create mode:
ring0— use the repo’s local operational ring0 signing secret; requires ring0 auth<verifier> <secret>— use an explicit inline signing pair
No other selector form is valid.
References:
🖧: B.<hash>references existing Blob🖧: P.<hash>references existing Plex
🖧WATCH
Subscribes to index changes under a coordinate prefix.
After acknowledgment, the connection delivers a stream of LF-terminated lines:
+ <versioned-coordinate>
- <versioned-coordinate>
+means the coordinate became visible in the subscribed tree-means the coordinate was removed or unindexed
WATCH delivers future changes only. To avoid missing events between subscription and initial state read, subscribe first, then read current state.
Events are filtered by list permission per 050. ACL changes to auth, member, or policy
packets take effect on active WATCH streams immediately. No
reconnect is required for ACL changes.
🖧DETACH
Payload is one hash. Removes packet from the coordinate index
only. Stored packet bytes remain in hash storage. Ring1
ring0 authorization is required.
🖧TIPS
Returns LF-separated versioned coordinates for tip packets.
Events are filtered by list permission.
🖧AUDIT
Streams audit log lines. Ring1 ring0 authorization
is required.
🖧MEMBERS
Returns expanded member list with tags. Ring2 details are defined in 052.
🖧INGEST
🖧INGEST admits a packet by the submitted packet’s
authority, not by the outer request identity.
Rules:
- payload is one complete full top-level Seal packet
- top-level Blob, Plex, Null, and thin packets are rejected
- the submitted Seal signature and hash must validate
- the submitted Plex
Groupselects the Ring2 group - submitted
Seal-Bymust be a current expanded Ring2 member for that group - Ring2 policy must grant
writeon the exact submitted Seal versioned coordinate - Ring2 non-member /
anyonefallback does not authorize INGEST - request envelope
Data-Lengthmay be up to 34 MiB
Response data lists stored hashes like 🖧STORE.
Streaming Commands
🖧EXCHANGE, 🖧STREAM_PUB, and
🖧STREAM_SUB are defined in 080.
Errors
In addition to generic error types from 030, the repository service uses:
INVALID_IDENTITYUNAUTHORIZEDHELLO_REQUIRED
HPPR Repository Request Envelopes
Tags: repo, command-flow, auth
© R.A.Sol
Repository commands arrive in envelopes. The envelope carries the command name, arguments, identity material, and any flow binding needed to authorize the command.
A repository command envelope answers three questions:
- which command is requested
- which principal is making the request
- which connection or message-flow context validates the request
Session Request Envelope
After session HELLO, repository session commands are sent as Seal
packets. API values starting with 🖧 are protocol
commands.
🖧: S.<hash>.H3
Seal-By: <client-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: <group>
API: 🖧<COMMAND>
Key: <key-with-session>
TAI: <tai>
🖧: B.<hash>.H3
Data-Length: <len>
<args>
The Key format selects the authentication
scheme:
| Scheme | Group | Key | Principal |
|---|---|---|---|
| Ring1 | repo |
<repo>/<ring1>/<session-id> |
Ring1 member or built-in anyone |
| Ring2 | <target-group> |
<repo>/<session-id> |
Ring2 group member or non-member runtime path |
| Anyone | repo |
<repo>/anyone/<session-id> |
Ring1 anyone |
Rules:
APInames the command.KeyMUST carry the current session binding.Seal-ByMUST verify the request signature.- the session flow rejects envelopes whose session binding does not match the connection.
- Ring1 identity loading is defined in 051.
- Ring2 identity loading is defined in 052.
Ring1 Session Envelope
Ring1 request form:
🖧: S.<hash>.H3
Seal-By: <member-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: repo
API: 🖧<COMMAND>
Key: <repo-name>/<ring1-name>/<session-id>
TAI: <tai>
🖧: B.<hash>.H3
Data-Length: <len>
<args>
Rules:
Groupisrepo.Keycarries repo name, Ring1 name, and HELLO session.Seal-Bymust be a configured member verifier or derived member verifier.
Anyone Session Envelope
Anyone request form:
🖧: S.<hash>.H3
Seal-By: <client-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: repo
API: 🖧<COMMAND>
Key: <repo-name>/anyone/<session-id>
TAI: <tai>
🖧: B.<hash>.H3
Data-Length: <len>
<args>
Rules:
Groupisrepo.Keycarries repo name, the built-in Ring1 nameanyone, and HELLO session.Seal-Bymust verify the request signature; membership is the built-in Ring1anyoneprincipal.
Ring2 Session Envelope
Ring2 request form:
🖧: S.<hash>.H3
Seal-By: <member-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: <target-group>
API: 🖧<COMMAND>
Key: <repo-name>/<session-id>
TAI: <tai>
🖧: B.<hash>.H3
Data-Length: <len>
<args>
Rules:
Groupis the target group, notrepo.Keycarries repo name and HELLO session.Seal-Bymust resolve to group membership, or the request follows the non-member runtime path where the repository service supports it.
Message Request Envelope
Repository message flow processes one complete request packet and returns one complete response packet. It does not create or use a connection-local session.
Non-HELLO message requests are Seal packets with the explicit public message envelope:
🖧: S.<hash>.H3
Seal-By: <ephemeral-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: repo
API: 🖧<COMMAND>
Key: message/anyone
TAI: <tai>
🖧: B.<hash>.H3
Data-Length: <len>
<args>
Rules:
GroupMUST berepo.KeyMUST be exactlymessage/anyone.- the client signs with ephemeral signing material.
- the server resolves read identity as Ring1
anyoneand appliesanyonepolicy. - TAI tolerance applies to the outer request envelope.
- no repository session binding validation applies.
- session envelopes such as
<repo>/<ring>/<session>are rejected on message flow.
Message requests are replayable by design. Use them for public reads and packet-authorized admission.
Trusted Local Null Envelope
The trusted Null command envelope is for local object-capability endpoints. It is not a public network envelope and is not accepted by ordinary repository service listeners.
Request packet form:
🖧: 0.H3
API: 🖧GET
Data-Length: <len>
<args>
Rules:
- possession of the endpoint object is the authorization capability.
APIis required exactly once and names the command.- request data is the command payload defined by the corresponding repository command.
- Blob, Plex, and Seal request envelopes are rejected by this local endpoint convention.
- Null packets are command envelopes and response envelopes only.
- Null packets are never stored as repository content.
- one request packet produces one response packet.
- streaming commands are not part of this local endpoint convention.
- ordinary repository network listeners reject non-HELLO Null command packets.
- local endpoints accept non-HELLO Null command packets only when configured as trusted object-capability endpoints; this is endpoint behavior, not a client-supplied HELLO option.
Response shape:
🖧HELLOreturns a Null HELLO packet.🖧GETsuccess returns raw Blob, Plex, or Seal packet bytes.- non-GET success returns a Null packet whose data is the command
response payload and whose
Statusheader isok. - errors return Null packets whose
Statusheader iserrororfataland whose data starts withERRORorFATAL. - clients may use
Statuswhen present; data-prefix parsing remains the generic error rule for Null error packets.
Trusted Null endpoint HELLO responses include:
🖧: 0.H3
Command-Flow: message
Seal-By: 0
Format: H3
Allow-Null-Command: 1
Storage-Backend: indexeddb
Schema-Version: 2
Message-Commands: 🖧HELLO 1 | 🖧GET 1 | 🖧STORE 1
Extension: store-top-level-blob
Status: ok
Data-Length: 0
Top-level Blob STORE is a local trusted-envelope
extension for browser-local chunk storage and content-addressed
caching. Repository service policy may still reject client-written
top-level Blob packets on authenticated session flow.
Command Responses
Successful session-flow responses are Seal packets signed by the repo verifier.
🖧: S.<hash>.H3
Seal-By: <repo-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: repo
API: 🖧<COMMAND>
Key: <repo-name>/<session-id>
TAI: <response-tai>
🖧: B.<hash>.H3
Data-Length: <len>
<response-data>
Message-flow responses use the transport’s one-response mapping.
Successful repository HTTP and UDP commands return raw packet bytes
for 🖧GET and Null or command-defined response packets
for other commands. Errors are Null packets as defined in 030.
HPPR Repository Session Flow
Tags: repo, command-flow, session
© R.A.Sol
The repository session flow is the authenticated command flow for long-lived repository connections.
It extends command messages with a connection-bound HELLO state, authenticated Seal request envelopes, repository identity metadata, and ACL enforcement.
Session Lifecycle
Repository session flow requires connection-bound greeting state before ordinary authenticated commands.
- on TCP, WebSocket, and Unix-socket transports, the client sends
generic
🖧HELLOfirst and receives a repository HELLO response - on QUIB, the encrypted handshake HELLO payload carries the same
repository greeting state, and later
🖧HELLOremains available as a refresh command - a different signing secret requires a new connection and new HELLO state
Repository HELLO Response
The repository service adds service-specific headers to the generic HELLO response. TCP, WebSocket, and Unix-socket session-flow HELLO responses are Null packets:
🖧: 0.H3
Command-Flow: session
Session-ID: <session-id>
Repo-Name: <repo-name>
Seal-By: <repo-verifier>
[PHC: $argon2id$v=19$m=<m>,t=<t>,p=<p>$]
Format: H3
[Transport: <via> [hints...]]*
Session-Commands: 🖧HELLO 1 | 🖧GET 1 | 🖧HEADERS 1 | 🖧LIST 1 | 🖧STORE 1 | 🖧ADD 1 | 🖧WATCH 1 | 🖧TIPS 1 | 🖧DETACH 1 | 🖧AUDIT 1 | 🖧MEMBERS 1 | 🖧INGEST 1 | 🖧EXCHANGE 1 | 🖧STREAM_PUB 1 | 🖧STREAM_SUB 1
Allow-Null-Command: 0
Limit: max-header-line 1024
Limit: max-extra-headers 512
Status: ok
Uptime: <seconds>
[Hpprd-Version: <version>]
Hpprd-Backend: <backend>
Data-Length: 0
QUIB carries a Null HELLO payload in the encrypted transport handshake instead of requiring a HELLO round trip. That handshake payload contains only the shared capability headers:
🖧: 0.H3
Command-Flow: session
Repo-Name: <repo-name>
Seal-By: <repo-verifier>
[PHC: $argon2id$v=19$m=<m>,t=<t>,p=<p>$]
Format: H3
[Transport: <via> [hints...]]*
Session-Commands: 🖧HELLO 1 | 🖧GET 1 | 🖧HEADERS 1 | 🖧LIST 1 | 🖧STORE 1 | 🖧ADD 1 | 🖧WATCH 1 | 🖧TIPS 1 | 🖧DETACH 1 | 🖧AUDIT 1 | 🖧MEMBERS 1 | 🖧INGEST 1 | 🖧EXCHANGE 1 | 🖧STREAM_PUB 1 | 🖧STREAM_SUB 1
Allow-Null-Command: 0
Data-Length: 0
Additional header meanings:
| Header | Status | Meaning |
|---|---|---|
Command-Flow |
required | session for repository session flow |
Session-ID |
required in session HELLO, absent from QUIB handshake payload | Connection-bound repository session token |
Repo-Name |
required | Repository identifier. Default is localhost |
Seal-By |
required | Repo verifier derived from the local operational ring0 signing
secret, or 0 before bootstrap |
PHC |
optional | Argon2id parameters for Ring1 token derivation; clients use defaults when absent |
Format |
required | Packet and envelope format identifier; value
H3 |
Session-Commands |
repeated | Session-flow command list from 032 |
Allow-Null-Command |
required | 0 for repository session flow; non-HELLO Null
commands are not accepted |
Transport |
repeated | Advertised transport via string plus endpoint hints |
Limit |
implementation extension | Repo limits as <name> <value> |
Status |
implementation extension | Daemon status; ok indicates readiness |
Uptime |
implementation extension | Daemon uptime in seconds |
Hpprd-Version |
optional implementation extension | Daemon build/version string |
Hpprd-Backend |
implementation extension | Storage backend name |
On QUIB, the repository service derives Session-ID
from transport keying material and formats it as
Q#<b64a>. The derived value is connection state,
not a header in the handshake payload. On TCP, WebSocket, and
Unix-socket transports, the repository service uses a
repository-generated TAI session id and sends it as
Session-ID.
Authenticated HELLO
After initial greeting, an authenticated 🖧HELLO
request returns the same session HELLO Null response shape and
refreshes endpoint status and capabilities. No ACL check is applied.
Any authenticated identity may send 🖧HELLO.
Repo Identity
The repository’s verifier is stored at:
//repo/admin/identity//root/|
It is a self-signed Seal. Repo-Name in that identity
is returned in HELLO.
Accepted Envelopes and Responses
Session flow accepts the Ring1, Ring2, and anyone session envelopes defined in 042. Non-HELLO Null command packets and public message envelopes are rejected on repository session listeners.
Successful session responses are Seal packets signed by the repo verifier, also defined in 042.
Command Authorization
Repository commands require authentication on session flow and are subject to ACL evaluation per 050. Command semantics and authorization mapping are defined in 041.
Repository Errors
In addition to the generic error types from 030, the repository service uses:
INVALID_IDENTITYUNAUTHORIZEDHELLO_REQUIRED
HPPR Repository Message Flow
Tags: repo, command-flow, message
© R.A.Sol
Repository message flow processes one complete request packet and returns one complete response packet. It does not create or use a connection-local session.
Message requests are replayable by design. Use them for public reads and packet-authorized admission.
Accepted Envelopes
Non-HELLO message requests use the public message Seal envelope defined in 042:
Group: repo
API: 🖧<COMMAND>
Key: message/anyone
The server resolves read identity as Ring1 anyone
and applies anyone policy. Session envelopes and
trusted local Null command envelopes are rejected on repository
message-flow listeners.
HTTP /hppr
HTTP is a repository message-flow endpoint. The request body is one complete HPPR request packet and the response body is one complete HPPR response packet. HTTP transport behavior is defined in 034.
Default commands:
🖧HELLO🖧GET🖧HEADERS🖧LIST🖧INGEST
🖧STORE, 🖧ADD, 🖧DETACH,
🖧TIPS, 🖧MEMBERS, 🖧EXCHANGE,
🖧WATCH, 🖧AUDIT, 🖧STREAM_PUB,
and 🖧STREAM_SUB are not accepted on the default HTTP
message flow.
HTTP HELLO advertises endpoint-specific commands and includes these metadata headers:
🖧: 0.H3
Command-Flow: message
Repo-Name: <repo-name>
Seal-By: <repo-verifier>
Format: H3
Transport: tcp:4777 flow=session
Transport: quib:4776 flow=session
Transport: http:4778 flow=message path=/hppr
Message-Commands: 🖧HELLO 1 | 🖧GET 1 | 🖧HEADERS 1 | 🖧LIST 1 | 🖧INGEST 1
Allow-Null-Command: 0
Status: ok
Data-Length: 0
Repository message flow uses the public message Seal envelope for non-HELLO commands. It does not accept trusted local Null command envelopes.
UDP
Repository UDP is a stricter datagram message-flow subset. UDP transport behavior is defined in 035.
UDP accepts only:
🖧GET🖧HEADERS
UDP does not accept 🖧HELLO, 🖧LIST,
🖧INGEST, 🖧STORE, or stream commands. Other
HELLO responses advertise it as:
Transport: udp:<port> flow=message
Oversized responses return TOO_LARGE when
possible.
Flow-specific Command Notes
Command semantics are defined in 041. 🖧INGEST
uses the submitted packet signer as authority; Ring2 validation
rules are specified in 052.
🖧STORE remains session flow only because STORE
authorizes the request principal rather than the submitted packet
signer.
Repository Identity Text
Tags: repo, auth, client
© R.A.Sol
Repository clients use identity text to select request authentication in CLI flags, SDKs, and local route-auth records.
This grammar is repository-service-specific. It is not generic HPPR packet syntax.
Forms
anyonering1:<name>|<password>ring1:<name>|&.<b64a>.H3ring2:<group>|&.<b64a>.H3ring2:<group>/<user>|<password>ring2:/<user>|<password>
Rules:
- split on the first
| anyoneselects the Ring1anyoneidentityring1:<name>|<password>derives Ring1 signing material from a password using repository HELLOPHCring1:<name>|&.<b64a>.H3uses explicit Ring1 signing secret materialring2:<group>|&.<b64a>.H3uses explicit Ring2 signing secret materialring2:<group>/<user>|<password>derives a Ring2 member verifier and signing secret locallyring2:/<user>|<password>is contextual input only; it resolves the group from request context
Local route-auth records SHOULD store non-contextual explicit identities. Local route-auth records SHOULD store operational signing-secret form rather than raw password form.
Ring1 password derivation is defined in 051. Ring2 adhoc member verifier derivation is defined in 052.
HPPR Repository Access Control
Tags: repo, auth, policy
© R.A.Sol
ACL rules are defined per repository identity.
Each rule targets a coordinate prefix and controls three operations:
readwritelist
Rule evaluation uses longest-prefix match with per-operation inheritance.
Operations
read: fetch packet data- commands:
🖧GET,🖧HEADERS,🖧MEMBERS
- commands:
write: store or mutate repository state- commands:
🖧STORE,🖧ADD,🖧DETACH
- commands:
list: enumerate or subscribe to coordinate trees- commands:
🖧LIST,🖧WATCH,🖧TIPS
- commands:
Rule Format
Rule syntax:
<ops> <coordinate-prefix>
<ops> is exactly three characters:
[r|d|.][w|d|.][l|d|.]
Meaning:
r,w,l: explicit allow for that operationd: explicit deny for that operation.: inherit from the next-longest matching rule
Examples:
ACL-Rule: rwl //u/chess//
ACL-Rule: r.l //u/mail//
ACL-Rule: rdl //u/market//
ACL-Rule: .w. //u/market//nl/eindhoven/
Common patterns:
rwl: full accessr.l: read and list, inherit writeddd: deny allrwd: read and write, deny list
Prefix Forms
ACL prefixes are parsed coordinates or coordinate-tree prefixes. They are not raw string prefixes. Matching compares group, API segments, the API/Key boundary, Key segments, and version-selector components as coordinate tree components.
Common forms:
| Prefix | Meaning |
|---|---|
//g/ |
all APIs in group g |
//g/chat/ |
API subtree under chat |
//g/chat// |
all Keys in exact API chat |
//g/chat//rooms/ |
Key subtree under rooms |
//g/chat//rooms/7/| |
exact Key version root |
//g/chat//x does not match
//g/chatty//x. //g/a//b does not match
//g/a/b//c.
Rule Ordering
Rules MUST be stored in canonical sorted order.
Sort by parsed coordinate-prefix components:
- group
- API segments
- API/Key boundary marker
- Key segments
- version selector components
Within each component list, sort bytewise by UTF-8 bytes. A version boundary sorts before a child segment at the same Key.
Resolution
Given a request coordinate:
- Parse the request coordinate.
- Find the longest matching parsed rule prefix.
- For each operation, apply explicit allow or deny when present.
- For
.values, continue to the next-longest matching rule. - If no explicit decision is found, deny.
For read and write checks, evaluate against the packet versioned coordinate.
Prefix examples:
| Prefix | Matches |
|---|---|
//u/a//README.md/| |
exact README.md Key version root |
//u/a//README.md/ |
README.md and children |
//u/a//README.md |
also README.md-draft |
Policy Storage
Rules are stored as ACL-Rule headers in policy
packets.
Policy coordinate depends on identity scheme:
- Ring1 (051-RING1.md):
//repo/admin/ring1//<name>/policy/|
- Ring2 (052-RING2.md):
//<group>/admin/ring2//policy/|/seal/<repo-verifier>
Policy packets carry only ACL-Rule headers.
Auth-config headers and member headers are invalid in policy
packets.
HPPR Ring1 Repository Authentication
Tags: repo, auth
© R.A.Sol
Ring1 is the repository-auth scheme. Ring1 requests are Seals signed by a Ring1 member verifier and carried in the Ring1 session envelope defined in 042.
The signing secret can be derived from a password or set up explicitly.
Request Envelope
Ring1 uses:
Group: repo
API: 🖧<COMMAND>
Key: <repo-name>/<ring1-name>/<session-id>
Seal-By: <member-verifier>
Rules:
Groupisrepo.APInames the protocol command.Keycarries repo name, Ring1 name, and HELLO session.Seal-Bymust be a configured member verifier or derived member verifier.
Built-in Ring1 Names
Two names are repository-service built-ins:
ring0: full repository access, ACL bypassanyone: unauthenticated fallback ACL identity
Built-in existence is repository-service behavior. Policy for both built-ins lives in policy packets. Other Ring1 names are configured through the packet families below.
Ring1-Name constraints for any name:
- max 128 bytes
- must match one Key segment
- must not contain
/ { } | - must not equal
.or..
Packet Families
Ring1 auth, membership, and policy are in separate packet families. All three are signed by the repo verifier.
All Ring1 packet families use:
Group: repo- API:
admin/ring1 - Key prefix:
<name>/...
Auth Config
Coordinate:
//repo/admin/ring1//<name>/auth/|
Required:
Ring1-Name— must match coordinate<name>, appears exactly once
Optional:
Ring1-Secret-Token— appears at most onceRing1-Expire— appears at most once
Validation:
Memberheaders are invalid hereACL-Ruleheaders are invalid here
Members
Coordinate:
//repo/admin/ring1//<name>/members/|/seal/<repo-verifier>
Required:
Member(repeatable) — at least one required
Validation:
ACL-Ruleheaders are invalid here- Auth-config headers (
Ring1-Name,Ring1-Secret-Token,Ring1-Expire) are invalid here
Member carries a verifier. Password-derived
membership uses Ring1-Secret-Token from the auth config
packet for derivation parameters.
Policy
Coordinate:
//repo/admin/ring1//<name>/policy/|
Required:
ACL-Rule(repeatable) — at least one required
Validation:
Memberheaders are invalid here- Auth-config headers are invalid here
ACL-Rule format and evaluation are defined in 050.
Operational Signing Material
The repo-owned signing secret lives in local operational storage, not in a canonical auth packet family.
The public repo verifier is derived from that local signing
secret and maintained in
//repo/admin/identity//root/|.
Auth, member, and policy packets are signed by the repo verifier. They do not carry secret material and are not the canonical source of repo signing-secret state.
Secret Token Derivation
Ring1-Secret-Token format:
<derived-token> <original-secret>
Split on first ASCII space.
- left side:
V.<b64a>.H3 - right side: original secret, may contain spaces
Client derives <derived-token> using Argon2id
with HELLO PHC. Repo does not recompute Argon2id. Repo
uses <derived-token> directly.
Argon2id:
- password: UTF-8 original secret
- salt: first 16 bytes of
BLAKE3.derive_key("hppr-🖧/phc-salt", "<ring1>/<repo-verifier>") - output length: 32 bytes
Then HSB3 signing secret derivation input is:
<derived-token>/<ring1-name>/<repo-verifier>
Pre-ACL Defaults
These apply before policy-packet evaluation and are final. They are repository-service runtime code, not packets.
ddd //repo/admin/ring1//ring0/dwd //repo/admin/request//join/rd. //repo/admin/ring1//rd. //repo/admin/identity//rootr.. //<group>/admin/members//root/|
Request/reply provisional access for join workflows is also runtime code, not packetized auth state.
Watch/Reload Trigger Map
| Packet coordinate | Effect |
|---|---|
//repo/admin/identity//root/| |
refresh repo identity; refresh repo verifier view |
//repo/admin/ring1//<name>/auth/| |
reload Ring1 auth-config cache for
<name> |
//repo/admin/ring1//<name>/members/|/seal/<repo-verifier> |
reload Ring1 membership/auth cache for
<name> |
//repo/admin/ring1//<name>/policy/| |
reload ACL snapshot; apply ACL changes to active WATCH streams |
Load and Evaluation Order
- parse the repository request envelope
- read auth config from
//repo/admin/ring1//<name>/auth/| - resolve membership from
//repo/admin/ring1//<name>/members/|/seal/<repo-verifier> - derive or verify member verifier; produce authenticated principal or reject
- load policy from
//repo/admin/ring1//<name>/policy/| - evaluate
read/write/listper 050 - workflow packets under
//repo/admin/request//...are ordinary stored packets subject to policy, not auth-config state
Ring1-only Commands
These commands require Ring1 ring0
authentication:
🖧DETACH🖧AUDIT
🖧ADD may use Seal-By: ring0 packet
creation mode only with Ring1 ring0 authentication.
Command details are defined in 041.
Errors
Common Ring1 failures:
HELLO_REQUIREDUNAUTHORIZED invalid signatureUNAUTHORIZED not a memberNOT_FOUND ring1NOT_FOUND inner packetINVALID configINVALID sessionUNAUTHORIZED ring1
Security
Ring1 expects encrypted transport for confidentiality. Replay
resistance uses HELLO-bound session IDs in request
Key.
HPPR Ring2 Group Authentication
Tags: repo, auth
© R.A.Sol
Ring2 is group-based authentication. Signer authorization is based on membership in the target group. Ring2 requests use the Ring2 session envelope defined in 042.
Request Envelope
Ring2 uses:
Group: <target-group>
API: 🖧<COMMAND>
Key: <repo-name>/<session-id>
Seal-By: <member-verifier>
Rules:
Groupis the target group, notrepo.APInames the protocol command.Keycarries repo name and HELLO session.Seal-Bymust resolve to group membership.- non-members follow a distinct runtime identity path where
command semantics permit unauthenticated fallback; that path
evaluates under
anyonepolicy.
Packet Families
Ring2 auth, membership, and policy are in separate packet families.
Auth Config
Coordinate:
//<group>/admin/ring2//auth/|/seal/<repo-verifier>
Signed by repo verifier.
Required:
Ring2-Name— must match coordinate<group>, appears exactly once
Optional:
Ring2-Expire— appears at most once
Validation:
- coordinate
<group>must matchRing2-Name Memberheaders are invalid hereMember-Delegateheaders are invalid hereACL-Ruleheaders are invalid here
Members
Coordinate:
//<group>/admin/members//root/|/seal/<verifier>
Multiple packets may exist under different signers and versions.
Required (at least one of):
Member(repeatable)Member-Delegate(repeatable)
Validation:
- at least one
MemberorMember-Delegateheader required ACL-Ruleheaders are invalid here- auth-config headers (
Ring2-Name,Ring2-Expire) are invalid here
Policy
Coordinate:
//<group>/admin/ring2//policy/|/seal/<repo-verifier>
Signed by repo verifier.
Required:
ACL-Rule(repeatable) — at least one required
Validation:
Memberheaders are invalid hereMember-Delegateheaders are invalid here- auth-config headers are invalid here
ACL-Rule format and evaluation are defined in 050. Each ACL-Rule coordinate
must start with //<group>/.
Adhoc Member Verifiers
Clients MAY derive a Ring2 member verifier locally from:
- group
- username
- password
Rules:
- username MUST satisfy one
Keysegment’s constraints - derivation is fully client-local and does not depend on HELLO
- repo MUST NOT receive or store the password
- identity text form is
ring2:<group>/<username>|<password> - parser split rule is first
| - derivation input bytes are exactly
<group>/<username>|<password> - Argon2id uses fixed built-in client parameters:
m=12288,t=3,p=1 - Argon2id salt is the first 16 bytes of
BLAKE3.derive_key("hppr-🖧/ring2-phc-salt", "<group>/<username>|<password>") - Argon2id output is encoded as
V.<b64a>.H3 - signing secret derivation input is:
<derived-token>/<group>/<username>|<password> - the resulting verifier is stored as an ordinary
Member
Contextual form:
ring2:/<username>|<password>resolves group from request context- derivation input bytes are exactly
<resolved-group>/<username>|<password> - text form with empty group is reserved for this convention
This is a client-side derivation convention only. Server behavior is unchanged.
Membership Config Detail
Supported headers in member packets:
Member
Adds one member verifier plus optional tags.
Member: <verifier> [<tags>...]
Member-Delegate
Delegates membership from another config source. Pipe separator
| is required.
Member-Delegate: [<group>]|[<verifier>[/<tai>/<hash>]] [<mods>...]
Defaults:
- omitted group means current group
- omitted verifier means signer of current packet
Pinned form:
<verifier>/<tai>/<hash>pins to exact member packet version
Modifier:
dynamicfollows unpinned delegates
Tag modifiers:
*: inherit all tags+tag: inherit tag if presenttag: grant tag!tag: deny tag
Traversal is depth-first with max depth 8.
Watch/Reload Trigger Map
| Packet coordinate | Effect |
|---|---|
//<group>/admin/ring2//auth/|/seal/<repo-verifier> |
reload Ring2 auth-config cache for
<group> |
//<group>/admin/members//root/|/seal/<verifier> |
reload group membership cache; revalidate active Ring2 WATCH subscribers for that group |
//<group>/admin/ring2//policy/|/seal/<repo-verifier> |
reload ACL snapshot; apply ACL changes to active WATCH streams |
Load and Evaluation Order
- parse the repository request envelope
- read auth config from
//<group>/admin/ring2//auth/|/seal/<repo-verifier> - resolve membership from
//<group>/admin/members//root/|/seal/<verifier> - verify member verifier; produce authenticated principal or enter non-member runtime path
- load policy from
//<group>/admin/ring2//policy/|/seal/<repo-verifier> - evaluate
read/write/listper 050 - workflow packets under
//<group>/admin/request//...are ordinary stored packets subject to policy, not auth-config state
🖧INGEST Ring2
Admission
🖧INGEST uses the submitted Seal’s signer as packet
authority.
Validation:
- Payload must be a complete full top-level Seal.
- The embedded Plex
Groupselects the Ring2 group. - The submitted Seal
Seal-Bymust resolve through currentMember/Member-Delegateexpansion for that group. - The Ring2 auth config must exist, be valid, and not be expired.
- The Ring2 policy must grant
writeon the exact submitted Seal coordinate://<group>/<api>//<key>/|/seal/<seal-by>/<tai>/<seal-hash>.
Ring2 INGEST never uses the non-member runtime path
and never falls back to Ring1 anyone ACL rules. A
non-member signer is rejected even if public anyone
policy would allow writing the target coordinate.
🖧MEMBERS
Returns expanded member list with tags.
Payload is a // URC.
Shorthand:
//<group>expands to//<group>/admin/members//root/|/seal/<repo-verifier>
Response:
- LF-separated lines:
<verifier> [<tags>...] - sorted by verifier
WATCH
WATCH events are filtered by list permission per 050. ACL changes to group auth, member, or
policy packets take effect on active streams immediately. No
reconnect needed.
Errors
Common Ring2 failures:
HELLO_REQUIREDUNAUTHORIZED invalid signatureUNAUTHORIZED not a memberNOT_FOUND ring2 configINVALID configINVALID sessionUNAUTHORIZED ring2
Filesystem Repository
Tags: repo, storage
© R.A.Sol
This spec defines filesystem storage for HPPR packets.
It follows packet rules in 010-PACKETS.md and
address rules in 020-URC.md.
Repository Layout
repo/
├── hash/<Type>/<hh>/<tail>.H3
├── ref/B/<hh>/<tail>/...
├── ref/P/<hh>/<tail>/...
├── index/<group>/<api...>/||/<key...>/|/...
├── detach/<hash>
└── .tmp/
hash/: packet storage by typeB,P,Sref/: back-reference treesindex/: coordinate indexdetach/: detached hashes.tmp/: atomic write staging
Filesystem requirements:
- MUST be case-sensitive
- MUST support UTF-8 names except
/and NUL - MUST support
|in path names - implementation MUST refuse startup if unsupported
Hash Storage (hash/)
Path form:
hash/<T>/<hh>/<tail>.H3
Where:
<T>isB,P, orS<hh>is first two B64A digest chars<tail>is remaining digest chars
Storage format:
- Blob (
B): raw content bytes only - Plex (
P): thin format - Seal (
S): thin format
Blob file size defines Data-Length during
reconstruction.
Index Storage
(index/)
Coordinate syntax uses
//<group>/<api>//<key>. Filesystem
storage does not store the second // as an empty path
component. It maps the API/Key boundary to ||, which is
forbidden in API and Key segments because | is
forbidden.
Plex path:
index/<group>/<api...>/||/<key...>/|/plex/<tai>/<hash>
Seal path:
index/<group>/<api...>/||/<key...>/|/seal/<verifier>/<tai>/<hash>
Examples:
| Coordinate | Index prefix |
|---|---|
//u/a//b/c |
index/u/a/||/b/c/|/ |
//u/a/b//c |
index/u/a/b/||/c/|/ |
//u/a//seal |
index/u/a/||/seal/|/ |
Rules:
- marker files are zero-byte
- filename/path encodes identity and version
<api...>is the API header value split on/<key...>is the Key header value split on/<tai>usesseconds:subsecondsform||is the filesystem API/Key boundary only|is the filesystem version-selector boundary
LIST Mapping
LIST over the API tree reads children before ||.
| LIST target | Filesystem view |
|---|---|
//<group>/ |
children of index/<group>/ |
//<group>/<api>/ |
children of index/<group>/<api...>/
before || |
//<group>/<api>// |
children of
index/<group>/<api...>/||/ |
//<group>/<api>//<key>/ |
children of
index/<group>/<api...>/||/<key...>/
before | |
//<group>/<api>//<key>/|/ |
children of
index/<group>/<api...>/||/<key...>/|/ |
When an exact API has a Key tree, LIST of that API prefix
includes // as the API/Key boundary marker. When an
exact Key has versions, LIST of that Key prefix includes
|/ as the version boundary marker.
The filesystem names || and | are not
returned directly by LIST except as these coordinate markers.
Back-Reference Storage
(ref/)
Blob to Plex references:
ref/B/<hh>/<tail>/<plex-hash>
Plex to Seal references:
ref/P/<hh>/<tail>/<seal-hash>/<verifier>
These support reverse traversal from inner to outer packet.
Store Flow
- Write Blob raw bytes to
hash/B/.... - For Plex:
- write thin Plex to
hash/P/... - add
index/.../|/plex/<tai>/<hash> - add
ref/B/.../<plex-hash>
- write thin Plex to
- For Seal:
- write thin Seal to
hash/S/... - ensure embedded Plex and Blob exist
- add
index/.../|/seal/<verifier>/<tai>/<seal-hash> - add embedded Plex index entry
- add
ref/B/.../<plex-hash>andref/P/.../<seal-hash>/<verifier>
- write thin Seal to
Duplicates SHOULD succeed as idempotent writes. Use
.tmp/ plus atomic rename for final placement.
Detach Cleanup
When detaching Plex or Seal:
- remove index entries
- remove matching
ref/B/.../<plex-hash> - if that
ref/B/...directory becomes empty, record blob hash indetach/ - never detach the empty-blob constant hash
Reconstruction
- Blob: synthesize markline and
Data-Lengthfrom file size + raw bytes. - Plex/Seal: resolve embedded hashes from
hash/and rebuild full packet.
Hash verification requires full reconstructed packet bytes.
Tip Tracking
Tip links are required materialized state for the filesystem
repository storage profile. They live under
index/.../|/.
Required tip links:
- top tip:
|/tip - plex tip:
|/plex/tip - seal type tip:
|/seal/tip - per-signer seal tip:
|/seal/<verifier>/tip
Tip update rule:
- compare
(tai, hash)lexicographically - newer value replaces existing link target
Tip Recovery
If a tip link is missing while version directories exist, implementation MUST:
- scan affected
|/plex/and|/seal/once - recompute latest entries
- recreate missing tips
If scan finds no packets, empty |/ structure SHOULD
be cleaned up.
After detach, recompute tip links for the affected coordinate.
Portability
- Atomic rename is required.
- If filesystem lacks symlinks, emulate tip links with files.
- Emulated tip links MUST be hidden from
🖧LISTexactly as symlinks are.
HPPR Packet Links and Chunks
Tags: packet, content-convention
© R.A.Sol
This spec defines packet-level content conventions that are independent of any repository service.
+Link Header
Generic form:
+Link: <tag> <hash>
Common tags:
request: this packet replies to that requestsupersedes: this packet replaces older version
Typed links are headers named [Type]+Link. Tools
should scan header names containing +Link.
Hash links form a DAG. Cycles are impossible because packet hash includes all header bytes.
Chunked Content Convention
Large content can be split into chunk blobs with a manifest packet.
Manifest detection:
- has one or more
Chunk+Linkheaders - has
Data-Length: 0
Syntax:
Chunk+Link: <start>..<end> <T>.<hash>.H3
- range is half-open: start inclusive, end exclusive
T=B: raw blob chunkT=P: nested chunk manifest
Required header:
Content-Total-Length: <n>
Optional headers:
Content-TypeContent-Hash-Full: B.<hash>.H3
Validation:
- chunk ranges contiguous
- no overlap
- total span exactly
0..<Content-Total-Length>
Nested manifests use 0-relative ranges in each sub-manifest. Depth limit is 8.
Default chunk size is 32 MiB. Smaller chunks improve random access and increase overhead.
HPPR Replication and Streams
Tags: repo, command, streaming
© R.A.Sol
Repository replication and live streams are repository commands with streaming result modes from 031.
🖧EXCHANGEuses negotiated raw packet exchange🖧STREAM_PUBuses relay mode after response🖧STREAM_SUBuses relay mode without response
🖧EXCHANGE
🖧EXCHANGE synchronizes packets while preserving
repository policy decisions. It has three phases:
- announce
- transfer
- finalize
Phase 1: Announce
Requester sends up to 1024 LF-separated lines:
NEED <versioned-coordinate>
HAVE <versioned-coordinate>
Responder returns FIN or PENDING
followed by status lines:
SEND <coord>
DENY <coord>
RECV <coord>
HAVE <coord>
Status meanings:
SEND: responder will send this packetDENY: denied by repository policyRECV: responder wants this packet from requesterHAVE: responder already has this packet
Phase 2: Transfer
Both peers stream raw packets concurrently in both directions.
Implementations MUST perform bidirectional I/O concurrently. Unidirectional blocking can deadlock the exchange.
Packet boundaries are parsed using Data-Length.
Phase 3: Finalize
When Phase 1 returned PENDING, the responder reports
final results for the coordinates that entered Phase 2 transfer
(SEND and RECV items):
FIN
OK <coord>
FAIL <coord> <type> <msg>
Phase 1 HAVE and DENY items are already
terminal negotiation results and do not appear in Phase 3.
OK means the Phase 2 action for that coordinate
completed: for SEND, the responder wrote the packet
bytes; for RECV, the responder received, validated, and
stored the matching packet. FAIL is only used for
receive/store failures after a RECV, for example
invalid received packet, coordinate mismatch, hash mismatch, storage
failure, or stream EOF before the expected packet arrived.
A responder MUST NOT skip a packet promised by Phase 1
SEND and report that missing packet as Phase 3
FAIL. Clients count exact raw Phase 2 packets after
SEND; a missing raw packet would make the Phase 3
response packet ambiguous. If a responder cannot write a promised
SEND packet, it MUST fail the exchange at the
connection level, for example with a FATAL error or close.
Repository Authorization in Phase 1
Authorization for NEED and HAVE is
repository-service behavior.
The HPPR Repository Service applies the following ACL rules in Phase 1.
For NEED <coord>:
- check
read - if readable and exists:
SEND - else:
DENY
For HAVE <coord>:
- check
read - if denied:
DENY - if allowed and exists:
HAVE - if missing, check
write - if writable:
RECV - else:
DENY
Blob-Addressed
🖧EXCHANGE
🖧EXCHANGE also accepts blob hash addressing:
NEED ////B.<hash>.H3
HAVE ////B.<hash>.H3
Rules:
- only
B.hashes are valid P.andS.in blob-addressed mode are FATAL invalid requests- additional authorization rules are service-specific
- the HPPR Repository Service applies no ACL checks in this mode
- the HPPR Repository Service allows any authenticated session to request blob hash sync
Decision rules:
NEED: blob exists =>SEND, elseDENYHAVE: blob exists =>HAVE, elseRECV
Transfer still uses full raw blob packets.
🖧STREAM_PUB
🖧STREAM_PUB ingests live trailer-format Seal
segments.
Request:
API: 🖧STREAM_PUB- data:
<coordinate-prefix>
Response:
- sealed
OK
After OK, connection enters relay mode and accepts
trailer segments.
Per segment:
- relay bytes to matching
🖧STREAM_SUBsubscribers - detect segment close marker
- verify hash and signature
- store packet
- emit
🖧WATCHevent
Authorization is repository-service behavior. The HPPR Repository
Service checks write per segment at store time.
Disconnect behavior:
- publisher disconnect ends stream
- no explicit end marker required
- partial in-flight segment is discarded
- subscriber sockets are closed
No FATAL is injected into relay stream. Subscribers detect truncation via trailer parsing.
Size rule:
- each segment must respect 32 MiB blob limit
Continuity recommendation:
- include
Previous-Segment: <hash>after first segment
🖧STREAM_SUB
🖧STREAM_SUB subscribes to live trailer bytes by
prefix.
Request:
API: 🖧STREAM_SUB- data:
<coordinate-prefix>
Behavior:
- enters dedicated relay mode immediately
- no
OKresponse packet - when no active publisher exists for the prefix, subscriber waits for one
- wait uses a fixed server timeout
- on wait timeout, repo writes
FATAL NOT_FOUND wait timeoutand closes - forwards bytes from matching active publishers
Late joiners receive bytes buffered from current in-flight segment and then continue live.
Authorization is repository-service behavior. The HPPR Repository
Service checks read at subscription time.
On publisher disconnect, repo closes subscriber sockets. Mid-segment disconnect yields partial trailer data followed by EOF.
Completed segments remain available via 🖧GET and
🖧EXCHANGE.
Relay Chaining
A downstream repo can relay a live stream by:
- subscribing upstream with
🖧STREAM_SUB - publishing downstream with
🖧STREAM_PUB
HPPR Repository Admin and Join Conventions
Tags: repo, workflow
© R.A.Sol
This spec defines repository-service operational conventions: repository bootstrap, request/reply workflow, join flows, and ring0-proxy.
Content route conventions live in
100-CONTENT-ROUTES.md. Packet link and chunk
conventions live in 070-LINKS-AND-CHUNKS.md.
Bootstrap
A repository needs only the canonical packet families below to operate. Do not bootstrap convenience scaffolding or workflow placeholders.
Bootstrap sequence:
- Load or generate repo-owned signing secret in local operational storage.
- Derive repo verifier from that local signing secret.
- Write
//repo/admin/identity//root/|— self-signed Seal carryingRepo-Name. - Write Ring1
ring0auth config at://repo/admin/ring1//ring0/auth/|— signed by repo verifier;Ring1-Name: ring0 - Write Ring1
ring0members at://repo/admin/ring1//ring0/members/|/seal/<repo-verifier>— at least one initialMemberverifier (see Initial Token below) - Write Ring1
ring0policy at://repo/admin/ring1//ring0/policy/|— signed by repo verifier;ACL-Ruleheaders defining ring0 access - Write Ring1
anyoneauth config at://repo/admin/ring1//anyone/auth/|— signed by repo verifier;Ring1-Name: anyone - Write Ring1
anyonepolicy at://repo/admin/ring1//anyone/policy/|— signed by repo verifier;ACL-Ruleheaders for public/unauthenticated access
Do not bootstrap:
- Ring1 identities other than
ring0andanyone - packet families for repo signing-secret storage
- combined auth, member, and policy packets
- workflow placeholder packets
- any extra packet family not required for the repository to operate
Default anyone
Policy
ACL-Rule: .w. //repo/admin/request//join/
ACL-Rule: r.l //u/
Initial ring0 Token
The default initial ring0 member derives from token
init:
secret = "init/ring0/<repo-verifier>"
signing_secret = derive_secret_from_text(secret)
Implementations MAY accept an explicit bootstrap token at
repository creation, for example
hpprd --default-password <password> or
HPPRD_DEFAULT_PASSWORD. Packaged services that listen
on public interfaces MUST use a random explicit bootstrap token
instead of init.
Rotate the initial member to durable operator-controlled signing material after first connection.
Request/Reply Convention
Administrative request flows use:
- request queue:
//<scope>/admin/request//<kind>/... - requester reply path:
//<scope>/admin/request//<kind>/<requester>/reply/|
<kind> names the workflow. Join flows use
join.
Reply packets are expected to include:
Request-Status: approved|denied|pending+Link: request <hash>
Clients use Request-Status for state.
+Link gives exact request linkage.
Workflow packets are ordinary stored packets subject to policy. They are not auth or policy state.
Joining a Repository
Standard Ring1 join flow uses
<kind> = join:
- user watches reply path:
//repo/admin/request//join/<name>/reply/| - user writes request to:
//repo/admin/request//join/<name>/| - admin approves or denies in reply packet
- if approved, admin creates Ring1 auth config, members, and policy packets
- user derives signing material and reconnects
Provisional Access
An anyone request gets provisional read/list access
to its matching reply path:
//repo/admin/request//join/<name>/reply/|
<name> must match first segment from request
Key.
This is repository-service runtime code, not a packetized permission.
Joining a Group
Ring2 join flow uses <kind> = join:
- user watches reply path:
//<group>/admin/request//join/<requester-verifier>/reply/| - user writes request to:
//<group>/admin/request//join/|/seal/<requester-verifier> - admin approves or denies in reply packet
A common client flow derives
<requester-verifier> locally from
<group>/<username>/<password> as
defined in 052-RING2.md. This works
before contacting any repo. The password remains local to the
client.
Recommended non-member join ACLs:
ACL-Rule: .w. //<group>/admin/request//join/|/seal/
ACL-Rule: r.l //<group>/admin/request//join/
Request headers:
Request-Tags(optional)
Ring0-Proxy Convention
Ring1 may request a ring0-mediated action.
Request path:
//repo/admin/ring1//<ring1-name>/🖧<COMMAND>/|
Reply path:
//repo/admin/ring1//<ring1-name>/🖧<COMMAND>/reply/|
Supported commands:
🖧LIST🖧HEADERS🖧ADD
🖧GET is excluded. Use 🖧HEADERS to
obtain hash, then fetch blob by hash.
HPPR Content Routes
Tags: scheme, route
© R.A.Sol
This spec defines route and content conventions used by higher-level schemes. They are ordinary packet families stored in repositories.
API Content Pointer Convention
Canonical API content should live under:
//u/apis/<publisher>/<api>//...
Each group publishes its API content pointer at:
//<group>/admin/deploy//<api>/|
Required headers:
Content-Root: //<...>Content-Authority: V.<...>.H3
Meaning:
Content-Rootselects the content tree for//<group>/<api>//...Content-Authorityselects the signer that authorizes that API content
Runtime intent:
- clients resolve
//<group>/<api>//...through the API content pointer - clients append the requested Key to
Content-Root - clients fetch document content from
<target>/|/seal/<Content-Authority> - clients list directory content from
<target>/
Clients follow the latest API content pointer only. When
Content-Authority changes, content signed by the
previous authority is no longer reachable through the API URL.
Group forks are supported by pointing Content-Root
to a group-owned subtree instead of the canonical
//u/apis/... tree.
Public Route Visibility Convention
Public route browsing is a convention, not a core repository-policy requirement.
For a namespace or API intended to be publicly browsable:
- the public-root repo SHOULD allow read and list access to
//u/ - a group that publishes public route records SHOULD allow read
and list access to
//<group>/route/ - a group that publishes a public API SHOULD allow read and list
access to
//<group>/admin/deploy//<api>/|
If these reads are denied, canonical public route lookup or deploy-pointer lookup fails and the namespace is not publicly browsable.
HPPR Schemes
Tags: scheme, route, name, attest
© R.A.Sol
This spec defines standard schemes that sit above the HPPR packet, wire, and repository service specs:
- public group discovery under
//u/route/group//...and//<group>/route/group//... - authority-local identity naming under
//<authority-group>/name//... - public attestation state under
//u/attest/...//...
These schemes are conventions. They use ordinary HPPR packets and ordinary repo commands.
Route discovery maps public or local route records to upstream repositories and content authorities. Authority-local names define stable identity names under a group. Attestations publish signed statements about verifiers or names.
Terms
- Public root: the provisioned public route root
under
//u/route/group// - Authority group: a group that publishes
routeornamerecords - Exact name:
<part>[.<part>...]@<authority-group> - Route-Authority-Key: stable public authority verifier for a group namespace
- Name-Key: stable continuity verifier for one exact identity name
- Current-Key: current operational verifier for one exact identity name
Common Conditional Headers
Packets defined in this spec MAY include repeated conditional headers after that packet family’s required semantic headers. A packet is valid only while all of its conditions hold.
Headers:
Condition-Route-Authority-Key: <group> <verifier>Condition-Name-Key: <name> <verifier>Condition-Current-Key: <name> <verifier>Condition-State: <state> <exact-urc>
Rules:
Condition-Route-Authority-Keypasses only while<group>still resolves toRoute-Authority-Key: <verifier>- for
<group> = u, this means<verifier>is still one of the currently provisioned trusted root route authority verifiers for the public root Condition-Name-Keypasses only while<name>still resolves toName-Key: <verifier>Condition-Current-Keypasses only while<name>still listsCurrent-Key: <verifier>Condition-Statepasses only while the packet at<exact-urc>currently has exactly oneStateheader equal to<state><exact-urc>inCondition-StateMUST contain/|<exact-urc>MAY further pin signer or version under/|/...- if the referenced packet has its own
Condition-*headers, they MUST also hold - dependency cycles MUST fail evaluation
- missing, unreadable, malformed, unsupported, or non-matching targets fail the condition
Hierarchical Public Group Route Discovery
Public group routing starts at the unnamed public root under
//u/route/group//.
The root delegates top-level labels. Each resolved authority group then delegates its own immediate child labels. API routing stays explicit at the final resolved group.
Canonical roots:
//u/route/group//...//u/route/api//...//<group>/route/group//...//<group>/route/api//...
Examples:
//u/route/group//eu//eu/route/group//lab//lab.eu/route/group//research
Group-name Model
Public group names use dotted suffix hierarchy for discovery only.
Examples:
eulab.euresearch.lab.eu
Each delegation step uses one immediate child label only. Canonical records do not repeat or reverse the full suffix.
Full group-name reconstruction:
- under parent
u, child group is<child-label> - under any other parent
<parent-group>, child group is<child-label>.<parent-group>
Child-label Rules
Each child label:
- MUST be non-empty
- MUST NOT contain
.,/,{,},|, or: - MUST NOT equal
.or.. - SHOULD fit in one
Keysegment
Provisioning
A route-capable client is provisioned out of band with:
- the public-root endpoint
- one or more trusted root route authority verifiers
- optional repo verifier pin for the public root
Child-group Records
Canonical coordinate for top-level eu:
//u/route/group//eu/|/seal/<u-route-verifier>
Canonical coordinate for lab.eu under
eu:
//eu/route/group//lab/|/seal/<eu-route-verifier>
Canonical coordinate for research.lab.eu under
lab.eu:
//lab.eu/route/group//research/|/seal/<lab.eu-route-verifier>
Packet form:
🖧: S.<hash>.H3
Seal-By: <parent-route-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: <parent-group>
API: route/group
Key: <child-label>
TAI: <tai>
Upstream: <via>
Route-Authority-Key: <child-route-verifier>
[Upstream-Verifier: <repo-verifier>]
[Home-API: <api>]
[Condition-Route-Authority-Key: <group> <verifier>]*
[Condition-Name-Key: <name> <verifier>]*
[Condition-Current-Key: <name> <verifier>]*
[Condition-State: <state> <exact-urc>]*
🖧: B.<hash>.H3
Data-Length: 0
Rules:
- packet MUST be a Seal
Seal-ByMUST equal a currently trusted route authority verifier for<parent-group>APIMUST beroute/groupKeyMUST be<child-label><child-label>MUST be one immediate child label under<parent-group>UpstreamMUST appear exactly onceRoute-Authority-KeyMUST appear exactly onceUpstream-VerifierMAY appear at most onceHome-APIMAY appear at most once- Blob
Data-LengthMUST be0
API Records
Canonical coordinate for API chat in group
u:
//u/route/api//chat/|/seal/<u-route-verifier>
Canonical coordinate for API docs in group
lab.eu:
//lab.eu/route/api//docs/|/seal/<lab.eu-route-verifier>
Packet form:
🖧: S.<hash>.H3
Seal-By: <group-route-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: <group>
API: route/api
Key: <api>
TAI: <tai>
[Upstream: <via>]
[Upstream-Verifier: <repo-verifier>]
[Content-Authority: <content-verifier>]
[Condition-Route-Authority-Key: <group> <verifier>]*
[Condition-Name-Key: <name> <verifier>]*
[Condition-Current-Key: <name> <verifier>]*
[Condition-State: <state> <exact-urc>]*
🖧: B.<hash>.H3
Data-Length: 0
Rules:
- packet MUST be a Seal
- for
Group: u,Seal-ByMUST equal a trusted root route authority verifier - for any other group,
Seal-ByMUST equal a currently trusted route authority verifier for that group APIMUST beroute/apiKeyMUST be<api>UpstreamMAY appear at most onceUpstream-VerifierMAY appear at most onceContent-AuthorityMAY appear at most once- Blob
Data-LengthMUST be0
After route resolution selects an API record, API content resolution continues through the deploy-pointer convention in [100-CONTENT-ROUTES.md].
Group Landing API Convention
Groups commonly expose one public landing API.
Convention:
Home-APIin the resolved child-group record selects that landing API- when
Home-APIis absent, clients MAY fall back to API namehome
Resolution Rules
To resolve direct root API //u/chat//...:
- connect to the public-root endpoint
- fetch
//u/route/api//chat - verify Seal with a trusted root route authority verifier
- use the API record’s endpoint and optional pins
- continue with the API deploy-pointer resolution defined in [100-CONTENT-ROUTES.md]
To resolve group landing page //lab.eu:
- connect to the public-root endpoint
- fetch
//u/route/group//eu - verify Seal with a trusted root route authority verifier
- connect to
euupstream - fetch
//eu/route/group//lab - verify Seal with trusted
euRoute-Authority-Key - read
Home-APIwhen present, else fall back tohome - continue as
//lab.eu/<home-api>//index.html
To resolve //lab.eu/docs//...:
- connect to the public-root endpoint
- fetch
//u/route/group//eu - verify Seal with a trusted root route authority verifier
- read
Upstream,Route-Authority-Key, and optional repo pin for groupeu - connect to
euupstream - fetch
//eu/route/group//lab - verify Seal with trusted
euRoute-Authority-Key - read
Upstream,Route-Authority-Key, and optional repo pin for grouplab.eu - connect to
lab.euupstream - fetch
//lab.eu/route/api//docs - verify Seal with trusted
lab.euRoute-Authority-Key - apply API-level
Upstreamor repo pin overrides when present - resolve the API deploy pointer at
//lab.eu/admin/deploy//docs/|as defined in [100-CONTENT-ROUTES.md] - fetch content from the selected content root
Generic algorithm for a public group with labels:
- split the group into labels on
. - start with the rightmost label under
//u/route/group// - then walk leftward one label at a time
- at each step, fetch
//<resolved-parent-group>/route/group//<next-child-label> - after the final group resolves, fetch
//<resolved-group>/route/api//<api>
Local Route Plane
The route scheme also defines a local effective route plane in the home repo.
Canonical roots:
//repo/route/group//...//repo/route/api//...//repo/route/auth//...
All local route-plane packets use:
Group: repo- APIs under
route/...
For this section,
<local-route-authority-verifier> is the currently
trusted verifier for the local route plane.
This spec does not require one canonical storage source for that
verifier. Repository-service clients commonly use the
Seal-By of //repo/admin/identity//root/|,
but other clients or local implementations may provision it
independently.
These packets are private client-side policy. They are not public namespace authority records.
Local exact-group records
Canonical coordinate:
//repo/route/group//<exact-group>/|/seal/<local-route-authority-verifier>
Packet form:
🖧: S.<hash>.H3
Seal-By: <local-route-authority-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: repo
API: route/group
Key: <exact-group>
TAI: <tai>
Upstream: <via>
Route-Authority-Key: <verifier>
[Upstream-Verifier: <repo-verifier>]
[Home-API: <api>]
[Condition-Route-Authority-Key: <group> <verifier>]*
[Condition-Name-Key: <name> <verifier>]*
[Condition-Current-Key: <name> <verifier>]*
[Condition-State: <state> <exact-urc>]*
🖧: B.<hash>.H3
Data-Length: 0
Rules:
- packet MUST be a Seal
Seal-ByMUST equal the current<local-route-authority-verifier>APIMUST beroute/groupKeyMUST be<exact-group><exact-group>MUST satisfy the HPPRGroupvalue constraints from010-PACKETS.mdUpstreamMUST appear exactly onceUpstreamMUST follow the via syntax from033-VIA-SYNTAX.mdRoute-Authority-KeyMUST appear exactly onceRoute-Authority-KeyMUST beV.<b64a>.H3Upstream-VerifierMAY appear at most onceUpstream-Verifier, when present, MUST beV.<b64a>.H3Home-APIMAY appear at most onceHome-API, when present, MUST satisfy the HPPRAPIvalue constraints from010-PACKETS.md- Blob
Data-LengthMUST be0
Meaning:
- exact local effective anchor for one full group name
- replaces the canonical public answer for that exact group in effective mode
- provides the trusted route-authority state from which descendant public records are verified
- for
exact-group = u, acts only as the effective local root anchor
The local plane stores exact groups, not delegation edges.
Local exact-API records
Canonical coordinate:
//repo/route/api//<group>/<api>/|/seal/<local-route-authority-verifier>
Packet form:
🖧: S.<hash>.H3
Seal-By: <local-route-authority-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: repo
API: route/api
Key: <group>/<api>
TAI: <tai>
[Upstream: <via>]
[Upstream-Verifier: <repo-verifier>]
[Content-Authority: <content-verifier>]
[Condition-Route-Authority-Key: <group> <verifier>]*
[Condition-Name-Key: <name> <verifier>]*
[Condition-Current-Key: <name> <verifier>]*
[Condition-State: <state> <exact-urc>]*
🖧: B.<hash>.H3
Data-Length: 0
Rules:
- packet MUST be a Seal
Seal-ByMUST equal the current<local-route-authority-verifier>APIMUST beroute/apiKeyMUST be<group>/<api><group>MUST satisfy the HPPRGroupvalue constraints from010-PACKETS.md<api>MUST satisfy the HPPRAPIvalue constraints from010-PACKETS.md- at least one of
Upstream,Upstream-Verifier, orContent-AuthorityMUST appear UpstreamMAY appear at most onceUpstream, when present, MUST follow the via syntax from033-VIA-SYNTAX.mdUpstream-VerifierMAY appear at most onceUpstream-Verifier, when present, MUST beV.<b64a>.H3Content-AuthorityMAY appear at most onceContent-Authority, when present, MUST beV.<b64a>.H3- Blob
Data-LengthMUST be0
Meaning:
- exact local override for one API in one group
- may layer over a local or public group answer
- may act as terminal bootstrap for one
group/apieven when no exact-group anchor exists
Local auth records
Local route auth attaches an identity choice to routed access. Public route records do not carry auth data.
Canonical coordinates:
- group default:
//repo/route/auth//<group>/|/seal/<local-route-authority-verifier> - exact API:
//repo/route/auth//<group>/<api>/|/seal/<local-route-authority-verifier>
Packet form:
🖧: S.<hash>.H3
Seal-By: <local-route-authority-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: repo
API: route/auth
Key: <group>[/<api>]
TAI: <tai>
Auth: <identity-text>
[Condition-Route-Authority-Key: <group> <verifier>]*
[Condition-Name-Key: <name> <verifier>]*
[Condition-Current-Key: <name> <verifier>]*
[Condition-State: <state> <exact-urc>]*
🖧: B.<hash>.H3
Data-Length: 0
Rules:
- packet MUST be a Seal
Seal-ByMUST equal the current<local-route-authority-verifier>APIMUST beroute/authKeyMUST be exactly<group>for group-default auth or<group>/<api>for exact-API auth<group>MUST satisfy the HPPRGroupvalue constraints from010-PACKETS.md<api>, when present, MUST satisfy the HPPRAPIvalue constraints from010-PACKETS.mdAuthMUST appear exactly onceAuth: anyonemeans unauthenticated access- any non-
anyoneAuthvalue MUST follow the local route implementation’s client identity-text convention - Blob
Data-LengthMUST be0
Meaning:
- exact-API auth overrides group auth
- missing local auth defaults to
anyone - local auth records are private client policy
Auth: anyone is valid and can explicitly override a
non-anonymous group default for one API.
Any non-anyone Auth text is outside
generic HPPR scheme semantics. Repository-service clients commonly
use the identity-text forms defined in 045-IDENTITY-TEXT.md.
Effective Route Resolution
Effective resolution uses both the public route plane and the local route plane.
For target //<group>/<api>//...,
effective resolution proceeds in this order.
Step 0: explicit endpoint override
If the input includes explicit via or CLI
--via, that wins.
This bypasses stored endpoint selection. It does not erase separately stored local auth or content metadata that the caller may still apply.
Step 1: local exact-API candidate
Check:
//repo/route/api//<group>/<api>/|
If present, record it as a local exact-API candidate. Do not merge fields yet.
Step 2: determine the effective root anchor
If //repo/route/group//u/| exists, effective mode
uses it as the root anchor. Otherwise effective mode starts from the
provisioned public root.
Step 3: walk exact groups from root to target
Split the group into dotted labels and reconstruct exact groups from right to left.
Example for research.ops.lab.eu:
eulab.euops.lab.euresearch.ops.lab.eu
For each exact group in order:
- check local exact-group anchor:
//repo/route/group//<exact-group>/|
- if present:
- use it as the effective anchor for that exact group
- it shadows the canonical public answer for that exact group
- descendant public lookup continues from this local anchor’s
Route-Authority-Key
- otherwise:
- fetch the canonical public child-group record under the current parent namespace
- verify it using the current parent anchor’s
Route-Authority-Key - use that public record as the effective anchor for the exact group
Step 4: resolve the API record
After the final exact-group anchor is known:
- read local exact-API candidate when present
- attempt canonical public API record:
//<group>/route/api//<api>- verified with the final exact-group anchor
Route-Authority-Key
- for non-
ugroups, allow canonicalContent-Authorityfallback from://u/route/api//<api>
Content-Authority fallback applies only to
Content-Authority. It never applies to
Upstream.
Step 5: allow terminal local exact-API bootstrap
If no effective exact-group chain exists for the target group, a local exact-API record may still be sufficient.
In that case:
- missing canonical public group/API records is not a failure
- the local API record alone provides the effective route answer for that exact API
- descendant group delegation is not implied
Step 6: effective field merge
API-level values override group-level values. Local values override public values at the same level.
Effective endpoint:
- local API
Upstream - public API
Upstream - local exact-group
Upstream - public exact-group
Upstream - failure if nothing resolves
Effective upstream repo verifier:
- local API
Upstream-Verifier - public API
Upstream-Verifier - local exact-group
Upstream-Verifier - public exact-group
Upstream-Verifier
Effective content authority:
- local API
Content-Authority - public API
Content-Authority - for non-
ugroups only, canonical fallback to//u/route/api//<api>
Effective home API:
- local exact-group
Home-API - public exact-group
Home-API - implementation fallback
home
Step 7: local auth attachment
After the effective route target is known, attach local auth in this order:
//repo/route/auth//<group>/<api>/|//repo/route/auth//<group>/|- implicit default
anyone
Step 8: route client construction
The effective route client uses:
- the resolved endpoint
- the attached local auth identity, or
anyoneif none exists - the resolved upstream repo pin when present
Canonical Route Resolution
Canonical resolution ignores all
//repo/route/...//... packets.
For public names:
- start from the provisioned public root
- walk delegated public group edges only
- resolve the public API record under the final exact group
- apply canonical public
Content-Authorityfallback from//u/route/api//<api>for non-ugroups only
For ~ groups:
- canonical resolution has no public answer
Conditions and Canonical Truth
Condition-* evaluation uses canonical resolution,
not effective local resolution.
For group u, canonical truth is the current
provisioned public-root configuration:
- the trusted root route authority verifiers
- the optional pinned public-root repo verifier, when provisioned
A local //repo/route/group//u/| packet affects only
effective local routing. It MUST NOT affect canonical
Condition-* truth.
Reason:
- local route overrides are private client policy
- condition meaning must not vary per client home repo
- canonical public truth is the only stable reference for conditional scheme semantics
Authority-Local Name Tree
Public or private identity naming lives under an authority group.
Canonical root:
//<authority-group>/name//...
Examples:
//lab.eu/name//...//friends/name//...
The same mechanism supports public and private identities. Visibility is controlled by the authority group’s repository policy.
Exact-name Syntax
Text form:
<part>[.<part>...]@<authority-group>
Examples:
ops@lab.euops.alice@lab.euops.alice.phone@lab.eu
The local name parts stay in written order. They are not reversed in storage.
Name-part Rules
Each local name part:
- MUST be non-empty
- MUST NOT contain
/,{,},|,:,@, or. - MUST NOT equal
.or.. - SHOULD fit in one
Keysegment
Core Model
The exact identity node is the continuity anchor. Each exact node has:
- one stable
Name-Key - zero or more
Current-Keyvalues
Top-level nodes are created by the authority group. Child nodes
are created by the current holder of the parent node’s
Name-Key.
Identity Node Records
Canonical coordinate for ops.alice.phone@lab.eu:
//lab.eu/name//ops/alice/phone/|
Packet form:
🖧: S.<hash>.H3
Seal-By: <authority-or-parent-node-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: <authority-group>
API: name
Key: <part>[/<part>...]
TAI: <tai>
State: active|withdrawn|compromised|rotated
Name-Key: <verifier>
[Current-Key: <verifier>]*
[Node-Type: role|person|device|team]
[Condition-Route-Authority-Key: <group> <verifier>]*
[Condition-Name-Key: <name> <verifier>]*
[Condition-Current-Key: <name> <verifier>]*
[Condition-State: <state> <exact-urc>]*
[+Link: supersedes <hash>]
🖧: B.<hash>.H3
Data-Length: <len>
<optional note>
Rules:
- packet MUST be a Seal
StateMUST appear exactly onceStateMUST beactive,withdrawn,compromised, orrotatedName-KeyMUST appear exactly once whenState: activeCurrent-KeyMAY appear zero or more times- the exact identity anchor is
//<authority-group>/name//<part>[/<part>...] - the visible name is
<part>[.<part>...]@<authority-group>
Authorization rules:
- a top-level node
<part>MUST be signed by a verifier authorized by the authority group - a child node
<p1>/.../<pn>MUST be signed by the current holder of the parent node’sName-Key
Continuity rules:
- changing
Current-Keyis ordinary operational rotation - changing
Name-Keyis identity-significant
Resolution
To resolve ops.alice.phone@lab.eu:
- resolve authority group
lab.euthrough the route scheme - fetch
//lab.eu/name//ops/| - read
Name-KeyandCurrent-Keyforops@lab.eu - fetch
//lab.eu/name//ops/alice/| - read
Name-KeyandCurrent-Keyforops.alice@lab.eu - fetch
//lab.eu/name//ops/alice/phone/| - read
Name-KeyandCurrent-Keyforops.alice.phone@lab.eu
Exact-name resolution is exact. There is no implicit fallback
from ops.alice.phone@lab.eu to
ops.alice@lab.eu or ops@lab.eu.
Underspecified UX is handled by listing:
//lab.eu/name////lab.eu/name//ops///lab.eu/name//ops/alice/
Public Attestation Tree
All attestation packets use:
Group: uAPI: attest
Packet families:
state— current attestation state packetsrequest— advisory requests asking another key to publish attestation statemeaning— issuer-local explanation of relation names
Scope IDs
<scope-id> lets one issuer publish more than
one independent statement for the same target and relation.
Typical values:
globalevent-2026org-hr
state/verifier
state/verifier carries attestation state about one
signer verifier.
Canonical coordinate:
//u/attest/state/verifier//<subject-verifier>/<scope-id>/<relation>/|/seal/<issuer-verifier>
Packet form:
🖧: S.<hash>.H3
Seal-By: <issuer-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: u
API: attest/state/verifier
Key: <subject-verifier>/<scope-id>/<relation>
TAI: <tai>
State: yes|no|withdrawn
[Condition-Route-Authority-Key: <group> <verifier>]*
[Condition-Name-Key: <name> <verifier>]*
[Condition-Current-Key: <name> <verifier>]*
[Condition-State: <state> <exact-urc>]*
[Scope: //<group>/<api>//...]
[Expires: <tai>]
[Meaning: <text-or-urc>]
[+Link: evidence <hash>]*
[+Link: request <hash>]
🖧: B.<hash>.H3
Data-Length: <len>
<free text note>
Rules:
- packet MUST be a Seal
StateMUST appear exactly onceStateMUST beyes,no, orwithdrawn- the subject is the verifier named in the path
- evaluators SHOULD use the tip packet for one exact signer path
- if
Expiresis present and already passed, the statement is invalid
state/name
state/name carries attestation state about one exact
identity name. It does not define names. Names are defined by the
name scheme in this spec.
Canonical coordinate:
//u/attest/state/name//<scope-id>/<relation>/<authority-group>/<part>[/<part>...]/|/seal/<issuer-verifier>
Packet form:
🖧: S.<hash>.H3
Seal-By: <issuer-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: u
API: attest/state/name
Key: <scope-id>/<relation>/<authority-group>/<part>[/<part>...]
TAI: <tai>
State: yes|no|withdrawn
Target-Name: <part>[.<part>...]@<authority-group>
[Condition-Route-Authority-Key: <group> <verifier>]*
[Condition-Name-Key: <name> <verifier>]*
[Condition-Current-Key: <name> <verifier>]*
[Condition-State: <state> <exact-urc>]*
[Scope: //<group>/<api>//...]
[Expires: <tai>]
[+Link: evidence <hash>]*
🖧: B.<hash>.H3
Data-Length: <len>
<free text note>
Rules:
- packet MUST be a Seal
StateMUST appear exactly onceStateMUST beyes,no, orwithdrawnTarget-NameMUST appear exactly onceTarget-NameMUST exactly match the authority group and local parts in the path- the exact identity anchor is the target name itself, not the target’s current operational verifier
- if
Expiresis present and already passed, the statement is invalid
Relation names are ordinary strings. Common examples:
trustedis-humanknownofficialmemberspeaks-for
request
request packets are advisory only. They ask another
verifier to publish attestation state.
Canonical coordinate:
//u/attest/request//<target-verifier>/<scope-id>/<relation>/<requester-verifier>/|/seal/<requester-verifier>
Packet form:
🖧: S.<hash>.H3
Seal-By: <requester-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: u
API: attest/request
Key: <target-verifier>/<scope-id>/<relation>/<requester-verifier>
TAI: <tai>
[Request-Subject: <subject-verifier>]
[Condition-Route-Authority-Key: <group> <verifier>]*
[Condition-Name-Key: <name> <verifier>]*
[Condition-Current-Key: <name> <verifier>]*
[Condition-State: <state> <exact-urc>]*
[Scope: //<group>/<api>//...]
[+Link: comment <hash>]
[+Link: profile <hash>]
🖧: B.<hash>.H3
Data-Length: <len>
<short free text request>
Rules:
- packet MUST be a Seal
Seal-ByMUST equal<requester-verifier>- request packets are advisory only
- hosts MUST NOT require request packets for attestation validity
meaning
meaning explains one relation name in issuer-local
human terms.
Canonical coordinate:
//u/attest/meaning//<relation>/|/seal/<issuer-verifier>
Packet form:
🖧: S.<hash>.H3
Seal-By: <issuer-verifier>
Seal-Sig: <signature>
🖧: P.<hash>.H3
Group: u
API: attest/meaning
Key: <relation>
TAI: <tai>
Label: <short label>
[Condition-Route-Authority-Key: <group> <verifier>]*
[Condition-Name-Key: <name> <verifier>]*
[Condition-Current-Key: <name> <verifier>]*
[Condition-State: <state> <exact-urc>]*
[Scope: //<group>/<api>//...]
🖧: B.<hash>.H3
Data-Length: <len>
<human-readable explanation>
.H3names the active format extension: BLAKE3-256 hashing, HSB3 signatures, UTF-8 NFC normalization (Unicode 17.0.0), and this packet structure.↩︎