Part of Stem. This page defines the space kind: the resource at the root of every space. Its state is a document whose metadata is the account's profile, and every other node in the space descends from it. The formal schema of this kind's state is attached as the schemaDefinition of this page.
Descriptor
{
"name": "Space",
"description": "The root resource of a space: profile attributes plus the home document, owner-only.",
"state": "changes",
"schema": "hm://z6MkiAKDcRSzQ4zPZfnJcS5HYx5MwgN6MU9foHihJGrhqNBj/stem/kinds/space/attributes",
"naming": "unnamed",
"children": true,
"access": "own",
"retention": "history",
"links": [
{ "path": "/icon", "kind": "file" }
]
}State
The root's state is a Change graph exactly like a document's: Change blobs replayed with the two document CRDTs into metadata and a block tree (Documents). The block tree is the home page. The metadata follows the attributes schema below, which is open: any other document metadata key is allowed.
field | type | required | meaning |
|---|---|---|---|
| no | Display name of the space. | |
| no | Avatar or icon. Emits a | |
| string | no | Short description of the account or organisation. |
| no | Another account this one is an alias of; readers are sent there. | |
| struct | no | The site that publishes this space: its HTTPS origin and the peer id of its daemon. |
Rules
The root's creating Node blob is deterministic: signed by the owner with ts 0, kind space, no id, no parent, no name, target heads naming the owner's deterministic genesis Change. Its CID is the root id, so any peer derives it from the owner's key before holding a single blob. Later Node blobs for the root carry that id and are the only Node blobs allowed to omit parent. hm://<owner> is an alias for hm://<owner>/<rootId>.
Only the space owner's key may sign a Node blob or a Change for the root. A Grant at write with the root as subject lets its audience create and update every other node in the space, setting space to the owner on the blobs they sign; it does not let them write the root itself. Open: whether admin on root should include the root's own state.
The root cannot be a tombstone or a redirect. To retire an account, publish alias.
Access is own: the root's readers are the audiences of grants whose subject is the root, plus the owner. A public space is one whose root has a live Grant(audience: everyone, access: read). Every node that inherits from root is then public unless it says own.
The genesis Change of the root is the deterministic empty Change with ts 0, exactly as today's home document (Change), so every device of an account derives the same identity.
site grants nothing by itself. The site peer becomes an authority peer only while it also holds a live sync grant on the root from the owner. Both halves are signed by the owner, so site trust no longer rests on DNS and HTTPS alone. See Site.
alias is honoured only when the alias account has issued a live admin grant to this account's key; otherwise it is ignored. This replaces HM24's AGENT capability check on Profile aliases.
Today (HM24)
Two blobs carried this state. The Profile blob held alias, name, avatar (the wire key for the icon), description and account (for an AGENT key signing on behalf of its parent), merged field by field by newest timestamp with no stable id. The home document was the document at the empty path, with siteUrl in its metadata, and it was the only path that could not be tombstoned or redirected. The roadmap already decided that home documents become profiles anchored to a fixed node id under an empty parent. Stem does that: both migrate into the root node's metadata, avatar becomes icon, siteUrl becomes site.url, and account disappears because a device or agent key writes through a grant, not through a field.
Example
The deterministic creating Node blob of a space, whose CID bafyreiujzdegxdncf32epf3dhodzdocis2jhtlgmxgedn73u55xtplpft7 is the root id (only sig varies between owners):
{
"type": "Node",
"signer": { "/": { "bytes": "7QHm…" } },
"sig": { "/": { "bytes": "…" } },
"ts": 0,
"kind": "hm://z6MkiAKDcRSzQ4zPZfnJcS5HYx5MwgN6MU9foHihJGrhqNBj/stem/kinds/space",
"target": { "kind": "heads", "heads": [{ "/": "bafy2bzace0…" }] }
}A later root Node blob of the same space, pointing at the current heads of its Change graph:
{
"type": "Node",
"signer": { "/": { "bytes": "7QHm…" } },
"sig": { "/": { "bytes": "…" } },
"ts": 1759900000000,
"id": "bafyreiujzdegxdncf32epf3dhodzdocis2jhtlgmxgedn73u55xtplpft7",
"kind": "hm://z6MkiAKDcRSzQ4zPZfnJcS5HYx5MwgN6MU9foHihJGrhqNBj/stem/kinds/space",
"target": { "kind": "heads", "heads": [{ "/": "bafy2bzacea…" }] },
"prev": [{ "/": "bafy2bzaceb…" }],
"access": "own"
}A Change in that graph setting the profile attributes:
{
"type": "Change",
"signer": { "/": { "bytes": "7QHm…" } },
"sig": { "/": { "bytes": "…" } },
"ts": 1759899000000,
"genesis": { "/": "bafy2bzace0…" },
"deps": [{ "/": "bafy2bzacec…" }],
"depth": 12,
"body": {
"ops": [
{ "type": "SetAttributes", "attrs": [
{ "key": ["name"], "value": "Starlight" },
{ "key": ["icon"], "value": "ipfs://bafkreih…" },
{ "key": ["site", "url"], "value": "https://starlight.example" },
{ "key": ["site", "peer"], "value": "12D3KooW…" }
] }
]
}
}Do you like what you are reading? Subscribe to receive updates.
Unsubscribe anytime