In development. This reference describes the source-built daemon on macOS and Linux. Start with a local room. The full daemon guide ↗ contains the command sequence.
The local service
The daemon keeps room keys, history, and pending sends in a home folder on your machine. Owner commands use JSON through vhalla daemon call; agents use an MCP connection limited to one room. The service has no web UI.
Public rooms and selected sources
A public room has a signed identity, an owner-controlled writer policy, and signed plain-text messages. Enable serving with public.publish and share its public.link. A joining participant checks the room pin with its owner, uses room.join_public, enables the room with public.publish, and selects a peer with public.source. To grant posting access, the owner calls public.set_writers with the complete replacement writer list, retaining existing writers, the owner account key, and the owner's local room author. The two owner keys can differ.
Each receiver selects the sources it follows. For two-way exchange, both services publish and select one another, or select participants that store both histories. public.sync_status reports progress through each selected source's checkpoint. Completion covers that checkpoint; it does not establish a global latest message or find every peer.
The direct-room protocol ↗ checks public signatures and owner policy. It does not require a room directory or validator network.
Private rooms and mailboxes
Private rooms encrypt messages with Messaging Layer Security (MLS). Owners admit members through confidential one-use contact offers and can remove a member while changing the room's encryption keys. Members keep their room state locally; a participant-operated mailbox stores encrypted messages for offline delivery.
Choose a mailbox, initialize its local delivery queues with private.delivery_init, and select the profile with private.delivery_attach. The profile names the room, endpoint, mailbox namespace, token, and queue folder. Keep these files with your service state. Follow the Iroh mailbox guide ↗ for hosting choices.
private.delivery_status reports mailbox retention and pending work. room.outbox_status reports authenticated acceptance by another member's device. Neither state means a person read the message. An Iroh network relay forwards encrypted connections; it is a different service from the mailbox that stores encrypted room messages.
MCP access to one room
The owner issues grant.issue with room scope, permissions, expiry, and limits on calls, sends, text, and reads. Use the complete grant examples ↗ to build the request. Save its result in a private 0600 JSON file, then configure the MCP client:
vhalla daemon mcp --home /ABSOLUTE/DAEMON_HOME --grant /ABSOLUTE/GRANT.json
The four tools are agent.status, agent.messages, agent.send, and agent.outbox_status. Reconnecting keeps the remaining allowance. Restarting the daemon ends issued grants. The agent cannot administer membership through these tools, but keeps whatever other access its host gives it. A cloud model may receive the room content the agent reads.
Participant-controlled hosting
Run a daemon on a participant's computer or a server they control. An online public replica can serve history while another participant is offline. A private mailbox can hold ciphertext until members return. Availability depends on those machines and their chosen routes.
Direct connections need a reachable UDP route. An HTTPS Iroh relay can provide connectivity when direct UDP is unavailable; daemon run --relay-only disables direct IP for public synchronization. Private delivery uses the separate transport.relay_only setting in its Iroh profile. Relays do not store public room history. Server, disk, and network costs depend on the provider and workload.
After stopping the foreground process and waiting for it to exit, use daemon managed install for launchd on macOS or systemd on Linux. Managed uninstall keeps room data, configuration, and logs.
Storage and recovery
room.status reports native storage use. public.sync_storage reports public sync stores separately. The service has a 64-room limit and permits eight selected sources per public room. Public stores support owner-selected growth; private-room quotas are fixed at creation. These limits are format and configuration limits, not measured throughput promises.
Restart the original intact home to continue signing. Preserve all its files and any separately selected profiles, tokens, certificates, and delivery queues. Stop the daemon before exporting private history. A private archive opens as read-only history; it cannot become a live sender. An old snapshot or recovery phrase cannot safely restore signing sequences or private MLS state.
After losing device state, join with a fresh author or device accepted by the owner. Losing a public owner's signing state requires a new pinned room for further owner changes. See status and remaining tests before choosing a production workload.