Each channel is a room. Each room has a computer. Everything else is emergent.
╔════════════════════════════════════════════════════════════╗
║ ║
║ ┌──────────┐ linz exec ┌──────────┐ ║
║ │ #forge │ ────────────────▶ │ #vault │ ║
║ │ ⚒️ VM │ │ 🔐 VM │ ║
║ └────┬─────┘ └────┬─────┘ ║
║ │ │ ║
║ │ linz exec │ linz exec ║
║ ▼ ▼ ║
║ ┌──────────┐ linz exec ┌──────────┐ ║
║ │ #tavern │ ◀──────────────── │ #arena │ ║
║ │ 🍺 VM │ │ ⚔️ VM │ ║
║ └──────────┘ └──────────┘ ║
║ ║
║ Kandan World: Channels as Rooms ║
║ ║
╚════════════════════════════════════════════════════════════╝
Kandan is a chat platform (think Slack/Discord) with integrated terminals and AI agents. This proposal reimagines it as a MUD (Multi-User Dungeon) - a multiplayer programmable world where every channel is a room backed by a full Linux VM via Linz.
The key insight: don't build a game engine into the platform. Instead, give every room a computer and let users and their AI agents build whatever they want.
Every channel gets a dedicated Linz VM - a full Linux box. No platform-provided quest systems, item schemas, or rule engines. Users write real code: shell scripts, Python, SQLite databases, web servers, whatever they need.
┌─── Channel: #forge ─────────────────────────────────────────────────┐
│ │
│ 💬 Chat Layer 🖥️ Terminal Layer │
│ ┌────────────────────┐ ┌──────────────────────────────────────┐ │
│ │ Player: forge │ │ $ tmux attach -t forge │ │
│ │ iron-sword │ │ > Running forge.sh ... │ │
│ │ │ │ > Checking inventory: 2 iron-ore │ │
│ │ Forge Bot: The │ │ > Consuming materials... │ │
│ │ hammer strikes! │ │ > Item created: iron-sword │ │
│ │ You forged an │ │ > Posting to #forge chat │ │
│ │ iron-sword! 🗡️ │ │ $ │ │
│ └────────────────────┘ └──────────────────────────────────────┘ │
│ │
│ 🐧 Linz VM (Full Linux) │
│ ┌──────────────────────────────────────────────────────────────────┐│
│ │ /home/linz/ ││
│ │ state/ ││
│ │ recipes.json {"iron-sword": {"iron-ore": 2}} ││
│ │ players/ ││
│ │ sgrove.json {"iron-ore": 5, "gold": 120} ││
│ │ scripts/ ││
│ │ forge.sh game logic ││
│ │ shop.sh buy/sell ││
│ │ .kandan/ ││
│ │ hooks/ ││
│ │ on_message.sh event-driven triggers ││
│ │ auth.json channel credentials ││
│ └──────────────────────────────────────────────────────────────────┘│
└──────────────────────────────────────────────────────────────────────┘
Every user has access to coding agents (Codex CLI sessions). Non-technical users don't need the platform to parse natural language - their agent writes the code for them:
┌───────────────────────────────────────────────────────────────────┐
│ │
│ User: "Hey @agent, make this room a blacksmith shop. │
│ When someone says 'forge <item>', check if they │
│ have the materials and create the item." │
│ │
│ │ │
│ ▼ │
│ │
│ ┌─ Agent (Codex Session) ──────────────────────────────────────┐ │
│ │ │ │
│ │ 1. Writes /home/linz/scripts/forge.sh │ │
│ │ 2. Writes /home/linz/.kandan/hooks/on_message.sh │ │
│ │ 3. Creates /home/linz/state/recipes.json │ │
│ │ 4. Creates /home/linz/state/players/ directory │ │
│ │ │ │
│ │ "Done! The forge is ready. Try: forge iron-sword" │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ The platform didn't parse anything. │
│ The agent wrote a bash script with a regex. │
│ The platform didn't need an item system. │
│ The agent created JSON files. │
│ │
│ ✨ The platform provides rooms with computers. │
│ Agents build everything else. │
│ │
└───────────────────────────────────────────────────────────────────┘
Every room's VM has a unique ID. Know the ID? You can execute commands on it. VM IDs are tradeable secrets - keys to rooms.
┌────────────────┐
│ #library │
│ 📚 VM │
│ │
│ Puzzle clue │
│ reveals: │
│ "lz-a8f3b2" │──── VM ID exposed
└───────┬────────┘ as narrative!
│
│ Player now knows
│ the vault's VM ID
│
▼
linz exec lz-a8f3b2 -- cat /home/linz/state/treasure.json
│
▼
┌────────────────┐
│ #vault │
│ 🔐 VM │
│ │
│ treasure: │
│ legendary │
│ dragon-axe │
└────────────────┘
┌───────────────────────────────────────────────────┐
│ VM IDs as game mechanics: │
│ │
│ 🔑 Discovery - find IDs through puzzles │
│ 🤝 Trading - "I'll trade vault access │
│ for 3 dragon scales" │
│ 🕵️ Espionage - steal IDs, sabotage rooms │
│ 🔒 Revocation - regenerate ID = change lock │
│ 📜 Quests - IDs as quest rewards │
└───────────────────────────────────────────────────┘
Two directions of communication make the world feel alive:
Chat → VM (Events trigger computation) VM → Chat (Results narrate the story)
────────────────────────────────────── ─────────────────────────────────────
Player says Agent receives Script runs Script posts
"forge iron-sword" message via WS game logic results to chat
│ │ │ │
▼ ▼ ▼ ▼
┌──────────┐ ┌───────────┐ ┌───────────┐ ┌─────────────┐
│ Chat │─────▶│ Agent │─────────▶│ VM Hook │─────────▶│ kandan send │
│ Message │ WS │ (Codex) │ linz exec│ Script │ kandan │ "#forge" │
└──────────┘ └───────────┘ └───────────┘ CLI └─────────────┘
A lightweight tool provisioned in every VM:
kandan send <channel> <message> Post a message
kandan send <channel> --as system <message> Post as system notice
kandan read <channel> [--since SEQ] [--limit N] Read recent messages
kandan mentions [--unread] Check @mentions
kandan channels List joined channels
kandan channel-info <channel> Get metadata + VM ID
kandan members <channel> List channel members
kandan react <channel> <seq> <emoji> Add a reaction
Convention-based event handlers that agents create and manage:
/home/linz/.kandan/hooks/
on_message.sh ← receives message JSON on stdin
on_mention.sh ← fires when someone @mentions the room's agent
on_join.sh ← fires when a new member joins
on_reaction.sh ← fires when someone reacts
┌───────────────────────────────────────────────────────────────────────┐
│ │
│ 🏪 NPC Agent Room-bound character │
│ Assigned to one channel. Maintains room state. │
│ Example: shopkeeper in #marketplace, guard at #gate │
│ │
│ 🧙 Personal Agent User companion │
│ Follows a user across channels. │
│ Assistant, translator, inventory manager. │
│ │
│ 🌍 World Agent Omnipresent narrator │
│ Membership in ALL channels. Global state. │
│ Cross-room rules, world events, DM orchestration. │
│ │
│ 📜 Quest Agent Temporary, purpose-built │
│ Spun up for a specific quest or storyline. │
│ Manages quest state, checkpoints, rewards. Despawns on complete. │
│ │
└───────────────────────────────────────────────────────────────────────┘
Agent Cognitive Loop:
─────────────────────
1. LISTEN ──▶ Receive message from channel WebSocket
2. DECIDE ──▶ Is this worth responding to? (LLM-gated)
3. CONTEXT ─▶ Load channel memory (summary.md, facts.json)
4. ACT ─────▶ Generate response and/or execute VM commands
5. REMEMBER ▶ Update memory artifacts with new facts/state
┌──────────────┐
│ #entrance │
│ 🚪 Gate NPC │
│ │
│ "Welcome, │
│ adventurer" │
└──────┬───────┘
│
┌───────────┼───────────┐
│ │
┌──────▼───────┐ ┌───────▼──────┐
│ #forge │ │ #library │
│ ⚒️ Smith │ │ 📚 Sage │
│ │ │ │
│ Craft items │ │ Solve puzzle │
│ from ore │ │ to get key │
└──────┬───────┘ └──────┬───────┘
│ │
│ ┌───────▼──────┐
│ │ #vault │
│ │ 🔐 Treasure │
│ │ │
│ │ Legendary │
│ │ loot inside │
│ └──────────────┘
│
┌──────▼───────┐
│ #boss-room │
│ 🐉 Dragon │
│ │
│ Final battle │
│ Save points │
│ via linz fork│
└──────────────┘
╔══════════════════════════════════════════════════════════════════╗
║ #forge ║
╠══════════════════════════════════════════════════════════════════╣
║ ║
║ 🧙 sgrove: forge iron-sword ║
║ ║
║ ⚒️ Forge Bot: The hammer strikes! You forged an iron-sword! 🗡️ ║
║ The blade glows with heat. (+5 attack) ║
║ ║
║ ┌─ System ───────────────────────────────────────────────────┐ ║
║ │ 📢 #marketplace was notified of the new item │ ║
║ └────────────────────────────────────────────────────────────┘ ║
║ ║
║ 🧙 sgrove: check inventory ║
║ ║
║ ⚒️ Forge Bot: ║
║ ┌────────────────────────────────────────┐ ║
║ │ 📦 Inventory - sgrove │ ║
║ │ ───────────────────────────────────── │ ║
║ │ 🗡️ iron-sword ×1 +5 ATK │ ║
║ │ 🪨 iron-ore ×3 │ ║
║ │ �ite coal ×2 │ ║
║ │ 💰 gold 120 │ ║
║ │ │ ║
║ │ Weight: 12/50 │ ║
║ └────────────────────────────────────────┘ ║
║ ║
╚══════════════════════════════════════════════════════════════════╝
╔══════════════════════════════════════════════════════════════════╗
║ #library ║
╠══════════════════════════════════════════════════════════════════╣
║ ║
║ 📚 Sage: Among these ancient tomes, one book seems different... ║
║ ║
║ 🧙 sgrove: examine the different book ║
║ ║
║ 📚 Sage: The book's spine reads: ║
║ ║
║ ┌────────────────────────────────────────┐ ║
║ │ │ ║
║ │ ╔═════════════════════════════╗ │ ║
║ │ ║ V A U L T ║ │ ║
║ │ ║ lz-a8f3b2c1 ║ │ ║
║ │ ╚═════════════════════════════╝ │ ║
║ │ │ ║
║ │ The letters shimmer and fade... │ ║
║ └────────────────────────────────────────┘ ║
║ ║
║ 💡 You now have the VM ID for #vault! ║
║ Use: linz exec lz-a8f3b2c1 -- <command> ║
║ ║
╚══════════════════════════════════════════════════════════════════╝
╔══════════════════════════════════════════════════════════════════╗
║ DM: spy → guild-leader ║
╠══════════════════════════════════════════════════════════════════╣
║ ║
║ 🕵️ spy: Got their armory VM ID: lz-b7e2d4f9 ║
║ ║
║ 👑 guild-leader: @war-agent sabotage their armory. ║
║ Replace weapon recipes with broken ones. ║
║ ║
║ ⚔️ war-agent: Done. Their next batch will be... disappointing. ║
║ ║
╠══════════════════════════════════════════════════════════════════╣
║ ║
║ Meanwhile, in enemy #armory: ║
║ ║
║ 🛡️ soldier: forge legendary-axe ║
║ ⚒️ Armory NPC: Forged! The legendary axe deals... 1 damage. ║
║ Something is terribly wrong. ║
║ ║
╚══════════════════════════════════════════════════════════════════╝
Linz VMs are backed by btrfs copy-on-write snapshots. This gives free save/load semantics:
Main Timeline
═══════════════════════════════════════════════════▶
──●──────────●──────────●──────────●──────────▶
│ │ │ │
│ Save Point Save Point Current
│ "pre-boss" "mid-fight" State
│
└──── linz fork checkpoint-before-boss-fight
│
│ Alternate Timeline (what-if?)
└────●──────────●──────────▶
│ │
"chose door A" "TPK 💀"
│
└── Rollback to "pre-boss"!
# Save current state (instant, zero-cost)
linz fork checkpoint-before-boss-fight
# Something goes wrong? Restore.
linz restore checkpoint-before-boss-fight
# Branch a parallel timeline
linz fork what-if-door-a
linz exec what-if-door-a -- /home/linz/scripts/open_door.sh A┌──────────────────┬──────────────────┬────────────────────────────────┐
│ Kandan Concept │ MUD Equivalent │ How It Works │
├──────────────────┼──────────────────┼────────────────────────────────┤
│ Public channel │ Town square │ Open to all, VM accessible │
│ │ │ to members │
├──────────────────┼──────────────────┼────────────────────────────────┤
│ Private channel │ Guild hall │ Invite-only, VM ID is the │
│ │ │ "key" to the room │
├──────────────────┼──────────────────┼────────────────────────────────┤
│ DM │ Whisper │ Trade VM IDs, share quest │
│ │ │ hints, negotiate deals │
├──────────────────┼──────────────────┼────────────────────────────────┤
│ Group DM │ Party chat │ Coordinate dungeon raids, │
│ │ │ plan attacks │
├──────────────────┼──────────────────┼────────────────────────────────┤
│ Workspace │ Game server │ Complete isolation, different │
│ │ │ workspaces = different worlds │
└──────────────────┴──────────────────┴────────────────────────────────┘
D&D sessions are chaotic. Players go off-script. New rooms get improvised. Side quests spawn out of nowhere.
DM: "You discover a hidden cave behind the waterfall"
┌──────────────────────────────────────────────────────────┐
│ │
│ World Agent: │
│ │
│ 1. linz create ──▶ Spin up new VM (instant) │
│ 2. Deploy cave template scripts │
│ 3. Spawn NPC agent for cave │
│ 4. Create #hidden-cave channel │
│ 5. Link to dungeon graph │
│ │
│ Total time: seconds │
│ │
└──────────────────────────────────────────────────────────┘
Players finish the cave? Quest complete?
┌──────────────────────────────────────────────────────────┐
│ │
│ World Agent: │
│ │
│ 1. Archive cave state (linz fork archive-cave-session) │
│ 2. Despawn NPC agent │
│ 3. Tear down VM │
│ 4. Archive or close channel │
│ │
│ Resources freed. Story preserved. │
│ │
└──────────────────────────────────────────────────────────┘
Rapid cluster spin-up/spin-down means the DM or World Agent can generate new rooms on the fly, fork existing ones for alternate timelines, and clean up when quests complete - matching the improvised, chaotic nature of D&D.
┌───────────────────────────────────────────────────────────────────┐
│ KANDAN MUD PLATFORM │
├───────────────────────────────────────────────────────────────────┤
│ │
│ What the platform provides: What users/agents build: │
│ ─────────────────────────── ──────────────────────── │
│ ✅ Channels (rooms) 🎮 Game mechanics │
│ ✅ Linz VMs (computers per room) 📦 Item systems │
│ ✅ Chat ↔ VM bridge (kandan CLI) ⚔️ Combat engines │
│ ✅ Cross-room exec (linz exec) 📜 Quest logic │
│ ✅ Snapshots (linz fork) 🏪 Economies │
│ ✅ Agent runtime (Codex sessions) 🗺️ World maps │
│ ✅ WebSocket event delivery 🧩 Puzzles │
│ ✅ DMs, groups, workspaces 🏰 Guilds & factions │
│ 📊 Dashboards & TUIs │
│ │
│ The platform is minimal. Everything else is emergent. │
│ │
└───────────────────────────────────────────────────────────────────┘
| Phase | Timeline | Focus | Success Metric |
|---|---|---|---|
| 1. The Bridge | Weeks 1-2 | kandan CLI, hook conventions, VM ID visibility |
A VM script can post a message to its channel |
| 2. Agent NPCs | Weeks 3-4 | NPC/Personal/World agent templates, status indicators | NPC responds to game commands via hook scripts |
| 3. World Building | Weeks 5-8 | Example dungeon, template VMs, quest conventions | Non-technical user builds a custom room in <30 min |
| 4. Rich UI | Weeks 9+ | Terminal split views, TUI dashboards, web embeds | Live world map alongside chat messages |
Built with Linz - where every room has a computer, and every computer is a world.