Architecture

MultiTerminal is a WinForms desktop application (C#/.NET) with an integrated REST API, MCP server, and WebView2-based UI panels. This page describes the system layers, data flow, database schema, and key patterns.

System Overview

The system is organized into five distinct layers, with the MessageBroker serving as the central hub connecting everything together.

UI Host MainForm.cs · ~5.2K LOC

Hosts the VS-style docking framework, owns the toolbar and terminal lifecycle, and wires every panel to the MessageBroker through C# events. Renders 11 WebView2 panels:

TasksPanelKanban board — create, claim and drag tasks across To Do / In Progress / Done; edit the plan and checklist.
ChatPanelInter-terminal messaging UI — point-to-point and broadcast, with persistent history.
ActivityPanelLive activity feed of tool use, builds, and task changes across all terminals.
ProfilePanelTeam-member profiles — avatar, role, skills, and online/availability state.
InboxPanelNotification center for checklist transitions, help requests, and alerts (unread badge).
ProjectPanelBrowse and edit registered projects: agents, MCP servers, named paths, prompts.
LauncherPanelLaunch app/agent processes and companion tools.
OfficePanelAnimated “office” visualization of spawned agents’ presence and activity.
AgentPanelRead-only live transcript stream of a spawned team agent.
DebugPanelInternal debug log (pause / resume / clear) for troubleshooting.
FilePreviewPanelIn-app preview of files — HTML, Markdown, images.
Also in this layer: Terminal/ (ConPTY terminals rendered in WebView2), Docking/ (GridLayoutManager grid presets + layout persistence), and Dialogs/ (11 modal windows — Settings, Project, History, Owner Profile, …).
C# events ↓
REST API MultiTerminalRestServer.cs · port 5050

A loopback HTTP API on localhost:5050. Both the UI and the MCP server call it; every controller delegates to the MessageBroker. ~25 controllers — the main ones:

TasksControllerTasks, checklists, inbox, and attachments — the largest controller.
MessagingControllerSend/broadcast messages, terminal registration, and channel-port routing.
SpawnControllerSpawns Claude Code terminals and team agents.
OfficeControllerSpawned-agent office and helper coordination.
KnowledgeControllerInstitutional knowledge entries + full-text search.
SessionLineageControllerSession history, lineage chains, and the start-of-session recap.
ProjectContextControllerOne-call project context (agents, MCP servers, paths, prompts, skills).
TeamControllerTeam roster and member profiles.
TaskReportsControllerPersisted pipeline / review-agent reports and verdicts.
NotificationsControllerRuntime notifications from hooks (push to phone).
BrowserTabsControllerHUD browser-tab pooling that agents drive via MCP.
TerminalStreamControllerWebSocket streaming of terminal output.
OwnerProfileControllerGit identity and GitHub config. Metadata only — reports whether a token is stored, never its value (ea7d9cf9).
RipgrepControllerFast regex code search (bundled rg.exe).
Loopback-only. Each MCP tool call becomes exactly one HTTP request to a controller here — the API is the single seam between the agents and the app. Other controllers: Tools, AgentPanels, AgentStats, Companion, Gateway, XamlPreview, CodeGraph, Settings.
method calls ↓
MessageBroker MessageBroker.cs · ~5.5K LOC

The central hub. Routes messages, caches tasks/terminals/profiles in ConcurrentDictionary stores, delivers webhooks, and fires ~19 events to the UI panels — everything flows through here. It owns these services:

ActivityServiceRecords workflow events to the activity feed.
PoolCoordinatorShared pool memory and cross-agent learnings.
ComplexityDetectorScores task complexity (SMALL / MEDIUM / LARGE) to scale workflow ceremony.
SessionDiscoveryResolves Claude Code session IDs for resume.
StaleTaskServiceFlags paused tasks at 7 and 14 days.
SpawnServiceOrchestrates agent spawning and registration.
SummaryServiceAuto-summarizes task progress on status transitions.
HttpWebhookServiceAt-least-once webhook / message delivery with retries.
SQLite calls ↓
Persistence SQLite

All durable state lives in SQLite — no external database server. Access is wrapped by per-domain data classes:

TaskDatabase.csCRUD for 21+ tables — tasks, checklists, reports, profiles, activity, attachments. (~4.6K LOC)
ProjectDatabase.csProjects plus 6 association tables: agents, MCP servers, specialists, paths, prompts, skills.
KnowledgeDatabaseKnowledge entries with FTS5 search and attention-decay ranking.
SessionLineageServiceImports JSONL transcripts; lineage chains and session search.
MessageQueueDatabaseReliable message-delivery queue with retry and de-duplication.
multiterminal.db holds the bulk — tasks, sessions, knowledge, projects, and the code graph. messages.db is a separate store so at-least-once message delivery survives restarts independently. Both live under %APPDATA%\multiterminal.
stdio (JSON-RPC) ↓
MCP Server Node.js · ~90 tools

A stateless bridge that exposes ~90 tools to Claude Code agents over MCP. It holds no state of its own — each tool wraps a single HTTP request to the REST API above. Tools fall into groups:

Task toolscreate / claim / update tasks, checklists, plans, continuation notes.
Messaging toolssend / broadcast, inbox, and channel reply / send.
Knowledge & sessionadd / query knowledge, search session history and memory.
Code graph toolsindex, search symbols, callers / callees, impact analysis.
Project & teamprojects, roster, profiles, spawn agents.
Located at %APPDATA%\multiterminal\mcp\index.js. See the MCP Tools reference for the full list.

Critical Files

These files contain the majority of the system's logic. Read them first when onboarding.

FileLOCRole
MCPServer/Services/MessageBroker.cs ~5,512 Central hub. Routes all messages, caches tasks/terminals/profiles in ConcurrentDictionaries, delivers webhooks, fires 19 events. Everything flows through here.
Services/TaskDatabase.cs ~4,621 Persistence. SQLite CRUD for 21+ tables: tasks, sessions, knowledge, reports, profiles, activity, attachments, and more.
MainForm.cs ~5,162 UI host. Creates/docks panels, wires events between panels and MessageBroker, manages terminal lifecycle.
MCPServer/Models/KanbanTask.cs ~500 Core model. All task properties: status, assignee, checklists, plan, helpers, stale tracking, continuation notes, plus all result types.
Services/ProjectDatabase.cs ~1,100 Project persistence. SQLite CRUD for projects and all 6 association tables (agents, MCP servers, specialists, paths, prompts, skills).
API/Controllers/TasksController.cs ~505 Tasks REST API. All task, checklist, inbox, and attachment endpoints. Largest controller.

Data Flow

Here is how a typical operation (e.g., creating a task) flows through the system.

Agent Creates a Task

1. Claude Code Agent
Calls create_task(title="Fix bug", ...) via MCP tool
2. MCP Server (Node.js)
Translates to POST /api/tasks with JSON body
3. TasksController
Validates request, calls _broker.CreateTask(...)
4. MessageBroker
Creates KanbanTask object, adds to cache, calls _taskDb.SaveTask(...), fires TasksUpdated event
5a. TaskDatabase
Persists to SQLite tasks table
5b. MainForm (event handler)
Receives TasksUpdated event, refreshes TasksPanel UI
5c. ActivityService
Records activity event to feed

Checklist Item Transition

1. Agent calls update_task_checklist
taskId, itemIndex=0, newStatus="testing", notes="Done implementing"
2. MessageBroker.TransitionChecklistItem()
Validates state machine: coding → testing allowed. Updates item status, appends notes, increments cycle count if cycling.
3a. TaskDatabase
Saves updated checklist_json
3b. Inbox Notification
Creates ready_for_testing inbox message for PM
3c. Escalation Check
If cycleCount >= 3, creates escalation inbox message

Host-Controlled Memory Architecture

MultiTerminal inverts the standard Claude Code context model. Instead of agents reading static files (CLAUDE.md, memory.md) and deciding what to remember, the host controls context injection through three mechanisms:

  • Session continuity — hooks track session→agent mappings, auto-sync JSONL transcripts, and inject the agent's own last-session recap at startup
  • Knowledge injection — hooks query SQLite at session start, rank entries by attention decay, and inject the most relevant knowledge before the agent sees any prompt
  • Subprocess isolation — spawned agents receive a per-agent system prompt file and scoped settings, bypassing global CLAUDE.md and user-level hooks entirely

The following sections detail each mechanism.

Session Sync Pipeline (End-to-End)

Every Claude Code session is automatically tracked and imported into the session database, preserving which agent ran it and providing session continuity across restarts.

Phase 1: Session Start (Hook)

1. Claude Code starts a session
Creates JSONL file: ~/.claude/projects/{folder}/{session-id}.jsonl
2. session-status-hook.js (SessionStart)
Reads MULTITERMINAL_NAME env var + hookData.session_id. Writes (session_id, agent_name, is_active=1) to session_agent_map table.
3. Profile marked online
Same hook upserts team_member_profiles with is_online=1.

Phase 2: Session End (Hook)

1. Claude Code session ends
JSONL file is complete. session-status-hook.js fires with SessionEnd.
2. session-status-hook.js (SessionEnd)
Updates session_agent_map: sets is_active=0, writes ended_at timestamp.
3. Profile marked offline
Calls POST /api/messaging/disconnect (or direct DB fallback).

Phase 3: Auto-Sync on Startup

1. MultiTerminal launches
MainForm.InitializeMcpServerAndChatPanel() fires background Task.Run.
2. Iterate registered projects
Reads all projects from ProjectDatabase. For each, resolves Claude project folder path.
3. SessionLineageService.SyncNewSessions()
Scans *.jsonl files. Skips already-imported sessions (GetImportedSessionIds). Skips active sessions (GetActiveSessionIds from session_agent_map where is_active=1).
4. Resolve agent name
For each new session, looks up session_agent_map for the real agent name (e.g. "Alice"). Falls back to "Unknown" only if no mapping exists.
5. Import to session_lineage + session_messages
Parses JSONL, extracts user/assistant messages, persists with correct agent name.

Phase 4: Session Recap at Terminal Start

1. session-status-hook.js (SessionStart)
Calls GET /api/session-lineage/latest?projectPath=...&agentName={terminalName}
2. SessionLineageController
Passes agentName filter to SessionLineageService.GetMostRecentSessionForProject()
3. Returns this agent's last session
SQL filters by agent_name = @agentName. Returns cached summary or recent messages for lazy generation.
4. Agent sees its own recap
Hook injects session summary into startup context. Agent can continue where it left off.

Key Files

FileRole
.claude/hooks/session-status-hook.jsWrites session→agent mapping on start/end, injects recap + knowledge
Services/SessionLineageService.csSync logic, JSONL parsing, queries
Services/SessionSyncService.csPath conversion, JSONL message parsing
Services/TaskDatabase.csAll session tables + CRUD + FTS5
Services/KnowledgeDatabase.csKnowledge CRUD + attention decay (BumpReference)
API/Controllers/SessionLineageController.csREST endpoints for session lineage
MainForm.cs (startup block)Triggers auto-sync on app launch

Host-Controlled Knowledge Injection

At every session start, the session-status-hook.js injects relevant knowledge entries into the agent's context. The host — not the agent — decides what gets injected and in what order.

1. session-status-hook.js (SessionStart)
Opens SQLite directly, queries knowledge_entries with decay ranking:
score = (reference_count + 1) / (days_since_last_referenced + 1)
2. Tiered injection
Top 10 by score → full inject (title + 200-char content). Next 5 → title-only. Rest skipped.
3. Bump references
All injected entries get reference_count += 1 and last_referenced = now, reinforcing their ranking for next session.
4. Graceful fallback
If decay columns don't exist yet (pre-migration), falls back to simple ORDER BY updated_at DESC.

Subprocess Isolation

Spawned team agents receive controlled context to prevent global CLAUDE.md leakage and user-level hook interference.

1. TerminalSpawner.SpawnTerminal()
Calls GenerateAgentSystemPrompt(agentName, agentType) to create a per-agent prompt file.
2. Prompt file written
%APPDATA%/multiterminal/agent-{name}-prompt.md containing: agent identity, rules from multiterminal-rules.md, and agent constraints (focus on task, no global settings changes).
3. Claude launched with isolation flags
--system-prompt-file {prompt.md} — overrides global CLAUDE.md
--setting-sources project --setting-sources local — skips user-level settings and hooks
--channels server:multiterminal-channel — MCP messaging
Isolation Key Files
FileRole
Services/TerminalSpawner.csGenerates prompt file, passes isolation flags to Claude CLI
multiterminal-rules.mdShared rules included in agent prompts

Database Schema

All data is stored under your per-user data folder, %APPDATA%\multiterminal (typically C:\Users\<you>\AppData\Roaming\multiterminal). The primary database is multiterminal.db, which holds most tables.

The %APPDATA%\multiterminal Data Folder

Everything MultiTerminal persists for the current user lives here — the databases, the configuration files, the bundled MCP server, and runtime logs. Nothing is written under the install directory, so the app can run from a read-only location and a single folder holds all your state.

Databases

ItemPurpose
multiterminal.dbPrimary store — tasks & checklists, sessions & lineage, knowledge, projects, code graph, profiles, and activity. Runs in SQLite WAL mode, so you'll also see transient multiterminal.db-wal and -shm sidecar files.
messages.dbReliable inter-terminal message-delivery queue (retry + de-duplication), kept separate so delivery survives restarts independently. (Also has -wal/-shm sidecars.)

Configuration & state files

ItemPurpose
.mcp.jsonRegisters the two stdio MCP servers (multiterminal + mcp-gateway). Claude Code is pointed at it with --mcp-config. Generated by the installer.
settings.txtUser/app settings (key=value). Per-install Multi-Connect and Presence overrides are written here and win over appsettings.json.
layout.xmlSaved docking layout — panel positions, sizes, and visibility (restored on next launch). .bak is the previous layout.
companion-processes.jsonCompanion processes MultiTerminal auto-launches on startup (e.g. the phone gateway).
push-config.jsonWeb-Push VAPID identity + your phones' push subscriptions (Multi-Connect notifications).
projects.jsonJSON project registry kept for portability (the SQLite ProjectDatabase is the primary source).
prompts.jsonSaved reusable prompts.
subagent-map.jsonMaps spawned subagents back to the agent that spawned them.
oracle-system-prompt.mdSystem prompt used by the Oracle helper.

Subfolders

ItemPurpose
mcp\The bundled Node.js MCP server (index.js + node_modules) — the ~90-tool surface agents call.
gateway\The MCP Gateway (McpGateway.exe) data — its backend-server registry and profiles (stored in the gateway's own SQLite DB, not in .mcp.json).
inbox\File-based inbox (<name>.json) — the legacy [cm] message fallback. Channels is the primary path now.
attachments\Task image attachments.
logs\Runtime and diagnostic logs (additional *.log files such as startup-error.log and hook-debug.log may also sit at the folder root).
.claude\Claude Code support files MultiTerminal generates (e.g. per-agent system-prompt files for spawned agents).
codex\Data for the optional Codex agent integration.

You may also see legacy/backup files here from older versions (e.g. sessions.db.old, tasks.db) — these are no longer used. To back up your data, copy this folder (at minimum multiterminal.db and messages.db) while MultiTerminal is closed; see Troubleshooting.

multiterminal.db - Core Tables

tasks

Primary kanban task storage.

ColumnTypeDescription
idTEXT PK8-char hex GUID
titleTEXT NOT NULLTask title
descriptionTEXTTask description
statusTEXT NOT NULLtodo, in_progress, done, suggestion
assigneeTEXTClaimed agent name
created_byTEXTCreator name
created_atDATETIMECreation timestamp
updated_atDATETIMELast update timestamp
priorityTEXTlow, normal, high
sub_statusTEXTactive, paused (for in_progress tasks)
paused_atDATETIMEWhen task was paused
checklist_jsonTEXTJSON array of checklist items
planTEXTMarkdown implementation plan
implementation_summaryTEXTWhat was built (markdown)
test_resultsTEXTTest outcomes (markdown)
continuation_notesTEXTSession handoff context
auto_statusINTEGERAuto-derive status from checklist
project_idTEXTFK to projects
flagged_stale_atDATETIMEWhen flagged as stale
stale_levelINTEGER0=fresh, 1=7day, 2=14day
stale_responseTEXTUser response to stale notification

task_helpers

Helper assignments for collaborative tasks.

ColumnTypeDescription
idTEXT PKHelper record ID
task_idTEXT FKReferences tasks.id
helper_nameTEXTHelper agent name
added_byTEXTWho added the helper
added_atDATETIMEWhen added

terminal_activity

Current state of each terminal.

ColumnTypeDescription
terminalTEXT PKTerminal name
statusTEXTidle, working, blocked
activityTEXTCurrent activity description
blocked_byTEXTWhat is blocking (if any)
task_idTEXTActive task ID
plan_idTEXTActive plan ID

activity_feed

High-level workflow events for the manager dashboard.

ColumnTypeDescription
idINTEGER PKAuto-increment
timestampTEXTEvent timestamp
activity_typeTEXTEvent type
actorTEXTWho triggered it
summaryTEXTHuman-readable summary
severityTEXTinfo, warning, error
details_jsonTEXTJSON event details

task_summaries

Progress snapshots for tracking work history and handoffs.

ColumnTypeDescription
idINTEGER PKAuto-increment
task_idTEXT FKReferences tasks.id
summary_atDATETIMEWhen summarized
triggered_byTEXTWhat triggered the summary
previous_statusTEXTStatus before transition
new_statusTEXTStatus after transition
work_completedTEXTWhat was done
next_stepsTEXTWhat's next
blockersTEXTCurrent blockers
authorTEXTWho wrote it

team_member_profiles

Rich identity information for team agents.

ColumnTypeDescription
idTEXT PKProfile ID
display_nameTEXTDisplay name
avatar_urlTEXTAvatar image URL
roleTEXTAgent role
bioTEXTAgent bio/description
skills_jsonTEXTJSON array of skills
interests_jsonTEXTJSON array of interests

user_inbox

Inbox notifications for task events.

ColumnTypeDescription
idTEXT PKMessage ID
user_idTEXTRecipient user
task_idTEXT FKRelated task
task_titleTEXTTask title snapshot
checklist_item_indexINTEGERRelated checklist item
checklist_item_nameTEXTItem name snapshot
message_typeTEXTready_for_testing, escalation, task_complete, helper_request
summaryTEXTHuman-readable summary
created_byTEXTWho triggered it
read_atDATETIMEWhen read (null if unread)
reply_textTEXTReply content
replied_atDATETIMEWhen replied

task_attachments

Image attachments stored as binary blobs.

ColumnTypeDescription
idTEXT PKAttachment ID
task_idTEXT FKReferences tasks.id
checklist_item_indexINTEGERAssociated checklist item
file_nameTEXTOriginal filename
mime_typeTEXTMIME type (image/png, etc.)
dataBLOBRaw binary image data
added_byTEXTWho added it

complexity_decisions

Learnable heuristic for task complexity analysis.

ColumnTypeDescription
idINTEGER PKAuto-increment
task_idTEXT FKReferences tasks.id
scoreINTEGERComplexity score (0-100)
signals_jsonTEXTDetected complexity signals
suggested_planINTEGERWhether a plan was suggested
user_acceptedINTEGERUser's decision (for learning)

task_relationships

Blocking and dependency relationships between tasks.

ColumnTypeDescription
idINTEGER PKAuto-increment
source_task_idTEXT FKSource task
target_task_idTEXT FKTarget task
typeTEXTblocks, depends_on, related_to
created_byTEXTWho created the relationship
created_atDATETIMECreation timestamp

task_file_links

Files linked to tasks for code review and context.

ColumnTypeDescription
idINTEGER PKAuto-increment
task_idTEXT FKReferences tasks.id
file_pathTEXTAbsolute file path
descriptionTEXTWhy this file is relevant
line_startINTEGERStart line number (optional)
line_endINTEGEREnd line number (optional)
added_byTEXTWho linked it
added_atDATETIMEWhen linked

task_reports

Persisted agent reports (HTML/markdown) linked to tasks.

ColumnTypeDescription
idTEXT PKReport ID
task_idTEXT FKReferences tasks.id
invocation_idTEXTLinks to agent_invocations
agent_nameTEXTAgent that generated the report
report_typeTEXThtml or markdown
report_contentTEXTFull report content
verdictTEXTPASS, FAIL, PASS WITH NOTES
scoreINTEGERNumeric score 0-100
created_atDATETIMECreation timestamp
created_byTEXTWho saved the report

agent_invocations

Tracks specialist agent invocations with performance metrics.

ColumnTypeDescription
idTEXT PKInvocation ID
agent_nameTEXTAgent name (verifier, code-reviewer, etc.)
task_idTEXT FKRelated task
invoked_byTEXTWho triggered the invocation
model_usedTEXTClaude model used
verdictTEXTResult verdict
scoreINTEGERNumeric score
findings_countINTEGERNumber of findings
duration_msINTEGERExecution time in ms
invoked_atDATETIMEWhen invoked
completed_atDATETIMEWhen completed
report_summaryTEXTBrief summary of findings

notification_events

Runtime notifications from Claude Code hooks — forwarded to the in-process gateway and pushed to your phone via Web Push (Multi-Connect).

ColumnTypeDescription
idTEXT PKNotification ID
notification_typeTEXTType of notification
titleTEXTNotification title
messageTEXTNotification message
session_idTEXTClaude Code session
agent_nameTEXTAgent that triggered it
cwdTEXTWorking directory
read_atDATETIMEWhen read (null if unread)
created_atDATETIMECreation timestamp

owner_profile

Owner identity: git user.name, email, GitHub username, and encrypted token.

ColumnTypeDescription
idINTEGER PKSingleton (always 1)
full_nameTEXTGit user.name
emailTEXTGit user.email
github_usernameTEXTGitHub username
github_token_encryptedTEXTEncrypted GitHub PAT
created_atDATETIMEWhen created
updated_atDATETIMELast updated

chat_messages

Persistent inter-terminal chat messages (survives restarts).

ColumnTypeDescription
idINTEGER PKAuto-increment
from_nameTEXTSender name
to_nameTEXTRecipient name (null for broadcast)
messageTEXTMessage content
timestampDATETIMEWhen sent

multiterminal.db - Session Lineage Tables

session_lineage

Tracks parent/child relationships between Claude Code sessions.

ColumnTypeDescription
idINTEGER PKAuto-increment
session_idTEXT UNIQUESession identifier
parent_session_idTEXTParent for lineage chaining
task_idTEXT FKLinked kanban task
agent_nameTEXTAgent who ran the session
session_typeTEXTcoding, review, testing, terminal
summaryTEXTGenerated session summary
session_file_pathTEXTPath to JSONL transcript
started_atTEXTSession start time
ended_atTEXTSession end time

session_messages

Individual messages extracted from session JSONL files.

ColumnTypeDescription
idINTEGER PKAuto-increment
session_idTEXT FKReferences session_lineage.session_id
task_idTEXTLinked task (denormalized)
agent_nameTEXTAgent name (denormalized)
message_indexINTEGERPosition in session
roleTEXTuser or assistant
contentTEXTMessage content
tool_nameTEXTTool used (if any)
timestampTEXTMessage timestamp

session_messages_fts

FTS5 virtual table for full-text search across session messages.

Columns indexed: content, role, agent_name, tool_name. Content sourced from session_messages.

session_agent_map

Maps session IDs to agent names. Written by session-status-hook.js on SessionStart/SessionEnd. Used during auto-sync to resolve agent names and skip active sessions.

ColumnTypeDescription
session_idTEXT PKClaude Code session GUID
agent_nameTEXTTerminal agent name (e.g. "Alice")
is_activeINTEGER1 = session in progress, 0 = ended
started_atTEXTWhen the session started
ended_atTEXTWhen the session ended (null if active)

multiterminal.db - Knowledge Tables

knowledge_entries

Institutional memory: decisions, patterns, gotchas, anti-patterns.

ColumnTypeDescription
idINTEGER PKAuto-increment
project_idTEXTProject scope (null = global)
categoryTEXTdecision, pattern, gotcha, anti_pattern, debug_insight, preference
titleTEXTShort summary title
contentTEXTFull knowledge content
source_typeTEXTmanual, session, debug, review
source_idTEXTReference ID (session, task)
source_agentTEXTAgent who contributed
tagsTEXTComma-separated tags
confidenceTEXTconfirmed, likely, uncertain
superseded_byINTEGERID of replacement entry
last_referencedTEXTISO timestamp of last access (search or injection). Used by attention decay ranking.
reference_countINTEGERTotal access count. Bumped on every search hit and session injection.

knowledge_entries_fts

FTS5 virtual table for full-text search across knowledge entries.

Columns indexed: title, content, tags. Content sourced from knowledge_entries.

code_digests

Per-file summaries for fast agent orientation.

ColumnTypeDescription
idINTEGER PKAuto-increment
project_idTEXTProject scope
file_pathTEXTAbsolute path to source file
file_hashTEXTSHA256 for staleness detection
purposeTEXTOne-sentence file description
key_classesTEXTJSON array of class names
key_methodsTEXTJSON array of method names
patternsTEXTNotable patterns
gotchasTEXTPitfalls and gotchas
dependenciesTEXTJSON array of dependencies
line_countINTEGERFile line count
digest_modelTEXTModel used (default: haiku)

multiterminal.db - Project Tables (ProjectDatabase.cs)

projects (extended)

Project registry with full metadata. Enhanced version with additional columns beyond the core record.

ColumnTypeDescription
idTEXT PKProject GUID
nameTEXTProject name
descriptionTEXTProject description
pathTEXTSource path
source_pathTEXTSource code location
deploy_pathTEXTDeploy output location
build_output_pathTEXTBuild output directory
build_commandTEXTBuild command
deploy_commandTEXTDeploy command
launch_commandTEXTLaunch command
project_typeTEXTProject archetype
current_versionTEXTCurrent version string
is_pinnedINTEGERPinned to dashboard
iconTEXTIcon identifier
icon_colorTEXTIcon color
team_leadTEXTTeam lead name
git_repo_urlTEXTGit repository URL
git_default_branchTEXTDefault git branch
git_auto_commitINTEGERAuto-commit enabled

project_agents

Agents assigned to a project.

ColumnTypeDescription
idINTEGER PKAuto-increment
project_idTEXT FKReferences projects.id
agent_nameTEXTAgent name
roleTEXTAgent role
preferred_modelTEXTopus, sonnet, haiku

project_mcp_servers

MCP servers configured for a project.

ColumnTypeDescription
idINTEGER PKAuto-increment
project_idTEXT FKReferences projects.id
server_nameTEXTServer name
is_enabledINTEGEREnabled flag

project_specialist_agents

Specialist agents (devils-advocate, verifier, etc.) for a project.

ColumnTypeDescription
idINTEGER PKAuto-increment
project_idTEXT FKReferences projects.id
agent_typeTEXTdevils-advocate, verifier, etc.
is_enabledINTEGEREnabled flag
custom_promptTEXTOverride prompt

project_paths

Named filesystem paths for a project.

ColumnTypeDescription
idINTEGER PKAuto-increment
project_idTEXT FKReferences projects.id
path_typeTEXTsource, deploy, build_output, docs
path_valueTEXTFilesystem path
descriptionTEXTPath description

project_prompts

Stored prompts and instructions for a project.

ColumnTypeDescription
idINTEGER PKAuto-increment
project_idTEXT FKReferences projects.id
prompt_typeTEXTsystem, user, context, workflow
prompt_textTEXTPrompt content
display_orderINTEGERSort order

project_skills

Skills enabled for a project.

ColumnTypeDescription
idINTEGER PKAuto-increment
project_idTEXT FKReferences projects.id
skill_nameTEXTSkill name
is_enabledINTEGEREnabled flag

mcp_registry

Three-tier MCP server registry (multiterminal, global, optional).

ColumnTypeDescription
server_nameTEXT PKMCP server name
tierTEXTmultiterminal, global, optional
commandTEXTServer command
args_jsonTEXTJSON array of arguments
env_jsonTEXTJSON object of env vars
is_enabledINTEGEREnabled by default

MessageBroker Events

The MessageBroker fires C# events that MainForm subscribes to for updating the UI. All events are thread-safe and marshaled to the UI thread.

EventPayloadWhen Fired
MessageSentMessageInter-terminal message delivered
TerminalRegisteredTerminalInfoNew terminal registers
TerminalDisconnectedTerminalInfoTerminal disconnects
TasksUpdatedList<KanbanTask>Any task created, updated, or deleted
TaskClaimedTaskClaimedEventArgsTask assigned to an agent
ActivityRecordedActivityEventActivity feed event recorded
PlanUpdatedPlanUpdateEventArgsTask plan created or modified
ProjectsUpdatedList<Project>Project list changed
ProfilesUpdatedList<TeamMemberProfile>Team profiles changed
HelperSessionUpdatedHelperSessionHelper session state changed
HelperMessageLoggedHelperMessageHelper message logged
InboxUpdatedInboxUpdatedEventArgsInbox message created or read
OfficeAgentSpawnedOfficeAgentInfoAgent walks into office panel
OfficeAgentDepartedOfficeAgentInfoAgent leaves office panel
AgentPanelCloseRequestedstring (transcript path)Subagent finished, close panel
ReportSavedReportSavedEventArgsAgent pipeline report saved for a task
NotificationReceivedNotificationEventArgsPush notification received from hooks
BrowserTabRequestedBrowserTabEventArgsAgent requested a browser tab in HUD
SessionLineageUpdatedstring (task ID)Session imported or synced

Key Patterns

Adding a UI Panel

  1. Create {Name}Panel/{Name}PanelDocument.cs inheriting DockContent (set DockAreas, HideOnClose=true)
  2. Create inner control with WebView2 or custom renderer
  3. Add Initialize(MessageBroker broker) and ApplyTheme(bool isDark) methods
  4. In MainForm: instantiate, call Initialize(), wire events, add toolbar toggle button
  5. Follow existing panels (TasksPanel, ActivityPanel) as templates

Adding a Backend Feature

  1. Add model to MCPServer/Models/
  2. Add persistence to TaskDatabase.cs (table + CRUD methods + migration)
  3. Add routing to MessageBroker.cs (methods + events)
  4. Add MCP tool to MCPServer/Tools/ (or index.js) if agents need access
  5. Add REST endpoint to API/Controllers/ if HTTP access needed

Adding an MCP Tool

  1. Add tool definition to the tools array in %APPDATA%\multiterminal\mcp\index.js
  2. Add handler in the CallToolRequestSchema switch block in the same file
  3. Tool handler calls the REST API which delegates to MessageBroker which delegates to TaskDatabase
  4. Return formatted text result for the agent

Adding a REST Endpoint

  1. Add method to the appropriate controller in API/Controllers/
  2. Add request model class if needed (same file or separate)
  3. Controller calls MessageBroker (for shared logic) or database directly (for reads)
  4. Update ToolsController.cs to include the new endpoint in the self-documenting list

Data Storage Patterns

  • Checklists: JSON array in checklist_json column: [{"item":"...","status":"pending|coding|testing|done","notes":[{"text":"...","at":"...","by":"..."}],"assignee":"...","cycleCount":0}]
  • Plans: Markdown text in plan column
  • Continuation notes: Free text in continuation_notes column (session handoff context)
  • Skills/interests: JSON arrays in profile columns (skills_json, interests_json)
  • Migrations: Manual column-check migrations in database constructors (uses PRAGMA table_info + ALTER TABLE ADD COLUMN)

Checklist State Machine

                    +----------+
                    | pending  |
                    +----+-----+
                         |
                    (start work)
                         |
                    +----v-----+
               +--->|  coding  |<---+
               |    +----+-----+    |
               |         |         |
          (fail/fix)  (submit)  (reject)
               |         |         |
               |    +----v-----+   |
               +----| testing  |---+
                    +----+-----+
                         |
                    (approve)
                         |
                    +----v-----+
                    |   done   |
                    +----------+

  Cycle count increments each coding->testing->coding loop.
  At 3 cycles, escalation inbox notification is sent to PM.

Folder Map

FolderPurposeKey Files
Services/Business logic & SQLite persistenceTaskDatabase, ProjectService, ProjectDatabase, ProjectContextService, ProjectJsonMigrationService, TerminalSpawner, SettingsService, KnowledgeDatabase, DebugLogService, TeamWatcherService, CompanionProcessManager, GatewayIntegrationService, OwnerProfileService, RipgrepService, TerminalStreamService
MCPServer/Services/MCP server servicesMessageBroker, PoolCoordinator, ActivityService, StaleTaskService, SpawnService, HttpWebhookService, SessionDiscovery, ComplexityDetector, SummaryService
MCPServer/Models/Data models (19 files)KanbanTask, Plan, Message, InboxMessage, TeamMemberProfile, TaskSummary, HelperSession, CodeDigest, KnowledgeEntry, ActivityEvent, TerminalInfo, TaskAttachment, ComplexityStats
Models/App-level models (8+ files)TerminalSessionInfo, SpawnedTeammate, Project, ProjectAgent, ProjectMcpServer, ProjectSpecialistAgent, ProjectPath, ProjectPromptEntry, ProjectSkill, DebugLogEntry
API/Controllers/REST endpoints (~25 controllers)TasksController, MessagingController, OfficeController, SpawnController, KnowledgeController, SessionLineageController, ProjectContextController, TeamController, DebugController, ToolsController, AgentPanelsController, AgentStatsController, BrowserTabsController, CompanionController, GatewayController, NotificationsController, OwnerProfileController, TaskReportsController, TerminalStreamController, XamlPreviewController, RipgrepController, CodeGraphController, SettingsController, WorktreesController, MultiConnectController, BranchMetadataController, WikiController, SessionMemoryController, RemoteModeController
TasksPanel/Kanban board UITasksPanelDocument + TasksPanelControl (WebView2)
ChatPanel/Messaging UIChatPanelDocument + ChatPanelControl (WebView2)
ActivityPanel/Activity feed UIActivityPanelDocument (WebView2)
ProfilePanel/Team profiles UIProfilePanelDocument (WebView2)
InboxPanel/Notifications UIInboxPanelDocument
AgentPanel/Subagent viewerAgentPanelControl (WebView2 transcript viewer)
FilePreviewPanel/File previewFilePreviewPanelDocument (file content preview)
Terminal/Terminal hostingConPtyTerminal, WebViewTerminalRenderer
Docking/Window layoutGridLayoutManager
Dialogs/Modal dialogs (11)ProjectManager, Settings, ChatHistory, OwnerProfile, NewProject, etc.
Controls/Custom UI controlsTerminalStatusBar (3-row status display)
docs/Documentation (this site + architecture docs)16+ design specs & workflow guides

Codebase Statistics

  • ~150 C# production files, ~30K+ lines of code
  • 1 primary SQLite database (multiterminal.db) with 30+ tables
  • 19 data models, ~90 MCP tools, ~25 REST controllers
  • 11 UI panels (WebView2-based), 11 dialog windows
  • REST API on port 5050, MCP server via Node.js (stdio transport)