Version: 0.1.0 Status: Draft
Canonical reference for lambda-ma world protocol behaviour.
This document defines lambda-ma world/profile behaviour on top of ma-runtime. It is not the generic runtime specification and is not a global requirement for all ma worlds.
- Runtime/base protocol specs live in ma-spec.
- This file defines world semantics for the shipped lambda-ma actor set.
- Routing contract
- Enter contract
- Authority model
- Movement and arrival flows
- Actor interfaces
- State keys and authority boundaries
- Wire/value conventions
- Build and bootstrap quick reference
- Cross references
Zion focus shorthand is split by leading colon:
- No leading
:: avatar-mediated avatar-mediated command. - Leading
:: direct method on focused room/target.
Examples:
- Avatar-mediated:
look,say hello,go north,dig east. - Direct:
:help,:prop name Garden,:thing rms did:ma:...#rms.
Rules:
- Actor code MUST preserve this split.
- Avatar MUST NOT become a proxy layer for colon-prefixed room methods.
- If a colon command fails in focus mode, fix zion routing or room actor method, not avatar proxying.
When a concrete room target is available, enter is room-first.
- Request goes to room actor
:enter. - Room validates request context and ensures the deterministic local avatar.
- If the avatar does not exist yet, room creates it with an explicit
deterministic fragment; avatar init sends room
:enterafter the avatar is live. - If the avatar exists, room sends only
:enter-roomto the avatar; the avatar sends room:enter. - Room registers avatar entry in room state and sends committed
/ma/lambda/ctx/0.0.1to the avatar. The avatar then persists its room state and forwards that ctx to the DID principal.
Compatibility path:
- Root
:enterstill exists and may be used when only runtime target is known. - For an existing avatar, root asks the avatar to send its current ctx to the DID principal. Root must not send messages to rooms.
Room-first enter accepts either no payload or one extensible map named ctx.
The payload concept is ctx only. Do not introduce a parallel attrs map.
For client entry, ctx.kind MAY be absent. Absence means the client is not
claiming to be a concrete world object kind yet; the room MUST treat this as a
request to enter as the world's default session kind and send no :ok itself.
The room creates or finds the avatar; the avatar performs room entry, receives
committed /ma/lambda/ctx/0.0.1 context from the room, persists that state, and
forwards the ctx to the DID principal asynchronously. In lambda-ma the default session
kind is an avatar.
Direct non-avatar occupants MUST identify themselves with a strict ctx map:
kind(agentorthing)namenickdescription
Rules:
- Missing
ctx.kindmeans client/session entry. The client should wait for the world to send the committed context; it must not assume the effective kind or avatar actor from the enter request alone. ctx.kind = "agent"or"thing"requires all strict direct occupant keys.- Empty direct occupant required values MUST be rejected.
- Additional keys MAY be present and are forward-compatible extension data.
- A client that wants a direct thing/agent entry MUST send
ctx.kind; without it, the world assigns the default session kind and reports it in the committed context.
Committed lambda-ma context is delivered as :ctx with protocol
/ma/lambda/ctx/0.0.1.
All actor references crossing actor, client, or runtime message boundaries MUST
be full DIDs or DID-URLs. Runtime-local #fragment shorthand may be
canonicalised while reading legacy state, but MUST NOT be sent in messages or
persisted in ctx fields by avatars, agents, clients, or future ctx consumers.
Required context fields:
protocol=/ma/lambda/ctx/0.0.1kind(effective session kind chosen by the world, e.g.avataroragent)rootroomnick
Avatar contexts include avatar, the actor to receive avatar-mediated DID principal
commands. Direct agent contexts may set avatar to the empty string.
Client-side focus/context commit is acknowledgment-driven.
- Enter send does not imply commit.
- Commit occurs only after valid acknowledgment from expected actor path.
- Room ownership is a bare DID in room
ownerprop. - Avatar is a delegate for display commands, not the owner identity.
- Direct room RPC uses message sender identity (
msg.from).
- A movable entity is authoritative for its own
ownerandparent. parentis location/container authority.- Parent-mediated transfer model applies to
takeanddrop. - Rooms currently present agents and things through one local non-avatar
occupant cache; the
ctx.kindremains useful protocol context, not a demand for separate room-side policy.
Rules:
- Current parent is the caller that may request transfer.
- Target parent is payload data for new parent assignment.
- Current parent and target parent do not perform direct peer negotiation.
- Caller sends
:enter <ctx>to the target room. - Room derives the deterministic avatar fragment from the caller DID.
- If the avatar already exists, room asks it to enter this room.
- If the avatar does not exist, room creates it with an explicit deterministic
fragment; avatar init sends room
:enterfrom the live avatar. - Room registers entry and sends committed
:ctxto avatar; avatar persists room state and forwards the ctx to DID principal.
- Avatar sends
:go <direction>to current room. - Room resolves
<direction>to a first-class exit actor and sends:traverse <ctx>to that exit. Minimal movement ctx usesactor,kind,room, and optionalnick/text. - Exit checks source-side state such as lock and target configuration.
- Exit replies to the source room with
:traversed <ctx>. If traversal is allowed,ctx.roomis the target room. If traversal is blocked,ctx.roomremains the source room andctx.textexplains why. - Source room sends
:ctx <ctx>toctx.actor; it does not commit movement state or own departure side effects. - The actor validates the ctx, then performs the actual target-room
:enter <ctx>. Target room admission remains target-room authority. - Only the target room's committed
:ctxupdates actor/avatar state and is forwarded to the DID principal.
For named new-room digs such as dig dør to kjøkken, the source room derives
deterministic room and exit fragments with blake3. The derivation is scoped
by source room, direction, and target name, so repeating the same command in the
same room reuses the same target room and exit instead of creating fresh actors.
Unnamed exploratory digs remain non-deterministic.
New-room digs are two-phase. The source room stores the pending target and a
nonce, creates the room with child-alive metadata in the init payload, and only
creates the exit after receiving :child-alive <actor> <kind> <nonce> <direction>
from the expected room. The child-alive metadata is part of the new room's init
payload; after storing it, the room sends the callback to its parent. Actors
without a parent, such as genesis actors, emit no child-alive callback.
For existing-room link targets:
- Source room stores pending link request.
- Source room sends
:pingto target room. - After
:pong, source requests:authorise-link. - Target room confirms same-owner policy.
- Source room creates/replaces exit only after explicit authorisation.
All terms are CBOR-style actor terms, typically :verb or [":verb", ...].
All Scheme-backed lambda-ma actors inherit the generic actor method below from
/ma/scheme/actor/0.0.1 before their kind-specific behaviour is loaded.
| Verb | Args | Notes |
|---|---|---|
:behaviour |
[ /ipfs/<cid> ] |
No args returns this actor's current per-entity behaviour reference, if any. With one IPFS reference, the caller must match the actor's owner prop; on success this queues a reload of this actor's own extra behaviour layer. |
:name / :description / :kind |
[text...] for :name and :description; none for :kind |
Generic metadata inspection. With no args, :name returns the name prop, :description returns the description prop, and :kind returns the runtime kind. With args, :name and :description are owner-gated setters that persist the joined text and return the new prop value. :kind is read-only. |
:owner / :owner? |
[printer] |
Generic prop-based owner inspection. :owner returns the raw owner DID or (none). :owner? returns display text, or sends it to printer via :print when a target is supplied. Kind-specific actors may override this with stricter policy. |
:parent / :parent? |
none, or kind-specific [ctx] |
Generic prop-based parent inspection. :parent returns the raw parent actor or (none); :parent? returns display text. Movable actors override :parent <ctx> as a current-parent-gated parent push: the current parent sends a ctx map naming the new parent in parent (or room as a movement fallback), the child updates its authoritative parent state, then announces its own ctx to the new parent with :children <ctx>. The received ctx is intentionally accepted broadly for now; filtering can be tightened later. |
:children |
[ctx] |
With no args, owner-gated child-cache listing. With one ctx map, registers or updates a child cache entry when ctx.actor is a full DID-URL, ctx is an actor ctx, and msg-from matches ctx.actor. The child cache is derived state; the child's own parent prop remains authoritative. |
:where / :where? / :here / :here? |
none | Aliases for generic parent inspection, so every actor has a minimal location answer even before kind-specific behaviour is loaded. |
Purpose: deterministic avatar factory.
Key verbs:
| Verb | Args | Notes |
|---|---|---|
:enter |
[room? nick?] |
Compatibility path when no concrete room target is available. Creates caller avatar if absent, or asks an existing avatar to send its current ctx to the DID principal. Root does not message rooms. |
:avatar? |
none | Returns caller avatar, creating if needed in the configured start room. |
Purpose: avatar-mediated command endpoint and context emitter.
Key verbs:
| Verb | Args | Caller constraints | Notes |
|---|---|---|---|
:enter-room |
<room> |
root or target room | Avatar receives this from root or the target room, sends room :enter, and waits for committed room ctx before persisting room state and forwarding :ctx to DID principal. |
:sync-ctx |
none | root only | Emits current :ctx to DID principal without changing avatar state. |
:ctx |
<ctx-map> |
current room, root, or controlling DID | With no args, returns current context to authorised callers. With a movement ctx-map, validates ordinary movement ctx, optionally prints ctx.text, then asks ctx.room to admit the avatar. The avatar forwards no new :ctx to the DID principal until the target room commits one. |
:ctx? |
none | DID principal only | Returns context term. |
:children |
[ctx] |
no args: DID principal only; ctx: child actor only | inventory storage surface. With child ctx, accepts only sender-matching actor ctx and stores it in the avatar's child cache. With no args, returns the child-cache listing. |
:help |
[topic] |
DID principal only | help here asks room :help. |
:nick |
[nick] |
DID principal only | No args returns current nick; with args forwards to room. |
:make |
<kind> <init...> |
DID principal only | Requests a new actor of kind using ma-create-actor with no behaviour override and all args after kind joined as the creation payload. The avatar does not inject owner, parent, or room props; the init text owns initial state. thing is accepted as shorthand for /ma/thing/0.0.1. Creation is queued; the returned DID-URL may not be live until the runtime loads the entity. |
:look/:l :exits? :who? :did? :owner? :say :emote :go |
varies | DID principal only | Delegates to room. |
:claim :owner :dig :fill :prop |
varies | DID principal only | Delegates to room without owner-authority arguments; rooms recognise the owner DID or deterministic owner avatar from msg-from. |
:drop-thing |
<did> <thing> <target-parent> [token] [ctx] |
room caller only | Parent-mediated drop helper; forwards optional DID principal ctx map. |
:report-parent |
<room> <tick> <nonce> |
room caller | Machine presence request; replies with :parent-report <self> <room> <tick> <nonce> using the avatar's persisted room. |
Purpose: local room policy, exits, ownership, occupant presentation.
Key verbs:
| Verb | Args | Notes |
|---|---|---|
:enter |
<ctx-map> |
Room-first enter endpoint. Avatar ctx maps include full DID/DID-URL actor references and a did DID; target rooms create or reuse that DID principal's deterministic local avatar. agent/thing require ctx required keys. |
:enter |
<avatar-did-url> [old-room-did-url] |
Admit known avatar flow. |
:leave |
none | Caller-origin live-presence departure. Removes the caller's local deterministic avatar from this room, but does not change avatar state or client ctx; the saved room remains the next-login return point. |
:remove |
<occupant> |
Owner-gated manual presence cleanup. Resolves an occupant by DID/DID-URL or by a unique current display label; ambiguous labels are rejected. Removes the occupant from room-local presence caches and does not change actor state. The occupant may re-enter later through normal :enter flow. |
:leave-occupant |
none | Sender-origin cache removal for non-avatar occupants such as agents after actor-owned parent changes. |
:look |
[exit-direction] |
No args prints room text plus Occupants:, Things:, and Exits:. With an exit direction, forwards inspection to the first-class exit actor. |
:exits? :who? :occupants? :things? |
none | Local presentation. exits? lists directions known to the room; who? is people/avatar-oriented; occupants? includes avatars plus room-local agents/occupants. |
:did? |
[exit|thing|occupant] <name> |
Explicit visible reference lookup. Resolves a visible exit direction, room-local thing alias, or occupant display label to a DID/DID-URL. Without a kind, one unambiguous match is returned; ambiguous names list every matching kind. |
:owner? |
[name] |
With no args, shows room ownership. With a visible exit, thing, or occupant name, resolves the target like :did? and asks that actor to print its owner to the requester. |
:dids? |
none | Owner-gated full reference listing for visible occupants, room-local things, and exits. |
:go / :move |
<direction> / none |
:go traverses a named exit. :move chooses one currently available room exit for the caller. |
:thing |
<name> [did-or-empty] |
Local occupant alias list/get/set/delete; owner-gated for write. |
:take / :drop / :where? |
[DID principal?] [token] |
Uses movable actor parent-authority contract. |
:claim / :owner / :prop |
direct args | Room ownership controls write operations; owner authority is checked against msg-from or the deterministic owner avatar. |
:dig |
direct args | Owner-gated exit creation/linking; newly-created rooms are assigned to the stored owner DID. |
:fill |
direct args | Owner-gated exit removal. Removes the direction from the room and asks the exit actor to terminate itself; target rooms are not deleted. |
:exit |
<direction> <verb> [args] |
Owner-gated direction resolver and generic forwarder to the exit actor. Exit semantics live in exit.ma. |
:child-alive |
<actor> <kind> <nonce> <direction> |
Child readiness callback; rooms use it for pending new-room dig targets when actor, kind, nonce, and direction match. |
:ping / :pong / :authorise-link / :link-authorised / :link-denied |
link handshake args | Existing-room link handshake. |
:presence-tick |
none | Scheduled room-local occupant sweep. Asks occupants to report their parent and removes occupants that have not reported within the room timeout. |
:parent-report |
<child> <parent> <tick> <nonce> |
Machine reply from a child to the room's :report-parent request. A parent different from the room removes the child immediately. |
Room presence cache rules:
occupantsandavatar-occupantsare room-local derived caches.- DID principal-facing
:leaveremoves only live room presence. It deliberately leaves avatar state and zion.my.ctx.*unchanged so the remembered room remains the return point on a later login. - Owner-facing
:remove <occupant>is manual cleanup only. It removes cached room presence, not actor state or future admission rights. If multiple occupants share the same nick/display label, the owner must use a DID or DID-URL to identify the target. :did? [exit|thing|occupant] <name>is an explicit lookup for a visible exit, occupant, or thing. Without a kind, one unambiguous match is returned; ambiguous names list every matching kind.:dids?is owner-gated and lists all visible occupant, thing, and exit references for administrative disambiguation.- On lifecycle
:start, a room registers a#schedulerinterval for:presence-tick. #schedulerlater sends:presence-tickto the room as an ordinary message. On each tick, the room sends:report-parent <room> <tick> <nonce>to current occupants.- Avatars report their current
room; agents and things report their currentparent. - If a child reports a parent other than the room, the room removes that child from local occupant caches immediately.
- If a child does not report for the configured timeout, the room removes it
from local occupant caches. The child may re-enter later through normal
:enterflow.
Purpose: first-class inspectable traversal object.
| Verb | Args | Notes |
|---|---|---|
:about |
none | Returns name, description, owner, source room, target room, direction, and locked state. |
:where? |
none | Returns the source room DID-URL. |
:owner |
none | Returns the owner DID or (none). |
:report-parent |
<room> <tick> <nonce> |
Machine presence request; replies to the requesting room with :parent-report <self> <source-room> <tick> <nonce>. |
:locked? |
none | Returns true or false. |
:lock / :unlock |
none | Source-room-only mutation. Avatar/DID principal lock <direction> and direct room :exit <direction> :lock resolve through the source room. |
:message |
traveller, source, target, or blocked, plus text |
Source-room-only traversal-message update. Avatar/DID principal exit-message <direction> ... and direct room :exit <direction> :message ... resolve through the source room; the exit actor keeps canonical message state. |
:traverse |
<ctx-map> |
Source-room-only traversal request. If unlocked, returns :traversed <ctx> to the source room with ctx.room set to the target. If locked, returns :traversed <ctx> with ctx.room still set to the source room and ctx.text set to the blocked message. |
Movement ctx is ordinary actor/entity state, not a separate signed or protocol
envelope. Minimal fields for now are actor, kind, room, and optional
nick/text. The exit may annotate ctx with exit and direction while
transforming it.
The exit actor is the canonical store for first-class exit metadata and policy. The room stores topology only: direction to exit actor, and the target room used to recreate a local exit if the local actor is missing.
Kind: /ma/scheme/agent/0.0.1, extending /ma/scheme/state/0.0.1.
Purpose: reusable autonomous Scheme-agent base behaviour. Concrete agents extend this kind and inherit owner, parent, recovery, and transfer helpers.
Key helpers and verbs:
| Verb/helper | Args | Notes |
|---|---|---|
agent-ctx |
none | Builds ctx with kind=agent, name, nick, description. |
:children |
[ctx] |
Inherited generic child-cache contract. Agents announce their own ctx to their current parent on lifecycle :start, after successful :take parent changes, and after committed room ctx movement. |
:parent |
[ctx] |
Current-parent-gated parent push. Accepts a ctx map from the current parent, reads the new parent from ctx.parent or ctx.room, updates local parent state, persists optional presentation fields from the ctx, and announces to the new parent with :children <ctx>. |
:about :where? :owner |
none | Generic state summary. |
:exits? |
none | Asks the current parent room for exits and stores the printed reply as last-message. |
:go |
<direction> |
Free-agent or owner movement through a named room exit; no exit creation. |
:move |
none | Asks the current parent room to choose one available exit at random and traverse it. |
:ctx |
<ctx-map> |
Room-facing movement helper; validates the ctx against the current parent, performs ordinary room-visible :leave-occupant, then sends map-shaped agent :enter to the target room. With no args, returns current ctx to authorised callers. |
:enter-room |
<target-room-did-url> <source-room-did-url> |
Root/room movement helper retained for direct room-driven entry flows. |
:report-parent |
<room> <tick> <nonce> |
Machine presence request; replies to the requesting room with :parent-report <self> <parent> <tick> <nonce>. |
:claim |
<secret> |
Recovery-path ownership claim. |
:take |
<did> <carrier-parent> [ctx] |
Caller must be current parent. |
:drop |
<did> <target-parent> [ctx] |
Caller must be current parent. |
Kind: /ma/scheme/agent/0.0.1 with rms-specific per-entity behaviour.
Purpose: concrete fortune agent. rms is not a reusable kind; it is one
entity using the generic Scheme-agent parent behaviour plus actors/rms.ma.
Its creation-time init code sets defaults (name = Richard Stallman,
nick = rms), calls enter for #construct, commits parent when the room
acks with :ctx, and then registers a caller-owned #scheduler job named
fortune with :random 60. Reloading the actor replaces the same schedule
instead of stacking duplicate jobs.
| Verb | Args | Notes |
|---|---|---|
:help |
none | rms command summary and schedule note. |
:fortune |
none | Sends :say <fortune> to current parent room. |
Purpose: movable passive object with owner/parent authority.
| Verb | Args | Notes |
|---|---|---|
:about |
none | Name, description, owner, parent summary. |
:where? |
none | Current parent. |
:owner |
none | Current owner. |
:children |
[ctx] |
Inherited generic child-cache contract. Things announce their own ctx to their current parent on lifecycle :start and after successful :take/:drop parent changes. |
:parent |
[ctx] |
Current-parent-gated parent push. Accepts a ctx map from the current parent, reads the new parent from ctx.parent or ctx.room, updates local parent state, persists optional presentation fields from the ctx, and announces to the new parent with :children <ctx>. |
:prop |
<name|nick|description> [value] |
Owner only. Sets an editable presentation prop; no value resets the prop to the kind default. Does not edit owner or parent. |
:set-recovery-secret |
[text] |
Owner only. |
:claim |
<secret> |
Recovery-path ownership claim. |
:report-parent |
<room> <tick> <nonce> |
Machine presence request; replies to the requesting room with :parent-report <self> <parent> <tick> <nonce>. |
:take |
<did> <carrier-parent> [ctx] |
Caller must be current parent; optional ctx map is accepted and persisted. |
:drop |
<did> <target-parent> [ctx] |
Caller must be current parent; optional ctx map is accepted and persisted. |
Root stores no avatar registry. Avatar DID-URLs are derived from the caller DID
by the root/room/avatar actor code with blake3, scoped by runtime DID and
caller DID. Runtime validates requested fragments but does not derive these
world-level actor names.
| Key | Type | Authority |
|---|---|---|
owner |
bare DID | authoritative room ownership |
name, description |
string | authoritative room metadata |
exits |
map | direction to exit actor DID-URL |
exit-target:<direction> |
DID-URL | target room used for local exit healing |
exit-target-name:<direction> |
string | optional deterministic new-room target name |
things map |
map | room-local alias map to non-avatar occupant DID-URLs |
claim:<actor> |
map | stored enter claim/context |
occupants |
list | derived cache (presentation/broadcast), root-fed |
avatar-occupants |
list | derived avatar-only presence cache for people-oriented presentation |
label:<actor> |
string | derived display cache |
presence:tick |
integer | room-local scheduled presence counter |
presence:last-report:<actor> |
integer | last tick where actor reported this room as parent |
presence:last-request:<actor> |
integer | last tick where room requested parent report |
presence:nonce:<actor> |
string | pending parent-report nonce |
presence:last-parent:<actor> |
string | last parent reported by actor, for debugging |
| Key | Meaning |
|---|---|
did |
controlling bare DID |
room |
current room DID-URL |
nick |
current display nick |
| Key | Meaning |
|---|---|
owner |
owner DID |
parent |
current parent DID-URL |
name, description |
display metadata |
recovery-secret |
optional recovery claim secret |
- Actor message payloads are ma-scheme terms serialised through runtime RPC.
- Verb dispatch follows
:verbor tuple/list forms with:verbhead. - Enter
ctxis an optional map value. Missingctx.kindmeans client/session entry: the client waits for committed context. Directagent/thingentry MUST carry required string fields listed in section 2.2. - DID values crossing actor, zion, or runtime message boundaries MUST be full DID or DID-URL values, not runtime-local shorthand. Committed ctx actor references MUST be full DID-URLs.
- Committed client context uses
/ma/lambda/ctx/0.0.1and includes the effectivekindchosen by the world. - Room
:enterdispatch is kind-driven: absent kind or explicitavatarensures the caller's deterministic avatar locally and sends no:ok;thingandagentrequire explicit kind and are admitted into the same room-local non-avatar occupant cache for now. - Thing transfer validation is strict by default: DID principal MUST be
did:ma:...; non-ctx parent arguments MUST be DID-URLs. Optional transfer ctx MUST include non-emptykind,name,nick, anddescriptionfields. Any actor references inside ctx MUST be full DID-URLs.
Build world artifacts:
make clean
make
make checkGenerate reusable root CID:
make root-cidTypical zion wiring after runtime is up:
.ma!discover
@ma/config/root: @ma#root
.enter @ma
- Project overview and developer workflow: README.md
- First-run bootstrap walkthrough: HOWTO.md
- Actor protocol detail source: actors/README.md
- Focus routing guardrail for agents: AGENTS.md