Personal Enclave — RBAC v2
Status: Design Based on: rbac-v2.md
Overview
A personal enclave is an identity anchor — holding who you are and where to find your data. Single-owner, no other human participants.
Three data layers:
- profile — KV Shared singleton. Public identity card. SMT-provable.
- public — Content events. Dynamic public content.
- private — Content events. Encrypted dynamic documents. Owner-only.
Manifest
{
"states": ["OWNER"],
"traits": ["dataview(1)"],
"readers": [
{ "type": "OWNER", "reads": "*" }
],
"moves": [],
"grants": [
{ "event": "Grant", "operator": ["OWNER"], "scope": ["OUTSIDER"], "trait": ["dataview"] },
{ "event": "Revoke", "operator": ["OWNER"], "scope": ["OUTSIDER"], "trait": ["dataview"] }
],
"transfers": [],
"slots": [
{ "event": "Shared", "operator": "OWNER", "ops": ["C", "U", "D"], "key": "profile" },
{ "event": "Shared", "operator": "dataview", "ops": ["P"], "key": "profile" }
],
"lifecycle": [
{ "event": "Terminate", "operator": "OWNER", "ops": ["C"] }
],
"customs": [
{ "event": "public", "operator": "OWNER", "ops": ["C", "U", "D"] },
{ "event": "public", "operator": "dataview", "ops": ["P"] },
{ "event": "private", "operator": "OWNER", "ops": ["C", "U", "D"] }
],
"init": [
{ "identity": "<owner_pub>", "state": "OWNER", "traits": [] }
]
}Design Rationale
States: ["OWNER"] — single State for the sole human identity. OUTSIDER (0) is implicit.
Traits: ["dataview(1)"] — push delivery for service accounts.
Operators:
OWNER(State) — all ops. Read on all events via readers. CUD on content and KV. Administrative: Grant, Revoke, Terminate.dataview(trait) — P on profile and public events for push delivery.
No moves — OWNER is bootstrapped via init. The owner never changes state. Validation rule 1 ("In and Out") is satisfied by init — OWNER is reachable at enclave creation.
No transfers — a personal enclave IS your identity; ownership cannot be transferred.
Lifecycle: Terminate only. No Pause/Resume — single owner, no security value.
Event-Operator Matrix
| Event | OWNER | OUTSIDER | dataview(1) |
|---|---|---|---|
| public | CRUD | P | |
| private | CRUD | ||
| Shared(profile) | CRUD | P | |
| Grant(dataview) | CR | ||
| Revoke(dataview) | CR | ||
| Terminate | CR |
Columns: States (OWNER, OUTSIDER) → traits (dataview).
Data
KV Shared: profile
Public identity card. Singleton. SMT-provable.
Cross-application fields: display_name, bio, avatar. Recommended for interoperability across apps. Apps may add additional fields — the protocol does not constrain the internal structure.
Content event: public
Dynamic public content. Owner creates. Supports U (update) and D (delete).
The protocol does not prescribe content structure. Apps define their own content types freely.
Content event: private
Dynamic private documents. Owner-only. Encrypted. Supports U (update) and D (delete).
Each event's content is encrypted before submission. The node stores opaque ciphertext. Apps use content events with U for granular updates to independent documents — no single-blob limitation.
The protocol does not prescribe what documents are stored. Apps define their own document types freely.
Encryption
profile
Plaintext. Readable by the owner. Service accounts receive pushes via dataview.
public
Plaintext. Readable by the owner.
private
Owner-only. Content is encrypted before submission — node stores opaque ciphertext.
content_key = HKDF(identity_secret, "enc-personal-private", enclave_id)
ciphertext = XChaCha20-Poly1305(content_key, nonce, plaintext)- Deterministic key derivation — any device with the identity secret derives the same key.
- Unique nonce per event.
- No key rotation — single-owner, key never changes.