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.
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:
Terminal/ (ConPTY terminals rendered in WebView2), Docking/ (GridLayoutManager grid presets + layout persistence), and Dialogs/ (11 modal windows — Settings, Project, History, Owner Profile, …).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:
rg.exe).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:
All durable state lives in SQLite — no external database server. Access is wrapped by per-domain data classes:
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.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:
%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.
| File | LOC | Role |
|---|---|---|
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
create_task(title="Fix bug", ...) via MCP toolPOST /api/tasks with JSON body_broker.CreateTask(...)KanbanTask object, adds to cache, calls _taskDb.SaveTask(...), fires TasksUpdated eventtasks tableTasksUpdated event, refreshes TasksPanel UIChecklist Item Transition
update_task_checklisttaskId, itemIndex=0, newStatus="testing", notes="Done implementing"coding → testing allowed. Updates item status, appends notes, increments cycle count if cycling.checklist_jsonready_for_testing inbox message for PMescalation inbox messageHost-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)
~/.claude/projects/{folder}/{session-id}.jsonlsession-status-hook.js (SessionStart)MULTITERMINAL_NAME env var + hookData.session_id. Writes (session_id, agent_name, is_active=1) to session_agent_map table.team_member_profiles with is_online=1.Phase 2: Session End (Hook)
session-status-hook.js fires with SessionEnd.session-status-hook.js (SessionEnd)session_agent_map: sets is_active=0, writes ended_at timestamp.POST /api/messaging/disconnect (or direct DB fallback).Phase 3: Auto-Sync on Startup
MainForm.InitializeMcpServerAndChatPanel() fires background Task.Run.ProjectDatabase. For each, resolves Claude project folder path.SessionLineageService.SyncNewSessions()*.jsonl files. Skips already-imported sessions (GetImportedSessionIds). Skips active sessions (GetActiveSessionIds from session_agent_map where is_active=1).session_agent_map for the real agent name (e.g. "Alice"). Falls back to "Unknown" only if no mapping exists.session_lineage + session_messagesPhase 4: Session Recap at Terminal Start
session-status-hook.js (SessionStart)GET /api/session-lineage/latest?projectPath=...&agentName={terminalName}SessionLineageControlleragentName filter to SessionLineageService.GetMostRecentSessionForProject()agent_name = @agentName. Returns cached summary or recent messages for lazy generation.Key Files
| File | Role |
|---|---|
.claude/hooks/session-status-hook.js | Writes session→agent mapping on start/end, injects recap + knowledge |
Services/SessionLineageService.cs | Sync logic, JSONL parsing, queries |
Services/SessionSyncService.cs | Path conversion, JSONL message parsing |
Services/TaskDatabase.cs | All session tables + CRUD + FTS5 |
Services/KnowledgeDatabase.cs | Knowledge CRUD + attention decay (BumpReference) |
API/Controllers/SessionLineageController.cs | REST 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.
session-status-hook.js (SessionStart)knowledge_entries with decay ranking:score = (reference_count + 1) / (days_since_last_referenced + 1)reference_count += 1 and last_referenced = now, reinforcing their ranking for next session.ORDER BY updated_at DESC.Subprocess Isolation
Spawned team agents receive controlled context to prevent global CLAUDE.md leakage and user-level hook interference.
TerminalSpawner.SpawnTerminal()GenerateAgentSystemPrompt(agentName, agentType) to create a per-agent prompt file.%APPDATA%/multiterminal/agent-{name}-prompt.md containing: agent identity, rules from multiterminal-rules.md, and agent constraints (focus on task, no global settings changes).--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 messagingIsolation Key Files
| File | Role |
|---|---|
Services/TerminalSpawner.cs | Generates prompt file, passes isolation flags to Claude CLI |
multiterminal-rules.md | Shared 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
| Item | Purpose |
|---|---|
multiterminal.db | Primary 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.db | Reliable inter-terminal message-delivery queue (retry + de-duplication), kept separate so delivery survives restarts independently. (Also has -wal/-shm sidecars.) |
Configuration & state files
| Item | Purpose |
|---|---|
.mcp.json | Registers the two stdio MCP servers (multiterminal + mcp-gateway). Claude Code is pointed at it with --mcp-config. Generated by the installer. |
settings.txt | User/app settings (key=value). Per-install Multi-Connect and Presence overrides are written here and win over appsettings.json. |
layout.xml | Saved docking layout — panel positions, sizes, and visibility (restored on next launch). .bak is the previous layout. |
companion-processes.json | Companion processes MultiTerminal auto-launches on startup (e.g. the phone gateway). |
push-config.json | Web-Push VAPID identity + your phones' push subscriptions (Multi-Connect notifications). |
projects.json | JSON project registry kept for portability (the SQLite ProjectDatabase is the primary source). |
prompts.json | Saved reusable prompts. |
subagent-map.json | Maps spawned subagents back to the agent that spawned them. |
oracle-system-prompt.md | System prompt used by the Oracle helper. |
Subfolders
| Item | Purpose |
|---|---|
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.
| Column | Type | Description |
|---|---|---|
id | TEXT PK | 8-char hex GUID |
title | TEXT NOT NULL | Task title |
description | TEXT | Task description |
status | TEXT NOT NULL | todo, in_progress, done, suggestion |
assignee | TEXT | Claimed agent name |
created_by | TEXT | Creator name |
created_at | DATETIME | Creation timestamp |
updated_at | DATETIME | Last update timestamp |
priority | TEXT | low, normal, high |
sub_status | TEXT | active, paused (for in_progress tasks) |
paused_at | DATETIME | When task was paused |
checklist_json | TEXT | JSON array of checklist items |
plan | TEXT | Markdown implementation plan |
implementation_summary | TEXT | What was built (markdown) |
test_results | TEXT | Test outcomes (markdown) |
continuation_notes | TEXT | Session handoff context |
auto_status | INTEGER | Auto-derive status from checklist |
project_id | TEXT | FK to projects |
flagged_stale_at | DATETIME | When flagged as stale |
stale_level | INTEGER | 0=fresh, 1=7day, 2=14day |
stale_response | TEXT | User response to stale notification |
task_helpers
Helper assignments for collaborative tasks.
| Column | Type | Description |
|---|---|---|
id | TEXT PK | Helper record ID |
task_id | TEXT FK | References tasks.id |
helper_name | TEXT | Helper agent name |
added_by | TEXT | Who added the helper |
added_at | DATETIME | When added |
terminal_activity
Current state of each terminal.
| Column | Type | Description |
|---|---|---|
terminal | TEXT PK | Terminal name |
status | TEXT | idle, working, blocked |
activity | TEXT | Current activity description |
blocked_by | TEXT | What is blocking (if any) |
task_id | TEXT | Active task ID |
plan_id | TEXT | Active plan ID |
activity_feed
High-level workflow events for the manager dashboard.
| Column | Type | Description |
|---|---|---|
id | INTEGER PK | Auto-increment |
timestamp | TEXT | Event timestamp |
activity_type | TEXT | Event type |
actor | TEXT | Who triggered it |
summary | TEXT | Human-readable summary |
severity | TEXT | info, warning, error |
details_json | TEXT | JSON event details |
task_summaries
Progress snapshots for tracking work history and handoffs.
| Column | Type | Description |
|---|---|---|
id | INTEGER PK | Auto-increment |
task_id | TEXT FK | References tasks.id |
summary_at | DATETIME | When summarized |
triggered_by | TEXT | What triggered the summary |
previous_status | TEXT | Status before transition |
new_status | TEXT | Status after transition |
work_completed | TEXT | What was done |
next_steps | TEXT | What's next |
blockers | TEXT | Current blockers |
author | TEXT | Who wrote it |
team_member_profiles
Rich identity information for team agents.
| Column | Type | Description |
|---|---|---|
id | TEXT PK | Profile ID |
display_name | TEXT | Display name |
avatar_url | TEXT | Avatar image URL |
role | TEXT | Agent role |
bio | TEXT | Agent bio/description |
skills_json | TEXT | JSON array of skills |
interests_json | TEXT | JSON array of interests |
user_inbox
Inbox notifications for task events.
| Column | Type | Description |
|---|---|---|
id | TEXT PK | Message ID |
user_id | TEXT | Recipient user |
task_id | TEXT FK | Related task |
task_title | TEXT | Task title snapshot |
checklist_item_index | INTEGER | Related checklist item |
checklist_item_name | TEXT | Item name snapshot |
message_type | TEXT | ready_for_testing, escalation, task_complete, helper_request |
summary | TEXT | Human-readable summary |
created_by | TEXT | Who triggered it |
read_at | DATETIME | When read (null if unread) |
reply_text | TEXT | Reply content |
replied_at | DATETIME | When replied |
task_attachments
Image attachments stored as binary blobs.
| Column | Type | Description |
|---|---|---|
id | TEXT PK | Attachment ID |
task_id | TEXT FK | References tasks.id |
checklist_item_index | INTEGER | Associated checklist item |
file_name | TEXT | Original filename |
mime_type | TEXT | MIME type (image/png, etc.) |
data | BLOB | Raw binary image data |
added_by | TEXT | Who added it |
complexity_decisions
Learnable heuristic for task complexity analysis.
| Column | Type | Description |
|---|---|---|
id | INTEGER PK | Auto-increment |
task_id | TEXT FK | References tasks.id |
score | INTEGER | Complexity score (0-100) |
signals_json | TEXT | Detected complexity signals |
suggested_plan | INTEGER | Whether a plan was suggested |
user_accepted | INTEGER | User's decision (for learning) |
task_relationships
Blocking and dependency relationships between tasks.
| Column | Type | Description |
|---|---|---|
id | INTEGER PK | Auto-increment |
source_task_id | TEXT FK | Source task |
target_task_id | TEXT FK | Target task |
type | TEXT | blocks, depends_on, related_to |
created_by | TEXT | Who created the relationship |
created_at | DATETIME | Creation timestamp |
task_file_links
Files linked to tasks for code review and context.
| Column | Type | Description |
|---|---|---|
id | INTEGER PK | Auto-increment |
task_id | TEXT FK | References tasks.id |
file_path | TEXT | Absolute file path |
description | TEXT | Why this file is relevant |
line_start | INTEGER | Start line number (optional) |
line_end | INTEGER | End line number (optional) |
added_by | TEXT | Who linked it |
added_at | DATETIME | When linked |
task_reports
Persisted agent reports (HTML/markdown) linked to tasks.
| Column | Type | Description |
|---|---|---|
id | TEXT PK | Report ID |
task_id | TEXT FK | References tasks.id |
invocation_id | TEXT | Links to agent_invocations |
agent_name | TEXT | Agent that generated the report |
report_type | TEXT | html or markdown |
report_content | TEXT | Full report content |
verdict | TEXT | PASS, FAIL, PASS WITH NOTES |
score | INTEGER | Numeric score 0-100 |
created_at | DATETIME | Creation timestamp |
created_by | TEXT | Who saved the report |
agent_invocations
Tracks specialist agent invocations with performance metrics.
| Column | Type | Description |
|---|---|---|
id | TEXT PK | Invocation ID |
agent_name | TEXT | Agent name (verifier, code-reviewer, etc.) |
task_id | TEXT FK | Related task |
invoked_by | TEXT | Who triggered the invocation |
model_used | TEXT | Claude model used |
verdict | TEXT | Result verdict |
score | INTEGER | Numeric score |
findings_count | INTEGER | Number of findings |
duration_ms | INTEGER | Execution time in ms |
invoked_at | DATETIME | When invoked |
completed_at | DATETIME | When completed |
report_summary | TEXT | Brief 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).
| Column | Type | Description |
|---|---|---|
id | TEXT PK | Notification ID |
notification_type | TEXT | Type of notification |
title | TEXT | Notification title |
message | TEXT | Notification message |
session_id | TEXT | Claude Code session |
agent_name | TEXT | Agent that triggered it |
cwd | TEXT | Working directory |
read_at | DATETIME | When read (null if unread) |
created_at | DATETIME | Creation timestamp |
owner_profile
Owner identity: git user.name, email, GitHub username, and encrypted token.
| Column | Type | Description |
|---|---|---|
id | INTEGER PK | Singleton (always 1) |
full_name | TEXT | Git user.name |
email | TEXT | Git user.email |
github_username | TEXT | GitHub username |
github_token_encrypted | TEXT | Encrypted GitHub PAT |
created_at | DATETIME | When created |
updated_at | DATETIME | Last updated |
chat_messages
Persistent inter-terminal chat messages (survives restarts).
| Column | Type | Description |
|---|---|---|
id | INTEGER PK | Auto-increment |
from_name | TEXT | Sender name |
to_name | TEXT | Recipient name (null for broadcast) |
message | TEXT | Message content |
timestamp | DATETIME | When sent |
multiterminal.db - Session Lineage Tables
session_lineage
Tracks parent/child relationships between Claude Code sessions.
| Column | Type | Description |
|---|---|---|
id | INTEGER PK | Auto-increment |
session_id | TEXT UNIQUE | Session identifier |
parent_session_id | TEXT | Parent for lineage chaining |
task_id | TEXT FK | Linked kanban task |
agent_name | TEXT | Agent who ran the session |
session_type | TEXT | coding, review, testing, terminal |
summary | TEXT | Generated session summary |
session_file_path | TEXT | Path to JSONL transcript |
started_at | TEXT | Session start time |
ended_at | TEXT | Session end time |
session_messages
Individual messages extracted from session JSONL files.
| Column | Type | Description |
|---|---|---|
id | INTEGER PK | Auto-increment |
session_id | TEXT FK | References session_lineage.session_id |
task_id | TEXT | Linked task (denormalized) |
agent_name | TEXT | Agent name (denormalized) |
message_index | INTEGER | Position in session |
role | TEXT | user or assistant |
content | TEXT | Message content |
tool_name | TEXT | Tool used (if any) |
timestamp | TEXT | Message 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.
| Column | Type | Description |
|---|---|---|
session_id | TEXT PK | Claude Code session GUID |
agent_name | TEXT | Terminal agent name (e.g. "Alice") |
is_active | INTEGER | 1 = session in progress, 0 = ended |
started_at | TEXT | When the session started |
ended_at | TEXT | When the session ended (null if active) |
multiterminal.db - Knowledge Tables
knowledge_entries
Institutional memory: decisions, patterns, gotchas, anti-patterns.
| Column | Type | Description |
|---|---|---|
id | INTEGER PK | Auto-increment |
project_id | TEXT | Project scope (null = global) |
category | TEXT | decision, pattern, gotcha, anti_pattern, debug_insight, preference |
title | TEXT | Short summary title |
content | TEXT | Full knowledge content |
source_type | TEXT | manual, session, debug, review |
source_id | TEXT | Reference ID (session, task) |
source_agent | TEXT | Agent who contributed |
tags | TEXT | Comma-separated tags |
confidence | TEXT | confirmed, likely, uncertain |
superseded_by | INTEGER | ID of replacement entry |
last_referenced | TEXT | ISO timestamp of last access (search or injection). Used by attention decay ranking. |
reference_count | INTEGER | Total 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.
| Column | Type | Description |
|---|---|---|
id | INTEGER PK | Auto-increment |
project_id | TEXT | Project scope |
file_path | TEXT | Absolute path to source file |
file_hash | TEXT | SHA256 for staleness detection |
purpose | TEXT | One-sentence file description |
key_classes | TEXT | JSON array of class names |
key_methods | TEXT | JSON array of method names |
patterns | TEXT | Notable patterns |
gotchas | TEXT | Pitfalls and gotchas |
dependencies | TEXT | JSON array of dependencies |
line_count | INTEGER | File line count |
digest_model | TEXT | Model 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.
| Column | Type | Description |
|---|---|---|
id | TEXT PK | Project GUID |
name | TEXT | Project name |
description | TEXT | Project description |
path | TEXT | Source path |
source_path | TEXT | Source code location |
deploy_path | TEXT | Deploy output location |
build_output_path | TEXT | Build output directory |
build_command | TEXT | Build command |
deploy_command | TEXT | Deploy command |
launch_command | TEXT | Launch command |
project_type | TEXT | Project archetype |
current_version | TEXT | Current version string |
is_pinned | INTEGER | Pinned to dashboard |
icon | TEXT | Icon identifier |
icon_color | TEXT | Icon color |
team_lead | TEXT | Team lead name |
git_repo_url | TEXT | Git repository URL |
git_default_branch | TEXT | Default git branch |
git_auto_commit | INTEGER | Auto-commit enabled |
project_agents
Agents assigned to a project.
| Column | Type | Description |
|---|---|---|
id | INTEGER PK | Auto-increment |
project_id | TEXT FK | References projects.id |
agent_name | TEXT | Agent name |
role | TEXT | Agent role |
preferred_model | TEXT | opus, sonnet, haiku |
project_mcp_servers
MCP servers configured for a project.
| Column | Type | Description |
|---|---|---|
id | INTEGER PK | Auto-increment |
project_id | TEXT FK | References projects.id |
server_name | TEXT | Server name |
is_enabled | INTEGER | Enabled flag |
project_specialist_agents
Specialist agents (devils-advocate, verifier, etc.) for a project.
| Column | Type | Description |
|---|---|---|
id | INTEGER PK | Auto-increment |
project_id | TEXT FK | References projects.id |
agent_type | TEXT | devils-advocate, verifier, etc. |
is_enabled | INTEGER | Enabled flag |
custom_prompt | TEXT | Override prompt |
project_paths
Named filesystem paths for a project.
| Column | Type | Description |
|---|---|---|
id | INTEGER PK | Auto-increment |
project_id | TEXT FK | References projects.id |
path_type | TEXT | source, deploy, build_output, docs |
path_value | TEXT | Filesystem path |
description | TEXT | Path description |
project_prompts
Stored prompts and instructions for a project.
| Column | Type | Description |
|---|---|---|
id | INTEGER PK | Auto-increment |
project_id | TEXT FK | References projects.id |
prompt_type | TEXT | system, user, context, workflow |
prompt_text | TEXT | Prompt content |
display_order | INTEGER | Sort order |
project_skills
Skills enabled for a project.
| Column | Type | Description |
|---|---|---|
id | INTEGER PK | Auto-increment |
project_id | TEXT FK | References projects.id |
skill_name | TEXT | Skill name |
is_enabled | INTEGER | Enabled flag |
mcp_registry
Three-tier MCP server registry (multiterminal, global, optional).
| Column | Type | Description |
|---|---|---|
server_name | TEXT PK | MCP server name |
tier | TEXT | multiterminal, global, optional |
command | TEXT | Server command |
args_json | TEXT | JSON array of arguments |
env_json | TEXT | JSON object of env vars |
is_enabled | INTEGER | Enabled 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.
| Event | Payload | When Fired |
|---|---|---|
MessageSent | Message | Inter-terminal message delivered |
TerminalRegistered | TerminalInfo | New terminal registers |
TerminalDisconnected | TerminalInfo | Terminal disconnects |
TasksUpdated | List<KanbanTask> | Any task created, updated, or deleted |
TaskClaimed | TaskClaimedEventArgs | Task assigned to an agent |
ActivityRecorded | ActivityEvent | Activity feed event recorded |
PlanUpdated | PlanUpdateEventArgs | Task plan created or modified |
ProjectsUpdated | List<Project> | Project list changed |
ProfilesUpdated | List<TeamMemberProfile> | Team profiles changed |
HelperSessionUpdated | HelperSession | Helper session state changed |
HelperMessageLogged | HelperMessage | Helper message logged |
InboxUpdated | InboxUpdatedEventArgs | Inbox message created or read |
OfficeAgentSpawned | OfficeAgentInfo | Agent walks into office panel |
OfficeAgentDeparted | OfficeAgentInfo | Agent leaves office panel |
AgentPanelCloseRequested | string (transcript path) | Subagent finished, close panel |
ReportSaved | ReportSavedEventArgs | Agent pipeline report saved for a task |
NotificationReceived | NotificationEventArgs | Push notification received from hooks |
BrowserTabRequested | BrowserTabEventArgs | Agent requested a browser tab in HUD |
SessionLineageUpdated | string (task ID) | Session imported or synced |
Key Patterns
Adding a UI Panel
- Create
{Name}Panel/{Name}PanelDocument.csinheritingDockContent(setDockAreas,HideOnClose=true) - Create inner control with WebView2 or custom renderer
- Add
Initialize(MessageBroker broker)andApplyTheme(bool isDark)methods - In MainForm: instantiate, call
Initialize(), wire events, add toolbar toggle button - Follow existing panels (TasksPanel, ActivityPanel) as templates
Adding a Backend Feature
- Add model to
MCPServer/Models/ - Add persistence to
TaskDatabase.cs(table + CRUD methods + migration) - Add routing to
MessageBroker.cs(methods + events) - Add MCP tool to
MCPServer/Tools/(orindex.js) if agents need access - Add REST endpoint to
API/Controllers/if HTTP access needed
Adding an MCP Tool
- Add tool definition to the
toolsarray in%APPDATA%\multiterminal\mcp\index.js - Add handler in the
CallToolRequestSchemaswitch block in the same file - Tool handler calls the REST API which delegates to MessageBroker which delegates to TaskDatabase
- Return formatted text result for the agent
Adding a REST Endpoint
- Add method to the appropriate controller in
API/Controllers/ - Add request model class if needed (same file or separate)
- Controller calls MessageBroker (for shared logic) or database directly (for reads)
- Update
ToolsController.csto include the new endpoint in the self-documenting list
Data Storage Patterns
- Checklists: JSON array in
checklist_jsoncolumn:[{"item":"...","status":"pending|coding|testing|done","notes":[{"text":"...","at":"...","by":"..."}],"assignee":"...","cycleCount":0}] - Plans: Markdown text in
plancolumn - Continuation notes: Free text in
continuation_notescolumn (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
| Folder | Purpose | Key Files |
|---|---|---|
Services/ | Business logic & SQLite persistence | TaskDatabase, ProjectService, ProjectDatabase, ProjectContextService, ProjectJsonMigrationService, TerminalSpawner, SettingsService, KnowledgeDatabase, DebugLogService, TeamWatcherService, CompanionProcessManager, GatewayIntegrationService, OwnerProfileService, RipgrepService, TerminalStreamService |
MCPServer/Services/ | MCP server services | MessageBroker, 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 UI | TasksPanelDocument + TasksPanelControl (WebView2) |
ChatPanel/ | Messaging UI | ChatPanelDocument + ChatPanelControl (WebView2) |
ActivityPanel/ | Activity feed UI | ActivityPanelDocument (WebView2) |
ProfilePanel/ | Team profiles UI | ProfilePanelDocument (WebView2) |
InboxPanel/ | Notifications UI | InboxPanelDocument |
AgentPanel/ | Subagent viewer | AgentPanelControl (WebView2 transcript viewer) |
FilePreviewPanel/ | File preview | FilePreviewPanelDocument (file content preview) |
Terminal/ | Terminal hosting | ConPtyTerminal, WebViewTerminalRenderer |
Docking/ | Window layout | GridLayoutManager |
Dialogs/ | Modal dialogs (11) | ProjectManager, Settings, ChatHistory, OwnerProfile, NewProject, etc. |
Controls/ | Custom UI controls | TerminalStatusBar (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)