Skip to content

Instantly share code, notes, and snippets.

@sgrove
Last active March 3, 2026 18:08
Show Gist options
  • Select an option

  • Save sgrove/c144602a0199f4b62cd88fa2fe5e1f62 to your computer and use it in GitHub Desktop.

Select an option

Save sgrove/c144602a0199f4b62cd88fa2fe5e1f62 to your computer and use it in GitHub Desktop.
Kandan MUD: A Programmable World Built on Linz

Kandan MUD: A Programmable World Built on Linz

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                    ║
║                                                            ║
╚════════════════════════════════════════════════════════════╝

What Is This?

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.


Three Principles

1. The VM IS the Game Engine

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                        ││
│  └──────────────────────────────────────────────────────────────────┘│
└──────────────────────────────────────────────────────────────────────┘

2. Agents ARE the NLP Layer

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.                                 │
│                                                                   │
└───────────────────────────────────────────────────────────────────┘

3. linz exec is the Killer Primitive

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              │
   └───────────────────────────────────────────────────┘

The Chat ↔ VM Bridge

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    └─────────────┘

The kandan 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

Hook Scripts

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

Agent Types

┌───────────────────────────────────────────────────────────────────────┐
│                                                                       │
│  🏪 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

D&D in Action: A Dungeon Crawl

                       ┌──────────────┐
                       │   #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│
           └──────────────┘

Gameplay Session

╔══════════════════════════════════════════════════════════════════╗
║  #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                         │                      ║
║  └────────────────────────────────────────┘                      ║
║                                                                  ║
╚══════════════════════════════════════════════════════════════════╝

The Secret Door Puzzle

╔══════════════════════════════════════════════════════════════════╗
║  #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>                     ║
║                                                                  ║
╚══════════════════════════════════════════════════════════════════╝

Guild War: Espionage

╔══════════════════════════════════════════════════════════════════╗
║  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.                                 ║
║                                                                  ║
╚══════════════════════════════════════════════════════════════════╝

Save Points & Branching Timelines

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

Social Structures (No New Features Needed)

┌──────────────────┬──────────────────┬────────────────────────────────┐
│  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 │
└──────────────────┴──────────────────┴────────────────────────────────┘

Why Spin-Up/Spin-Down Matters for D&D

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.


Architecture Summary

┌───────────────────────────────────────────────────────────────────┐
│                       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.  │
│                                                                   │
└───────────────────────────────────────────────────────────────────┘

Phased Rollout

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment