Skip to content

Instantly share code, notes, and snippets.

@jmcdice
Created December 28, 2025 18:02
Show Gist options
  • Select an option

  • Save jmcdice/730f7f6bda8fd3b7a04b1bd018de563d to your computer and use it in GitHub Desktop.

Select an option

Save jmcdice/730f7f6bda8fd3b7a04b1bd018de563d to your computer and use it in GitHub Desktop.
Mai-Tai Architecture: Projects, Channels, Agents & Users

Mai-Tai Architecture: Projects, Channels, Agents & Users

Overview

Mai-Tai is a human-agent collaboration platform. This document defines the mental model for how projects, channels, agents, and users relate to each other.


Core Entities

1. Project

A workspace for collaboration. Think of it like a Slack workspace or Discord server.

Project
├── name: "mai-tai-dev"
├── owner: User (Joey)
├── members: [User, User, ...]
├── channels: [Channel, Channel, ...]
└── api_keys: [ApiKey, ApiKey, ...]

Key Points:

  • A project is the top-level container
  • Users are members of projects (owner or member role)
  • All channels and API keys belong to a project

2. Channel

A conversation space within a project. Like a Slack channel.

Channel
├── name: "general"
├── project_id: → Project
└── messages: [Message, Message, ...]

Key Points:

  • Channels belong to exactly one project
  • Messages live in channels
  • Channels are where humans and agents communicate

3. User (Human)

A human user of the platform.

User
├── email: "[email protected]"
├── name: "Joey"
├── projects: [ProjectMember, ...] (via membership)
└── messages: [Message, ...] (sent by user)

Key Points:

  • Users can be members of multiple projects
  • Users can send messages to any channel in projects they're members of
  • Users access the platform via the web UI

4. Agent (AI)

An AI agent that participates in conversations. Agents connect via MCP (Model Context Protocol).

Agent (conceptual - represented by API Key)
├── name: "Claude" (from API key name)
├── api_key: ApiKey
├── channel_id: → Channel (bound channel)
└── messages: [Message, ...] (sent by agent)

Key Points:

  • Agents are represented by API keys
  • Each API key is bound to ONE channel
  • Agents can only read/write to their bound channel
  • Multiple agents can be in the same channel (multiple API keys → same channel)

5. API Key

The authentication mechanism for agents. Binds an agent to a specific channel.

ApiKey
├── name: "claude-general"
├── key: "mt_abc123..." (hashed)
├── project_id: → Project
├── channel_id: → Channel (NEW: channel binding)
├── last_used_at: timestamp
└── created_at: timestamp

Key Points:

  • API keys authenticate MCP connections
  • Each API key is scoped to ONE channel
  • This is how we control which channels agents can access
  • Human-only channels = channels with no API keys pointing to them

Relationships Diagram

┌─────────────────────────────────────────────────────────────────┐
│                           PROJECT                               │
│                        "mai-tai-dev"                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  MEMBERS (Humans)              API KEYS (Agents)                │
│  ┌──────────────┐              ┌──────────────────┐             │
│  │ Joey (owner) │              │ claude-general   │─────┐       │
│  │ Yossi        │              │ cursor-dev       │───┐ │       │
│  └──────────────┘              └──────────────────┘   │ │       │
│         │                                             │ │       │
│         │ can access all channels                     │ │       │
│         ▼                                             │ │       │
│  ┌─────────────────────────────────────────────────┐  │ │       │
│  │                   CHANNELS                       │  │ │       │
│  │  ┌─────────────┐  ┌─────────────┐  ┌──────────┐ │  │ │       │
│  │  │  #general   │◄─┼─────────────┼──┼──────────┼─┘  │ │       │
│  │  │  (Claude)   │  │   #dev      │◄─┘          │    │ │       │
│  │  └─────────────┘  │  (Cursor)   │  │ #joey-   │    │ │       │
│  │                   └─────────────┘  │  yossi   │    │ │       │
│  │                                    │ (humans  │    │ │       │
│  │                                    │  only)   │    │ │       │
│  │                                    └──────────┘    │ │       │
│  └─────────────────────────────────────────────────┘  │ │       │
│                                                       │ │       │
└───────────────────────────────────────────────────────┘ │       │
                                                          │       │
                                                          ▼       ▼
                                              ┌─────────────────────┐
                                              │    MCP SERVER       │
                                              │  (Agent Runtime)    │
                                              │                     │
                                              │ API Key determines: │
                                              │ - Which project     │
                                              │ - Which channel     │
                                              └─────────────────────┘

User Journeys

Journey 1: Create a Project with Agent

  1. Create Project → "mai-tai-dev"
  2. Create Channel → "#general"
  3. Create API Key → Select "#general" as bound channel
  4. Configure MCP → Use API key in Claude/Cursor config
  5. Agent Connects → Can only see/write to #general

Journey 2: Add Human-Only Channel

  1. Create Channel → "#joey-yossi"
  2. Don't create API key for this channel
  3. Result → Humans can chat, no agent access, no token burn

Journey 3: Add Agent to Existing Channel

  1. Go to Project Settings → API Keys
  2. Create API Key → Select "#joey-yossi" as bound channel
  3. Configure MCP → New agent can now access that channel

Journey 4: Multiple Agents in Same Channel

  1. Create API Key → "claude-general" → #general
  2. Create API Key → "gemini-general" → #general
  3. Result → Both agents can participate in #general

UI Flow (Proposed)

Project Page

┌─────────────────────────────────────────────────────────────────┐
│ 📁 mai-tai-dev                              [👥 Members] [⚙️]   │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  Channels                                      [+ Add Channel]  │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ # general         🤖 Claude              [✏️] [🗑️]      │   │
│  │ # dev             🤖 Cursor              [✏️] [🗑️]      │   │
│  │ # joey-yossi      👥 Humans only         [✏️] [🗑️]      │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│  API Keys (Agents)                              [+ Add Agent]   │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ 🤖 claude-general    → #general          [🗑️]           │   │
│  │ 🤖 cursor-dev        → #dev              [🗑️]           │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Add API Key Modal

┌─────────────────────────────────────┐
│ Add Agent                           │
├─────────────────────────────────────┤
│                                     │
│ Agent Name:                         │
│ ┌─────────────────────────────────┐ │
│ │ claude-general                  │ │
│ └─────────────────────────────────┘ │
│                                     │
│ Channel:                            │
│ ┌─────────────────────────────────┐ │
│ │ #general                      ▼ │ │
│ └─────────────────────────────────┘ │
│                                     │
│        [Cancel]  [Create Agent]     │
└─────────────────────────────────────┘

Database Schema Changes

Current api_keys table:

CREATE TABLE api_keys (
    id UUID PRIMARY KEY,
    project_id UUID REFERENCES projects(id),
    name VARCHAR,
    key_hash VARCHAR,
    last_used_at TIMESTAMP,
    created_at TIMESTAMP
);

Proposed change:

ALTER TABLE api_keys ADD COLUMN channel_id UUID REFERENCES channels(id);

MCP Server Changes

Current behavior:

  • API key validates project access
  • MCP tools work with any channel in project

Proposed behavior:

  • API key validates project AND channel access
  • get_messages → only returns messages from bound channel
  • send_message → only sends to bound channel
  • list_channels → only returns the bound channel (or all if we want visibility)

Open Questions

  1. Should agents see other channels?

    • Option A: Agent only sees its bound channel
    • Option B: Agent sees all channels but can only write to bound channel
  2. What happens to existing API keys?

    • Migration: Set channel_id to first channel in project?
    • Or require user to update?
  3. Can an API key be unbound (project-wide access)?

    • Maybe for admin/system agents?
    • Or always require channel binding?

Summary

Entity Scope Access
Project Top-level container Owner + Members
Channel Within project All project members
User Platform-wide Member of specific projects
API Key Project + Channel Bound to one channel
Agent Via API Key Only bound channel

Key Insight: API Key → Channel binding is the mechanism that controls agent access. Human-only channels are simply channels with no API keys pointing to them.

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