Grand Diomande Research · Full HTML Reader

Server Architecture Integration — Aura

Aura currently has a flat thread model: `HubThread` objects live in `hub_threads`, categorized by `ThreadCategory` and `ThreadType`, with no parent container. The Discord ecosystem, however, operates on three distinct architectural patterns — each representing an evolution in how the Clawdbot gateway handles task dispatch and message delivery. This document describes those three patterns in abstract form and specifies how they integrate into Aura as a **secluded feature** that does not interfere with the existing t

Embodied Trajectory Systems architecture technical paper candidate score 62 .md

Full Public Reader

Server Architecture Integration — Aura

Context

Aura currently has a flat thread model: `HubThread` objects live in `hub_threads`, categorized by `ThreadCategory` and `ThreadType`, with no parent container. The Discord ecosystem, however, operates on three distinct architectural patterns — each representing an evolution in how the Clawdbot gateway handles task dispatch and message delivery. This document describes those three patterns in abstract form and specifies how they integrate into Aura as a secluded feature that does not interfere with the existing thread hierarchy.

---

The Three Server Architectures

Architecture 1: Command Dispatch (Koji Pattern)

Abstract model: A stateless request-response loop. The client sends a named command with arguments. The server executes a direct database query, formats the result, and returns it immediately. No task queue, no progress streaming, no persistent connection.

Execution flow:

Client sends command → Server parses command name + args
  → Server executes database query (direct, synchronous)
  → Server formats result as text
  → Server returns result to client
  → Transaction complete. No state retained.

Characteristics:
- Commands are a fixed set: each maps to exactly one query/action
- No model routing — the server IS the executor
- No progress updates — result arrives in one shot
- Stateless — each command is independent, no session continuity
- Response format: plain text, chunked if exceeding size limits

Data requirements:
- Command registry (name → handler function)
- Direct database access (reads from domain-specific tables)
- No task table, no thread table, no message history

When to use: Domain-specific dashboards where you need instant answers from structured data. Sales pipeline queries, inventory lookups, metric summaries.

---

Architecture 2: Flat Task Pipeline (Buf Barista Pattern)

Abstract model: A persistent connection receives messages, classifies them, creates tasks in a queue, dispatches to mesh executors, and streams progress back into the originating channel as flat sequential messages.

Execution flow:

Client sends message → Server classifies task type and model affinity
  → Server creates task record in queue (status: pending)
  → Mesh executor claims task (status: running)
  → Server polls task record every 2 seconds
  → On partial_output change → post progress message to client
  → On status=complete → post final result to client
  → On status=failed → post error to client

Characteristics:
- Intelligent model routing: content analysis determines Claude vs Gemini vs Codex
- Platform affinity: Swift/Xcode tasks route only to macOS executors
- Progress streaming: up to 15 incremental updates per task
- Team decomposition: single request splits into parallel subtasks, results aggregated
- Rate limit awareness: automatic fallback when primary model is throttled
- Channel-to-project mapping: message origin determines working directory
- All messages (progress, results) appear sequentially in the same channel — no spatial isolation

Data requirements:
- Task queue table (`mac_tasks`): content, project, status, model_preference, claimed_by, partial_output, result
- Channel configuration: maps channels to project paths and model preferences
- Mesh device registry: tracks online status, available models, rate limits
- Message history in the channel (flat, chronological)

When to use: Active development workflows where you want to watch work happen in real time. Quick iterations, debugging sessions, single-operator workflows.

---

Architecture 3: Threaded Task Isolation (Cloud Hub Pattern)

Abstract model: Same task pipeline as Architecture 2, but each task spawns a dedicated conversational thread. All progress and results are posted into that thread, not the parent channel. Threads have a managed lifecycle with automatic archival.

Execution flow:

Client sends message → Server classifies and creates task (same as Arch 2)
  → Server spawns a dedicated thread for this task
  → Thread record created in database (status: active)
  → Mesh executor claims task
  → Server polls and posts progress INTO the thread
  → On completion → post color-coded result embed in thread
  → Thread enters decay lifecycle:
      ACTIVE (receiving messages)
        → 2 hours idle → IDLE (warning posted)
        → 1 hour idle → DECAYING
        → next cycle → ARCHIVED (summary posted, thread closed)
  → On server restart → recover orphaned tasks, re-deliver missed results

Characteristics:
- Everything from Architecture 2, plus:
- Spatial isolation: each task has its own conversation space
- Rich formatting: color-coded embeds (green=success, red=failure, blue=decomposed, yellow=synthesizing)
- Lifecycle management: decay loop runs every 60 seconds, auto-archives stale threads
- Crash recovery: on startup, scans for completed tasks with undelivered results
- Thread tracking table: records thread state, message count, last activity
- Parent channel stays clean — only the initial "Task queued" message appears there

Data requirements:
- Everything from Architecture 2, plus:
- Thread tracking table (`discord_threads`): thread_id, parent_channel, task_id, status, message_count, last_activity, archived_at
- Decay configuration: active→idle timeout, idle→archive timeout, check interval
- Embed schema: title, description, color, fields[], footer, timestamp

When to use: Multi-operator environments, high-volume task dispatch, infrastructure operations where you need to track many concurrent tasks without channel noise.

---

Integration into Aura

Design Principle: Secluded Section

These three architectures live in a dedicated feature area that does NOT touch the existing thread hierarchy. The current `ThreadListFeature` → `ThreadDetailFeature` → `AgentChatFeature` chain remains untouched. The server architecture feature is a peer, not a parent.

Where It Lives in the Tab Hierarchy

Existing tabs (unchanged):
  Threads | Quad | Feeds | Dispatch | Fleet | Panes | Content | Timeline | Settings

New addition:
  Threads tab gets a segmented control at the top:
    [Conversations]  [Servers]

  "Conversations" = current thread list (default, unchanged)
  "Servers" = new server architecture section

This keeps the feature discoverable without adding a new tab or disrupting the thread list.

Navigation Hierarchy

Threads Tab
  ├─ Segment: Conversations (existing ThreadListFeature — no changes)
  │   ├─ Thread A (conversation) → AgentChatView
  │   ├─ Thread B (feed) → ThreadDetailView
  │   └─ Thread C (dispatch) → ThreadDetailView
  │
  └─ Segment: Servers (new ServerListFeature)
      ├─ Server: Koji Pipeline (Architecture 1)
      │   ├─ #leads → CommandChannelView
      │   ├─ #accounts → CommandChannelView
      │   └─ #sweeps → CommandChannelView
      │
      ├─ Server: Buf Barista (Architecture 2)
      │   ├─ #bridge → FlatTaskChannelView
      │   ├─ #cc-semantic → FlatTaskChannelView
      │   ├─ #workshop → FlatTaskChannelView
      │   └─ #research → FlatTaskChannelView
      │
      └─ Server: Cloud Hub (Architecture 3)
          ├─ #dispatch → ThreadedTaskChannelView
          │   ├─ Task Thread: "a1b2 — Build REST API" → TaskThreadView
          │   ├─ Task Thread: "c3d4 — Fix auth bug" → TaskThreadView
          │   └─ Task Thread: "e5f6 — Refactor DB" [archived]
          ├─ #pulse-control → ThreadedTaskChannelView
          └─ #infrastructure → ThreadedTaskChannelView

Data Models

HubServer

swift
struct HubServer: Codable, Identifiable, Equatable, Sendable {
    let id: UUID
    let name: String                          // "koji-pipeline", "buf-barista", "cloud-hub"
    var displayName: String                   // "Koji Pipeline", "Buf Barista", "Cloud Hub"
    var description: String?                  // "Sales pipeline command center"
    var icon: String                          // SF Symbol name
    var architectureType: ServerArchitecture  // .commandDispatch, .flatTaskPipeline, .threadedTaskIsolation
    var isDefault: Bool                       // Pre-created servers are default
    var channelCount: Int
    var metadata: [String: String]?
    let createdAt: Date
    var updatedAt: Date
}

enum ServerArchitecture: String, Codable, Sendable {
    case commandDispatch       // Architecture 1 (Koji)
    case flatTaskPipeline      // Architecture 2 (Buf Barista)
    case threadedTaskIsolation // Architecture 3 (Cloud Hub)
}

HubChannel

swift
struct HubChannel: Codable, Identifiable, Equatable, Sendable {
    let id: UUID
    let serverId: UUID                    // FK to HubServer
    let name: String                      // "leads", "bridge", "dispatch"
    var displayName: String               // "#leads", "#bridge", "#dispatch"
    var description: String?
    var categoryGroup: String?            // "sales", "comp-core", "ops" — visual grouping
    var projectPath: String?              // Working directory for task execution
    var modelPreference: ModelPreference  // .claude, .gemini, .any, .codex
    var isReadOnly: Bool                  // Feed channels
    var messageCount: Int
    var lastMessageAt: Date?
    var metadata: [String: String]?
    let createdAt: Date
}

enum ModelPreference: String, Codable, Sendable {
    case claude, gemini, codex, any
}

ServerMessage

Reuse the existing `HubMessage` model. The `threadId` field links to a `HubChannel.id` (channels are conceptually threads in Supabase). No new message model needed.

However, for Architecture 3's task threads, we need:

TaskThread

swift
struct TaskThread: Codable, Identifiable, Equatable, Sendable {
    let id: UUID
    let channelId: UUID                   // Parent channel
    let taskId: UUID?                     // Linked mac_task
    let teamId: UUID?                     // Linked team task
    var name: String                      // "a1b2c3d4 — Build REST API..."
    var status: TaskThreadStatus
    var messageCount: Int
    var lastActivityAt: Date?
    var archivedAt: Date?
    var metadata: [String: String]?
    let createdAt: Date
}

enum TaskThreadStatus: String, Codable, Sendable {
    case active, idle, decaying, archived
}

Supabase Tables

sql
-- New tables (do not modify existing hub_threads / hub_messages)

CREATE TABLE hub_servers (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name TEXT NOT NULL UNIQUE,
    display_name TEXT NOT NULL,
    description TEXT,
    icon TEXT NOT NULL DEFAULT 'server.rack',
    architecture_type TEXT NOT NULL CHECK (architecture_type IN ('command_dispatch', 'flat_task_pipeline', 'threaded_task_isolation')),
    is_default BOOLEAN DEFAULT false,
    channel_count INTEGER DEFAULT 0,
    metadata JSONB,
    created_at TIMESTAMPTZ DEFAULT now(),
    updated_at TIMESTAMPTZ DEFAULT now()
);

CREATE TABLE hub_channels (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    server_id UUID NOT NULL REFERENCES hub_servers(id) ON DELETE CASCADE,
    name TEXT NOT NULL,
    display_name TEXT NOT NULL,
    description TEXT,
    category_group TEXT,
    project_path TEXT,
    model_preference TEXT DEFAULT 'any',
    is_read_only BOOLEAN DEFAULT false,
    message_count INTEGER DEFAULT 0,
    last_message_at TIMESTAMPTZ,
    metadata JSONB,
    created_at TIMESTAMPTZ DEFAULT now(),
    UNIQUE (server_id, name)
);

CREATE TABLE hub_channel_messages (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    channel_id UUID NOT NULL REFERENCES hub_channels(id) ON DELETE CASCADE,
    task_thread_id UUID REFERENCES hub_task_threads(id),  -- NULL for flat messages
    sender_type TEXT NOT NULL,
    sender_id TEXT,
    sender_label TEXT,
    content TEXT NOT NULL,
    content_type TEXT DEFAULT 'text',
    embed_data JSONB,
    reply_to UUID,
    is_progress BOOLEAN DEFAULT false,  -- Progress update vs final message
    metadata JSONB,
    created_at TIMESTAMPTZ DEFAULT now()
);

CREATE TABLE hub_task_threads (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    channel_id UUID NOT NULL REFERENCES hub_channels(id) ON DELETE CASCADE,
    task_id UUID REFERENCES mac_tasks(id),
    team_id UUID,
    name TEXT NOT NULL,
    status TEXT DEFAULT 'active' CHECK (status IN ('active', 'idle', 'decaying', 'archived')),
    message_count INTEGER DEFAULT 0,
    last_activity_at TIMESTAMPTZ DEFAULT now(),
    archived_at TIMESTAMPTZ,
    metadata JSONB,
    created_at TIMESTAMPTZ DEFAULT now()
);

-- Indexes
CREATE INDEX idx_hub_channels_server ON hub_channels(server_id);
CREATE INDEX idx_hub_channel_messages_channel ON hub_channel_messages(channel_id);
CREATE INDEX idx_hub_channel_messages_thread ON hub_channel_messages(task_thread_id);
CREATE INDEX idx_hub_task_threads_channel ON hub_task_threads(channel_id);
CREATE INDEX idx_hub_task_threads_status ON hub_task_threads(status);

-- RLS (basic — lock to authenticated users)
ALTER TABLE hub_servers ENABLE ROW LEVEL SECURITY;
ALTER TABLE hub_channels ENABLE ROW LEVEL SECURITY;
ALTER TABLE hub_channel_messages ENABLE ROW LEVEL SECURITY;
ALTER TABLE hub_task_threads ENABLE ROW LEVEL SECURITY;

CREATE POLICY "authenticated_read_servers" ON hub_servers FOR SELECT TO authenticated USING (true);
CREATE POLICY "authenticated_read_channels" ON hub_channels FOR SELECT TO authenticated USING (true);
CREATE POLICY "authenticated_read_messages" ON hub_channel_messages FOR SELECT TO authenticated USING (true);
CREATE POLICY "authenticated_insert_messages" ON hub_channel_messages FOR INSERT TO authenticated WITH CHECK (true);
CREATE POLICY "authenticated_read_task_threads" ON hub_task_threads FOR SELECT TO authenticated USING (true);

TCA Feature Reducers

ServerListFeature (top-level for the "Servers" segment)

swift
@Reducer
struct ServerListFeature {
    @ObservableState
    struct State: Equatable, Sendable {
        var servers: [HubServer] = []
        var isLoading = false
        @Presents var selectedServer: ServerDetailFeature.State?
    }

    enum Action: Sendable {
        case onAppear
        case serversLoaded([HubServer])
        case selectServer(HubServer)
        case serverDetail(PresentationAction<ServerDetailFeature.Action>)
    }
}

ServerDetailFeature (channel list for a server)

swift
@Reducer
struct ServerDetailFeature {
    @ObservableState
    struct State: Equatable, Sendable {
        var server: HubServer
        var channels: [HubChannel] = []
        var groupedChannels: [String: [HubChannel]] {
            Dictionary(grouping: channels, by: { $0.categoryGroup ?? "General" })
        }
        var isLoading = false
        @Presents var selectedChannel: ChannelFeature.State?
    }

    enum Action: Sendable {
        case onAppear
        case channelsLoaded([HubChannel])
        case selectChannel(HubChannel)
        case channel(PresentationAction<ChannelFeature.Action>)
    }
}

ChannelFeature (behavior depends on server architecture)

This is the key reducer — it adapts its behavior based on the parent server's `architectureType`:

swift
@Reducer
struct ChannelFeature {
    @ObservableState
    struct State: Equatable, Sendable {
        var channel: HubChannel
        var architectureType: ServerArchitecture  // Inherited from parent server
        var messages: [HubChannelMessage] = []
        var taskThreads: [TaskThread] = []        // Only populated for .threadedTaskIsolation
        var composeText = ""
        var isLoading = false
        var isExecuting = false                    // Command in progress (Arch 1)
        var isPolling = false                      // Task polling active (Arch 2 & 3)
        @Presents var selectedTaskThread: TaskThreadFeature.State?
    }

    enum Action: Sendable {
        // Common
        case onAppear
        case messagesLoaded([HubChannelMessage])
        case compose(String)
        case send

        // Architecture 1: Command Dispatch
        case commandResult(String)
        case commandError(String)

        // Architecture 2: Flat Task Pipeline
        case taskCreated(MACTask)
        case progressUpdate(String)
        case taskCompleted(MACTask)
        case taskFailed(MACTask, String)

        // Architecture 3: Threaded Task Isolation
        case taskThreadsLoaded([TaskThread])
        case taskThreadCreated(TaskThread)
        case selectTaskThread(TaskThread)
        case taskThread(PresentationAction<TaskThreadFeature.Action>)
        case threadDecayTick  // 60-second lifecycle check

        // Realtime
        case newMessageReceived(HubChannelMessage)
    }
}

Reducer behavior per architecture:

swift
case .send:
    let text = state.composeText
    state.composeText = ""

    switch state.architectureType {
    case .commandDispatch:
        // Architecture 1: Parse command, execute directly, return result
        state.isExecuting = true
        return .run { send in
            let result = try await serverClient.executeCommand(channel.id, text)
            await send(.commandResult(result))
        }

    case .flatTaskPipeline:
        // Architecture 2: Create task, start polling, stream progress as flat messages
        return .run { send in
            let message = HubChannelMessage(content: text, senderType: .human, ...)
            try await serverClient.postChannelMessage(channel.id, message)
            let task = try await infraClient.createMACTask(text, channel.projectPath, ...)
            await send(.taskCreated(task))
            // Start polling loop
            for await update in serverClient.pollTaskProgress(task.id) {
                await send(.progressUpdate(update))
            }
        }

    case .threadedTaskIsolation:
        // Architecture 3: Create task, spawn thread, stream progress into thread
        return .run { send in
            let message = HubChannelMessage(content: text, senderType: .human, ...)
            try await serverClient.postChannelMessage(channel.id, message)
            let task = try await infraClient.createMACTask(text, channel.projectPath, ...)
            let thread = try await serverClient.createTaskThread(channel.id, task)
            await send(.taskThreadCreated(thread))
            // Polling happens inside TaskThreadFeature
        }
    }

TaskThreadFeature (Architecture 3 only)

swift
@Reducer
struct TaskThreadFeature {
    @ObservableState
    struct State: Equatable, Sendable {
        var taskThread: TaskThread
        var messages: [HubChannelMessage] = []
        var task: MACTask?
        var isPolling = false
    }

    enum Action: Sendable {
        case onAppear
        case messagesLoaded([HubChannelMessage])
        case startPolling
        case progressReceived(String)
        case taskCompleted(MACTask)
        case taskFailed(MACTask, String)
        case newMessageReceived(HubChannelMessage)
    }
}

ServerClient (New Dependency)

swift
struct ServerClient: Sendable {
    // Server & channel CRUD
    var fetchServers: @Sendable () async throws -> [HubServer]
    var fetchChannels: @Sendable (_ serverId: UUID) async throws -> [HubChannel]
    var fetchChannelMessages: @Sendable (_ channelId: UUID, _ limit: Int, _ before: Date?) async throws -> [HubChannelMessage]

    // Architecture 1: Command dispatch
    var executeCommand: @Sendable (_ channelId: UUID, _ command: String) async throws -> String

    // Architecture 2 & 3: Task pipeline
    var postChannelMessage: @Sendable (_ channelId: UUID, _ message: HubChannelMessage) async throws -> HubChannelMessage
    var pollTaskProgress: @Sendable (_ taskId: UUID) -> AsyncStream<String>

    // Architecture 3: Thread management
    var fetchTaskThreads: @Sendable (_ channelId: UUID) async throws -> [TaskThread]
    var createTaskThread: @Sendable (_ channelId: UUID, _ task: MACTask) async throws -> TaskThread
    var updateThreadStatus: @Sendable (_ threadId: UUID, _ status: TaskThreadStatus) async throws -> Void
    var fetchThreadMessages: @Sendable (_ threadId: UUID, _ limit: Int) async throws -> [HubChannelMessage]

    // Realtime
    var subscribeToChannelMessages: @Sendable (_ channelId: UUID) -> AsyncStream<HubChannelMessage>
    var subscribeToTaskThreadUpdates: @Sendable (_ channelId: UUID) -> AsyncStream<TaskThread>
}

Views

ServerListView

┌──────────────────────────────────┐
│  Servers                         │
├──────────────────────────────────┤
│  ┌────┐                         │
│  │ 🔧 │  Koji Pipeline          │
│  │    │  Command dispatch        │
│  │    │  3 channels              │
│  └────┘                         │
│  ┌────┐                         │
│  │ ☕ │  Buf Barista             │
│  │    │  Flat task pipeline      │
│  │    │  15 channels             │
│  └────┘                         │
│  ┌────┐                         │
│  │ ☁️ │  Cloud Hub               │
│  │    │  Threaded task isolation │
│  │    │  8 channels              │
│  └────┘                         │
└──────────────────────────────────┘

ServerDetailView (channel list with category groups)

┌──────────────────────────────────┐
│  ← Buf Barista                   │
│  Flat task pipeline              │
├──────────────────────────────────┤
│  HUB                             │
│    # bridge                      │
│    # quick                       │
│                                  │
│  COMP-CORE                       │
│    # cc-runtime                  │
│    # cc-semantic                 │
│    # cc-retrieval                │
│    # cc-motion                   │
│    # cc-agents                   │
│    # cc-media                    │
│                                  │
│  CREATIVE                        │
│    # workshop                    │
│    # research                    │
│    # garden                      │
└──────────────────────────────────┘

CommandChannelView (Architecture 1)

┌──────────────────────────────────┐
│  ← # leads                      │
│  Koji Pipeline · Command Dispatch│
├──────────────────────────────────┤
│                                  │
│  > !stats                        │
│  ┌─────────────────────────────┐ │
│  │ Pipeline: 23 active leads   │ │
│  │ Hot: 8 | Warm: 12 | Cold: 3│ │
│  │ Revenue MTD: $4,200         │ │
│  └─────────────────────────────┘ │
│                                  │
│  > !hot brooklyn                 │
│  ┌─────────────────────────────┐ │
│  │ 1. Bakeri (★4.8) - sample   │ │
│  │ 2. Laurel (★4.6) - outreach │ │
│  │ 3. ACRE (★4.5) - follow_up  │ │
│  └─────────────────────────────┘ │
│                                  │
├──────────────────────────────────┤
│  !_________________________  ⏎  │
└──────────────────────────────────┘

Note the `!` prefix in the compose field — visual hint that this is command mode.

FlatTaskChannelView (Architecture 2)

┌──────────────────────────────────┐
│  ← # cc-semantic                 │
│  Buf Barista · Flat Pipeline     │
├──────────────────────────────────┤
│                                  │
│  Mohamed                         │
│  Fix the graph kernel cache      │
│  invalidation bug                │
│                                  │
│  ⏳ Task a1b2 queued             │
│     Model: claude | Project:     │
│     cc-graph-kernel              │
│                                  │
│  📋 a1b2: Analyzing cache.rs... │
│  📋 a1b2: Found stale TTL logic │
│  📋 a1b2: Patching invalidation │
│                                  │
│  ✅ a1b2 complete [claude/mac1]  │
│  Fixed cache invalidation by     │
│  switching from fixed TTL to     │
│  LRU eviction with 512 entry... │
│                                  │
├──────────────────────────────────┤
│  ___________________________ ⏎  │
└──────────────────────────────────┘

Sequential messages in the channel. Progress updates inline. No threading.

ThreadedTaskChannelView (Architecture 3)

┌──────────────────────────────────┐
│  ← # dispatch                    │
│  Cloud Hub · Threaded Isolation  │
├──────────────────────────────────┤
│                                  │
│  Active Threads                  │
│  ┌─────────────────────────────┐ │
│  │ 🟢 a1b2 — Build REST API   │ │
│  │    3 messages · 2m ago      │ │
│  ├─────────────────────────────┤ │
│  │ 🟢 c3d4 — Fix auth bug     │ │
│  │    7 messages · 5m ago      │ │
│  ├─────────────────────────────┤ │
│  │ 🟡 e5f6 — Refactor DB      │ │
│  │    idle · 2h ago            │ │
│  └─────────────────────────────┘ │
│                                  │
│  Archived                        │
│  ┌─────────────────────────────┐ │
│  │ ⚫ g7h8 — Update configs   │ │
│  │    archived · yesterday     │ │
│  └─────────────────────────────┘ │
│                                  │
├──────────────────────────────────┤
│  ___________________________ ⏎  │
│  New message creates a thread    │
└──────────────────────────────────┘

Tapping a thread opens TaskThreadView with the isolated conversation.

TaskThreadView (Architecture 3 — inside a thread)

┌──────────────────────────────────┐
│  ← a1b2 — Build REST API   🟢  │
│  dispatch · cloud-hub            │
├──────────────────────────────────┤
│                                  │
│  Mohamed                         │
│  Build a REST API for the user   │
│  profile service                 │
│                                  │
│  ┌─────────────────────────────┐ │
│  │ 🔵 Task Queued              │ │
│  │ Model: claude               │ │
│  │ Device: — (pending)         │ │
│  └─────────────────────────────┘ │
│                                  │
│  📋 Creating route handlers...  │
│  📋 Adding validation middleware│
│                                  │
│  ┌─────────────────────────────┐ │
│  │ 🟢 Task Complete            │ │
│  │ Model: claude-sonnet-4-6    │ │
│  │ Device: mac1                │ │
│  │ Duration: 42s               │ │
│  └─────────────────────────────┘ │
│                                  │
│  Created 4 files:               │
│  - src/routes/profile.ts        │
│  - src/middleware/validate.ts    │
│  - src/models/user.ts           │
│  - tests/profile.test.ts        │
│                                  │
├──────────────────────────────────┤
│  ___________________________ ⏎  │
│  Reply continues in this thread  │
└──────────────────────────────────┘

---

Integration Points with Existing Features

What Does NOT Change

ComponentStatus
`ThreadListFeature`Untouched — conversations, feeds, alerts continue as-is
`ThreadDetailFeature`Untouched — thread detail view unchanged
`AgentChatFeature`Untouched — conversation streaming unchanged
`HubThread` modelUntouched — no new fields
`HubMessage` modelUntouched — no new fields
`hub_threads` tableUntouched — no schema changes
`hub_messages` tableUntouched — no schema changes
`DispatchFeature`Untouched — task creation via Dispatch tab is separate
`FeedAggregatorFeature`Untouched — feed aggregation is separate

What Connects

1. Task creation (Arch 2 & 3) reuses `infraClient.createMACTask()` — same task queue, same mesh executors
2. Model routing heuristic can be shared from `GatewayClient`'s `ModelHeuristic` logic
3. Realtime subscriptions use the same Supabase Realtime infrastructure (new channels for `hub_channel_messages` and `hub_task_threads`)
4. Embeds reuse the existing `EmbedData` struct from `HubModels.swift`

Where to Wire In

AppReducer.swift — add `serverList` to State and scope it:

swift
// In AppReducer.State:
var serverList = ServerListFeature.State()

// In AppReducer body:
Scope(state: \.serverList, action: \.serverList) {
    ServerListFeature()
}

ThreadListView.swift — add segmented control at the top:

swift
// At top of ThreadListView body:
Picker("View", selection: $viewMode) {
    Text("Conversations").tag(ViewMode.conversations)
    Text("Servers").tag(ViewMode.servers)
}
.pickerStyle(.segmented)

// Below picker:
switch viewMode {
case .conversations:
    // existing thread list
case .servers:
    ServerListView(store: store.scope(state: \.serverList, action: \.serverList))
}

Alternatively, if scoping through the parent is preferred, pass the server store from AppView into the threads tab.

---

Seed Data

On first launch (or via migration), create three default servers:

json
[
    {
        "name": "koji-pipeline",
        "display_name": "Koji Pipeline",
        "description": "Sales pipeline command center. Direct query access to leads, accounts, prospects, and market sweeps.",
        "icon": "chart.bar.xaxis",
        "architecture_type": "command_dispatch",
        "is_default": true,
        "channels": [
            { "name": "leads", "display_name": "#leads", "category_group": "Sales", "description": "Lead queries and enrichment status" },
            { "name": "accounts", "display_name": "#accounts", "category_group": "Sales", "description": "Active account lookups" },
            { "name": "sweeps", "display_name": "#sweeps", "category_group": "Ops", "description": "Market sweep commands and status" },
            { "name": "digest", "display_name": "#digest", "category_group": "Ops", "description": "Daily pipeline summaries" }
        ]
    },
    {
        "name": "buf-barista",
        "display_name": "Buf Barista",
        "description": "Development task pipeline with real-time progress streaming. Tasks execute on mesh devices and report back inline.",
        "icon": "cup.and.saucer.fill",
        "architecture_type": "flat_task_pipeline",
        "is_default": true,
        "channels": [
            { "name": "bridge", "display_name": "#bridge", "category_group": "Hub", "project_path": "Desktop/homelab", "model_preference": "any" },
            { "name": "quick", "display_name": "#quick", "category_group": "Hub", "project_path": "Desktop/homelab", "model_preference": "any" },
            { "name": "cc-runtime", "display_name": "#cc-runtime", "category_group": "Comp-Core", "project_path": "Desktop/Comp-Core/core/runtime", "model_preference": "claude" },
            { "name": "cc-semantic", "display_name": "#cc-semantic", "category_group": "Comp-Core", "project_path": "Desktop/Comp-Core/core/semantic", "model_preference": "claude" },
            { "name": "cc-retrieval", "display_name": "#cc-retrieval", "category_group": "Comp-Core", "project_path": "Desktop/Comp-Core/core/retrieval", "model_preference": "claude" },
            { "name": "cc-motion", "display_name": "#cc-motion", "category_group": "Comp-Core", "project_path": "Desktop/Comp-Core/core/motion", "model_preference": "claude" },
            { "name": "cc-agents", "display_name": "#cc-agents", "category_group": "Comp-Core", "project_path": "Desktop/Comp-Core/core/agents", "model_preference": "claude" },
            { "name": "cc-media", "display_name": "#cc-media", "category_group": "Comp-Core", "project_path": "Desktop/Comp-Core/core/audio-media", "model_preference": "claude" },
            { "name": "workshop", "display_name": "#workshop", "category_group": "Creative", "project_path": "Desktop/homelab", "model_preference": "any" },
            { "name": "research", "display_name": "#research", "category_group": "Creative", "project_path": "Desktop/homelab", "model_preference": "any" },
            { "name": "garden", "display_name": "#garden", "category_group": "Creative", "project_path": "Desktop/homelab", "model_preference": "any" }
        ]
    },
    {
        "name": "cloud-hub",
        "display_name": "Cloud Hub",
        "description": "Infrastructure operations with threaded task isolation. Each task gets its own conversation thread with lifecycle management.",
        "icon": "cloud.fill",
        "architecture_type": "threaded_task_isolation",
        "is_default": true,
        "channels": [
            { "name": "dispatch", "display_name": "#dispatch", "category_group": "Ops", "project_path": "Desktop/homelab", "model_preference": "claude" },
            { "name": "pulse-control", "display_name": "#pulse-control", "category_group": "Ops", "project_path": "Desktop/homelab", "model_preference": "claude" },
            { "name": "infrastructure", "display_name": "#infrastructure", "category_group": "Ops", "project_path": "Desktop/homelab", "model_preference": "claude" },
            { "name": "morning-brief", "display_name": "#morning-brief", "category_group": "Feeds", "is_read_only": true },
            { "name": "heartbeat", "display_name": "#heartbeat", "category_group": "Feeds", "is_read_only": true },
            { "name": "memory-log", "display_name": "#memory-log", "category_group": "Feeds", "is_read_only": true }
        ]
    }
]

---

Thread Decay Implementation (Architecture 3)

The decay loop runs as a background task in `ChannelFeature` when `architectureType == .threadedTaskIsolation`:

swift
// In ChannelFeature reducer, on .onAppear for Architecture 3:
case .onAppear where state.architectureType == .threadedTaskIsolation:
    return .merge(
        loadChannelMessages(),
        loadTaskThreads(),
        startDecayLoop()  // Fires .threadDecayTick every 60 seconds
    )

case .threadDecayTick:
    let now = Date()
    for thread in state.taskThreads where thread.status != .archived {
        let idle = now.timeIntervalSince(thread.lastActivityAt ?? thread.createdAt)
        switch thread.status {
        case .active where idle > 7200:   // 2 hours
            // Transition to .idle, post warning message
        case .idle where idle > 3600:      // 1 more hour
            // Transition to .archived, post summary
        default:
            break
        }
    }

---

Command Registry (Architecture 1)

For the Koji command dispatch pattern, commands are registered as a fixed map:

swift
struct CommandRegistry {
    static let commands: [String: CommandDefinition] = [
        "stats":         CommandDefinition(name: "stats", description: "Pipeline summary", usage: "!stats"),
        "hot":           CommandDefinition(name: "hot", description: "Hot-tier prospects", usage: "!hot [market]"),
        "warm":          CommandDefinition(name: "warm", description: "Warm-tier prospects", usage: "!warm [market]"),
        "sweep":         CommandDefinition(name: "sweep", description: "Launch market sweep", usage: "!sweep <city>"),
        "sweep-status":  CommandDefinition(name: "sweep-status", description: "Active sweep status", usage: "!sweep-status"),
        "lead":          CommandDefinition(name: "lead", description: "Prospect detail", usage: "!lead <id>"),
        "export":        CommandDefinition(name: "export", description: "CSV export", usage: "!export [market]"),
        "send-samples":  CommandDefinition(name: "send-samples", description: "Top prospects for sampling", usage: "!send-samples <n>"),
        "followup":      CommandDefinition(name: "followup", description: "Trigger follow-ups", usage: "!followup"),
        "digest":        CommandDefinition(name: "digest", description: "Daily summary", usage: "!digest"),
    ]
}

The `serverClient.executeCommand()` implementation routes through the Koji Supabase Edge Function (existing `koji-discord-bot`), adapting HTTP calls for the mobile client.

---

Files to Create

FilePurpose
`Models/ServerModels.swift``HubServer`, `HubChannel`, `TaskThread`, `ServerArchitecture`, `ModelPreference`, `TaskThreadStatus`, `CommandDefinition`
`Services/ServerClient.swift``ServerClient` dependency with Supabase live implementation
`Features/Servers/ServerListFeature.swift`TCA reducer for server list
`Features/Servers/ServerListView.swift`Server list UI
`Features/Servers/ServerDetailFeature.swift`TCA reducer for channel list within a server
`Features/Servers/ServerDetailView.swift`Channel list UI with category groups
`Features/Servers/Channels/ChannelFeature.swift`Polymorphic TCA reducer (adapts to architecture type)
`Features/Servers/Channels/CommandChannelView.swift`Architecture 1 UI
`Features/Servers/Channels/FlatTaskChannelView.swift`Architecture 2 UI
`Features/Servers/Channels/ThreadedTaskChannelView.swift`Architecture 3 UI
`Features/Servers/Channels/TaskThreadFeature.swift`TCA reducer for individual task threads
`Features/Servers/Channels/TaskThreadView.swift`Task thread conversation UI

Files to Modify

FileChange
`App/AppReducer.swift`Add `serverList` state, scope reducer
`Views/MainTabView.swift` or `Features/ThreadList/ThreadListView.swift`Add segmented control for Conversations/Servers
`project.yml`Add new source files to target

---

Verification

1. Schema: Run the SQL migration. Verify tables created with `\dt hub_*` in psql.
2. Seed data: Insert three default servers. Verify with `SELECT * FROM hub_servers`.
3. Server list: Launch app → Threads tab → tap "Servers" segment → see three servers.
4. Architecture 1: Tap Koji Pipeline → #leads → type `!stats` → verify instant result.
5. Architecture 2: Tap Buf Barista → #cc-semantic → type a task → verify task queued in `mac_tasks`, progress streams as flat messages.
6. Architecture 3: Tap Cloud Hub → #dispatch → type a task → verify thread created in `hub_task_threads`, progress streams into thread, thread shows in channel's thread list.
7. Decay: Wait 2+ hours (or mock time) → verify thread transitions to idle/archived.
8. Isolation: Verify no changes to existing Conversations segment — threads, messages, agent chat all work as before.

Promotion Decision

Promote into a technical note or architecture paper with implementation anchors.

Source Anchor

OpenClawHub/SERVER-ARCHITECTURE-DESIGN.md

Detected Structure

Method · Evaluation · References · Code Anchors · Architecture