docs: restructure docs — eliminate v3- prefix, merge findings, create decisions.md

Merge v3-task_plan.md content into architecture.md (data model, layout system,
keyboard shortcuts) and new decisions.md (22-entry categorized decisions log).
Merge v3-findings.md into unified findings.md (16 sections covering all research).
Move progress logs to progress/ subdirectory (v2.md, v3.md, v2-archive.md).
Rename v3-release-notes.md to release-notes.md. Update all cross-references.
Delete v3-task_plan.md and v3-findings.md (content fully incorporated).
This commit is contained in:
Hibryda 2026-03-14 02:51:13 +01:00
parent 60e2bfb857
commit a89e2b9f69
11 changed files with 555 additions and 718 deletions

View file

@ -26,8 +26,8 @@ The application has three major version milestones:
| Document | What It Covers | | Document | What It Covers |
|----------|---------------| |----------|---------------|
| [architecture.md](architecture.md) | End-to-end system architecture: Rust backend, Svelte frontend, sidecar layer, data flow, IPC patterns | | [architecture.md](architecture.md) | End-to-end system architecture: Rust backend, Svelte frontend, sidecar layer, data model, layout system, data flow, IPC patterns |
| [v3-task_plan.md](v3-task_plan.md) | v3 Mission Control architecture decisions, adversarial review, data model, component tree, layout system, 10-phase plan | | [decisions.md](decisions.md) | Architecture decisions log: rationale and dates for all major design choices |
| [multi-machine.md](multi-machine.md) | Multi-machine relay architecture: bterminal-core extraction, bterminal-relay binary, RemoteManager, WebSocket protocol, reconnection | | [multi-machine.md](multi-machine.md) | Multi-machine relay architecture: bterminal-core extraction, bterminal-relay binary, RemoteManager, WebSocket protocol, reconnection |
### Subsystem Guides ### Subsystem Guides
@ -44,22 +44,21 @@ The application has three major version milestones:
| Document | What It Covers | | Document | What It Covers |
|----------|---------------| |----------|---------------|
| [phases.md](phases.md) | v2 implementation phases (1-7 + multi-machine A-D + profiles/skills) with checklists | | [phases.md](phases.md) | v2 implementation phases (1-7 + multi-machine A-D + profiles/skills) with checklists |
| [v3-progress.md](v3-progress.md) | v3 session-by-session progress log (All Phases 1-10 + production hardening) | | [progress/v3.md](progress/v3.md) | v3 session-by-session progress log (Phases 1-10 + production hardening) |
| [progress.md](progress.md) | v2 session-by-session progress log (recent sessions) | | [progress/v2.md](progress/v2.md) | v2 session-by-session progress log (recent sessions) |
| [progress-archive.md](progress-archive.md) | Archived v2 progress (2026-03-05 to 2026-03-06 early) | | [progress/v2-archive.md](progress/v2-archive.md) | Archived v2 progress (2026-03-05 to 2026-03-06 early) |
### Research & Analysis ### Research & Analysis
| Document | What It Covers | | Document | What It Covers |
|----------|---------------| |----------|---------------|
| [findings.md](findings.md) | v2 research: Claude Agent SDK, Tauri+xterm.js, terminal performance, Zellij architecture, ultrawide design patterns | | [findings.md](findings.md) | All research: Claude Agent SDK, Tauri+xterm.js, terminal performance, adversarial review, provider coupling, codebase reuse, session anchors, multi-agent design, theme evolution, performance measurements |
| [v3-findings.md](v3-findings.md) | v3 research: adversarial architecture review, production hardening analysis, provider adapter coupling map, session anchor design |
### Release ### Release & Testing
| Document | What It Covers | | Document | What It Covers |
|----------|---------------| |----------|---------------|
| [v3-release-notes.md](v3-release-notes.md) | v3.0 release notes: feature summary, breaking changes, test coverage, known limitations | | [release-notes.md](release-notes.md) | v3.0 release notes: feature summary, breaking changes, test coverage, known limitations |
| [e2e-testing.md](e2e-testing.md) | E2E testing facility: WebDriverIO fixtures, test mode, LLM judge, CI integration, troubleshooting | | [e2e-testing.md](e2e-testing.md) | E2E testing facility: WebDriverIO fixtures, test mode, LLM judge, CI integration, troubleshooting |
--- ---
@ -69,12 +68,12 @@ The application has three major version milestones:
If you are new to this codebase, read the documents in this order: If you are new to this codebase, read the documents in this order:
1. **[architecture.md](architecture.md)** — Understand how the pieces fit together 1. **[architecture.md](architecture.md)** — Understand how the pieces fit together
2. **[v3-task_plan.md](v3-task_plan.md)** — Understand the design decisions behind v3 2. **[decisions.md](decisions.md)** — Understand why things are built the way they are
3. **[sidecar.md](sidecar.md)** — Understand how agent sessions actually run 3. **[sidecar.md](sidecar.md)** — Understand how agent sessions actually run
4. **[orchestration.md](orchestration.md)** — Understand multi-agent coordination 4. **[orchestration.md](orchestration.md)** — Understand multi-agent coordination
5. **[e2e-testing.md](e2e-testing.md)** — Understand how to test changes 5. **[e2e-testing.md](e2e-testing.md)** — Understand how to test changes
For v2-specific context (the foundation that v3 builds on), read [findings.md](findings.md) and [phases.md](phases.md). For research context, read [findings.md](findings.md). For implementation history, see [phases.md](phases.md) and [progress/](progress/).
--- ---

View file

@ -320,6 +320,203 @@ Key-value store for user preferences: theme, fonts, shell, CWD, provider setting
--- ---
## Data Model
### Project Group Config (`~/.config/bterminal/groups.json`)
Human-editable JSON file defining workspaces. Each group contains up to 5 projects. Loaded at startup by `groups.rs`, not hot-reloaded.
```jsonc
{
"version": 1,
"groups": [
{
"id": "work-ai",
"name": "AI Projects",
"projects": [
{
"id": "bterminal",
"name": "BTerminal",
"identifier": "bterminal",
"description": "Terminal emulator with Claude integration",
"icon": "\uf120",
"cwd": "/home/user/code/BTerminal",
"profile": "default",
"enabled": true
}
]
}
],
"activeGroupId": "work-ai"
}
```
### TypeScript Types (`v2/src/lib/types/groups.ts`)
```typescript
export interface ProjectConfig {
id: string;
name: string;
identifier: string;
description: string;
icon: string;
cwd: string;
profile: string;
enabled: boolean;
}
export interface GroupConfig {
id: string;
name: string;
projects: ProjectConfig[]; // max 5
}
export interface GroupsFile {
version: number;
groups: GroupConfig[];
activeGroupId: string;
}
```
### SQLite Schema (v3 Additions)
Beyond the core `sessions` and `settings` tables, v3 added project-scoped agent persistence:
```sql
ALTER TABLE sessions ADD COLUMN project_id TEXT DEFAULT '';
CREATE TABLE IF NOT EXISTS agent_messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id TEXT NOT NULL,
project_id TEXT NOT NULL,
sdk_session_id TEXT,
message_type TEXT NOT NULL,
content TEXT NOT NULL,
parent_id TEXT,
created_at INTEGER NOT NULL,
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS project_agent_state (
project_id TEXT PRIMARY KEY,
last_session_id TEXT NOT NULL,
sdk_session_id TEXT,
status TEXT NOT NULL,
cost_usd REAL DEFAULT 0,
input_tokens INTEGER DEFAULT 0,
output_tokens INTEGER DEFAULT 0,
last_prompt TEXT,
updated_at INTEGER NOT NULL
);
```
---
## Layout System
### Project Grid (Flexbox + scroll-snap)
Projects are arranged horizontally in a flex container with CSS scroll-snap for clean project-to-project scrolling:
```css
.project-grid {
display: flex;
gap: 4px;
height: 100%;
overflow-x: auto;
scroll-snap-type: x mandatory;
}
.project-box {
flex: 0 0 calc((100% - (N-1) * 4px) / N);
scroll-snap-align: start;
min-width: 480px;
}
```
N is computed from viewport width: `Math.min(projects.length, Math.max(1, Math.floor(containerWidth / 520)))`
### Project Box Internal Layout
Each project box uses a CSS grid with 4 rows:
```
┌─ ProjectHeader (auto) ─────────────────┐
├─────────────────────┬──────────────────┤
│ AgentSession │ TeamAgentsPanel │
│ (flex: 1) │ (240px/overlay) │
├─────────────────────┴──────────────────┤
│ [Tab1] [Tab2] [+] TabBar auto │
├────────────────────────────────────────┤
│ Terminal content (xterm or scrollback) │
└────────────────────────────────────────┘
```
Team panel: inline at >2560px viewport (240px wide), overlay at <2560px. Collapsed when no subagents running.
### Responsive Breakpoints
| Viewport Width | Visible Projects | Team Panel Mode |
|---------------|-----------------|-----------------|
| 5120px+ | 5 | inline 240px |
| 3840px | 4 | inline 200px |
| 2560px | 3 | overlay |
| 1920px | 3 | overlay |
| <1600px | 1 + project tabs | overlay |
### xterm.js Budget: 4 Active Instances
WebKit2GTK OOMs at ~5 simultaneous xterm.js instances. The budget system manages this:
| State | xterm.js Instance? | Memory |
|-------|--------------------|--------|
| Active-Focused | Yes | ~20MB |
| Active-Background | Yes (if budget allows) | ~20MB |
| Suspended | No (HTML pre scrollback) | ~200KB |
| Uninitialized | No (placeholder) | 0 |
On focus: serialize least-recent xterm scrollback, destroy it, create new for focused tab, reconnect PTY. Suspend/resume cycle < 50ms.
### Project Accent Colors
Each project slot gets a distinct Catppuccin accent color for visual distinction:
| Slot | Color | CSS Variable |
|------|-------|-------------|
| 1 | Blue | `var(--ctp-blue)` |
| 2 | Green | `var(--ctp-green)` |
| 3 | Mauve | `var(--ctp-mauve)` |
| 4 | Peach | `var(--ctp-peach)` |
| 5 | Pink | `var(--ctp-pink)` |
Applied to border tint and header accent via `var(--accent)` CSS custom property set per ProjectBox.
---
## Keyboard Shortcuts
Three-layer shortcut system prevents conflicts between terminal input, workspace navigation, and app-level commands:
| Shortcut | Action | Layer |
|----------|--------|-------|
| Ctrl+K | Command palette | App |
| Ctrl+G | Switch group (palette filtered) | App |
| Ctrl+1..5 | Focus project by index | App |
| Alt+1..4 | Switch sidebar tab + open drawer | App |
| Ctrl+B | Toggle sidebar open/closed | App |
| Ctrl+, | Toggle settings panel | App |
| Escape | Close sidebar drawer | App |
| Ctrl+Shift+F | FTS5 search overlay | App |
| Ctrl+N | New terminal in focused project | Workspace |
| Ctrl+Shift+N | New agent query | Workspace |
| Ctrl+Tab | Next terminal tab | Project |
| Ctrl+W | Close terminal tab | Project |
| Ctrl+Shift+C/V | Copy/paste in terminal | Terminal |
Terminal layer captures raw keys only when focused. App layer has highest priority.
---
## Key Constraints ## Key Constraints
1. **WebKit2GTK has no WebGL** — xterm.js must use the Canvas addon explicitly. Maximum 4 active xterm.js instances to avoid OOM. 1. **WebKit2GTK has no WebGL** — xterm.js must use the Canvas addon explicitly. Maximum 4 active xterm.js instances to avoid OOM.

51
docs/decisions.md Normal file
View file

@ -0,0 +1,51 @@
# Architecture Decisions Log
This document records significant architecture decisions made during the development of Agent Orchestrator. Each entry captures the decision, its rationale, and the date it was made. Decisions are listed chronologically within each category.
---
## Data & Configuration
| Decision | Rationale | Date |
|----------|-----------|------|
| JSON for groups config, SQLite for session state | JSON is human-editable, shareable, version-controllable. SQLite for ephemeral runtime state. Load at startup only — no hot-reload, no split-brain risk. | 2026-03-07 |
| btmsg/bttask shared SQLite DB | Both CLI tools share `~/.local/share/bterminal/btmsg.db`. Single DB simplifies deployment — agents already have the path. Read-only for non-Manager roles via CLI permissions. | 2026-03-11 |
## Layout & UI
| Decision | Rationale | Date |
|----------|-----------|------|
| Adaptive project count from viewport width | `Math.min(projects.length, Math.max(1, Math.floor(containerWidth / 520)))` — 5 at 5120px, 3 at 1920px, scroll-snap for overflow. min-width 480px. Better than forcing 5 at all sizes. | 2026-03-07 |
| Flexbox + scroll-snap over CSS Grid | Allows horizontal scroll on narrow screens. Scroll-snap gives clean project-to-project scrolling. | 2026-03-07 |
| Team panel: inline >2560px, overlay <2560px | Adapts to available space. Collapsed when no subagents running. Saves ~240px on smaller screens. | 2026-03-07 |
| VSCode-style left sidebar (replaces top tab bar) | Vertical icon rail (2.75rem) + expandable drawer (max 50%) + always-visible workspace. Settings is a regular tab, not a special drawer. ProjectGrid always visible. Ctrl+B toggles. | 2026-03-08 |
| CSS relative units (rule 18) | rem/em for all layout CSS. Pixels only for icon sizes, borders, box shadows. Exception: `--ui-font-size`/`--term-font-size` store px for xterm.js API. | 2026-03-08 |
| Project accent colors from Catppuccin palette | Visual distinction: blue/green/mauve/peach/pink per slot 1-5. Applied to border + header tint via `var(--accent)`. | 2026-03-07 |
## Agent Architecture
| Decision | Rationale | Date |
|----------|-----------|------|
| Single shared sidecar (v3.0) | Existing multiplexed protocol handles concurrent sessions. Per-project pool deferred to v3.1 if crash isolation needed. Saves ~200MB RAM. | 2026-03-07 |
| xterm budget: 4 active, unlimited suspended | WebKit2GTK OOM at ~5 instances. Serialize scrollback to text buffer, destroy xterm, recreate on focus. PTY stays alive. Suspend/resume < 50ms. | 2026-03-07 |
| AgentPane splits into AgentSession + TeamAgentsPanel | Team agents shown inline in right panel, not as separate panes. Saves xterm/pane slots. | 2026-03-07 |
| Tier 1 agents as ProjectBoxes via `agentToProject()` | Agents render as full ProjectBoxes (not separate UI). `getAllWorkItems()` merges agents + projects. Unified rendering = less code, same capabilities. | 2026-03-11 |
| `extra_env` 5-layer passthrough for BTMSG_AGENT_ID | TS → Rust AgentQueryOptions → NDJSON → JS runner → SDK env. Minimal surface — only agent projects get env injection. | 2026-03-11 |
| Periodic system prompt re-injection (1 hour) | LLM context degrades over long sessions. 1-hour timer re-sends role/tools reminder when agent is idle. `autoPrompt`/`onautopromptconsumed` callback pattern. | 2026-03-11 |
| Role-specific tabs via conditional rendering | Manager=Tasks, Architect=Arch, Tester=Selenium+Tests, Reviewer=Tasks. PERSISTED-LAZY pattern (mount on first activation). Conditional on `isAgent && agentRole`. | 2026-03-11 |
| PlantUML via plantuml.com server (~h hex encoding) | Avoids Java dependency. Hex encoding simpler than deflate+base64. Works with free tier. Trade-off: requires internet. | 2026-03-11 |
## Themes & Typography
| Decision | Rationale | Date |
|----------|-----------|------|
| All 17 themes map to `--ctp-*` CSS vars | 4 Catppuccin + 7 Editor + 6 Deep Dark themes. All map to same 26 CSS custom properties — zero component changes when adding themes. Pure data operation. | 2026-03-07 |
| Typography via CSS custom properties | `--ui-font-family`/`--ui-font-size` + `--term-font-family`/`--term-font-size` in `:root`. Restored by `initTheme()` on startup. Persisted as SQLite settings. | 2026-03-07 |
## System Design
| Decision | Rationale | Date |
|----------|-----------|------|
| Keyboard shortcut layers: App > Workspace > Terminal | Prevents conflicts. Terminal captures raw keys only when focused. App layer uses Ctrl+K/G/B. | 2026-03-07 |
| Unmount/remount on group switch | Serialize xterm scrollbacks, destroy, remount new group. <100ms perceived. Frees ~80MB per switch. | 2026-03-07 |
| Remote machines deferred to v3.1 | Elevate to project level (`project.remote_machine_id`) but don't implement in MVP. Focus on local orchestration first. | 2026-03-07 |

View file

@ -1,12 +1,17 @@
# BTerminal v2 — Research Findings # Research Findings
## 1. Claude Agent SDK — The Foundation This document captures research conducted during v2 and v3 development — technology evaluations, architecture reviews, performance measurements, and design analysis. Each finding informed implementation decisions recorded in [decisions.md](decisions.md).
---
## 1. Claude Agent SDK (v2 Research, 2026-03-05)
**Source:** https://platform.claude.com/docs/en/agent-sdk/overview **Source:** https://platform.claude.com/docs/en/agent-sdk/overview
The Claude Agent SDK (formerly Claude Code SDK, renamed Sept 2025) provides everything we need: The Claude Agent SDK (formerly Claude Code SDK, renamed Sept 2025) provides structured streaming, subagent detection, hooks, and telemetry — everything needed for a rich agent UI without terminal emulation.
### Streaming API ### Streaming API
```typescript ```typescript
import { query } from "@anthropic-ai/claude-agent-sdk"; import { query } from "@anthropic-ai/claude-agent-sdk";
@ -14,196 +19,380 @@ for await (const message of query({
prompt: "Fix the bug", prompt: "Fix the bug",
options: { allowedTools: ["Read", "Edit", "Bash"] } options: { allowedTools: ["Read", "Edit", "Bash"] }
})) { })) {
// Each message is structured, typed, parseable console.log(message); // structured, typed, parseable
console.log(message);
} }
``` ```
### Subagent Detection ### Subagent Detection
Messages from subagents include `parent_tool_use_id`: Messages from subagents include `parent_tool_use_id`:
```typescript ```typescript
// Check for subagent invocation
for (const block of msg.message?.content ?? []) { for (const block of msg.message?.content ?? []) {
if (block.type === "tool_use" && block.name === "Task") { if (block.type === "tool_use" && block.name === "Task") {
console.log(`Subagent invoked: ${block.input.subagent_type}`); console.log(`Subagent invoked: ${block.input.subagent_type}`);
} }
} }
// Check if message is from within a subagent
if (msg.parent_tool_use_id) { if (msg.parent_tool_use_id) {
console.log("Running inside subagent"); console.log("Running inside subagent");
} }
``` ```
### Session Management ### Session Management
- `session_id` captured from init message - `session_id` captured from init message
- Resume with `options: { resume: sessionId }` - Resume with `options: { resume: sessionId }`
- Subagent transcripts persist independently - Subagent transcripts persist independently
### Hooks ### Hooks
`PreToolUse`, `PostToolUse`, `Stop`, `SessionStart`, `SessionEnd`, `UserPromptSubmit` `PreToolUse`, `PostToolUse`, `Stop`, `SessionStart`, `SessionEnd`, `UserPromptSubmit`
### Telemetry ### Telemetry
Every `SDKResultMessage` contains: `total_cost_usd`, `duration_ms`, per-model `modelUsage` breakdowns. Every `SDKResultMessage` contains: `total_cost_usd`, `duration_ms`, per-model `modelUsage` breakdowns.
### Key Insight ### Key Insight
**We don't need terminal emulation for SDK agents.** The SDK gives us structured data — we can render it as rich UI (markdown, diff views, file cards, agent trees) instead of raw terminal text. Terminal emulation (xterm.js) is only needed for SSH, local shell, and legacy Claude CLI sessions.
The SDK gives structured data — we render it as rich UI (markdown, diff views, file cards, agent trees) instead of raw terminal text. Terminal emulation (xterm.js) is only needed for SSH, local shell, and legacy CLI sessions.
--- ---
## 2. Tauri + xterm.js — Proven Stack ## 2. Tauri + xterm.js Integration (v2 Research, 2026-03-05)
### Existing Projects ### Existing Projects
- **tauri-terminal** (github.com/marc2332/tauri-terminal) — basic Tauri + xterm.js + portable-pty
- **Terminon** (github.com/Shabari-K-S/terminon) — Tauri v2 + React + xterm.js, SSH profiles, split panes - **tauri-terminal** — basic Tauri + xterm.js + portable-pty
- **terraphim-liquid-glass-terminal** — Tauri + xterm.js with design effects - **Terminon** — Tauri v2 + React + xterm.js, SSH profiles, split panes
- **tauri-plugin-pty** (github.com/Tnze/tauri-plugin-pty) — PTY plugin for Tauri 2, xterm.js bridge - **tauri-plugin-pty** — PTY plugin for Tauri 2, xterm.js bridge
### Integration Pattern ### Integration Pattern
```
Frontend (xterm.js) ←→ Tauri IPC ←→ Rust PTY (portable-pty) ←→ Shell/SSH/Claude
```
- `pty.onData()``term.write()` (output)
- `term.onData()``pty.write()` (input)
### Tauri IPC Latency ```
- Linux: ~5ms for typical payloads (serialization-free IPC in v2) Frontend (xterm.js) <-> Tauri IPC <-> Rust PTY (portable-pty) <-> Shell/SSH/Claude
- For terminal output: irrelevant. Claude outputs text at human-readable speed. ```
- For keystroke echo: 5ms + xterm.js render = ~10-15ms total. Acceptable.
- `pty.onData()` -> `term.write()` (output)
- `term.onData()` -> `pty.write()` (input)
--- ---
## 3. Terminal Performance Context ## 3. Terminal Performance Benchmarks (v2 Research, 2026-03-05)
### Native Terminal Latency
### Native Terminal Latency (for reference)
| Terminal | Latency | Notes | | Terminal | Latency | Notes |
|---|---|---| |----------|---------|-------|
| xterm (native) | ~10ms | Gold standard | | xterm (native) | ~10ms | Gold standard |
| Alacritty | ~12ms | GPU-rendered Rust | | Alacritty | ~12ms | GPU-rendered Rust |
| Kitty | ~13ms | GPU-rendered | | Kitty | ~13ms | GPU-rendered |
| VTE (GNOME Terminal) | ~50ms | GTK3/4, spikes above | | VTE (GNOME Terminal) | ~50ms | GTK3/4, spikes above |
| Hyper (Electron+xterm.js) | ~40ms | Web-based worst case | | Hyper (Electron+xterm.js) | ~40ms | Web-based worst case |
### Throughput (find /usr benchmark)
All within 0.5s of each other: xterm 2.2s, alacritty 2.2s, wezterm 2.8s. "Not meaningfully different to a human."
### Memory ### Memory
- Alacritty: ~30MB
- WezTerm: ~45MB
- xterm (native): ~5MB
### Verdict for BTerminal v2 - Alacritty: ~30MB, WezTerm: ~45MB, xterm native: ~5MB
xterm.js in Tauri will be ~20-30ms latency, ~40MB per terminal instance. For Claude sessions (AI output, not vim), this is perfectly fine. The VTE we currently use in GTK3 is actually *slower* at ~50ms.
### Verdict
xterm.js in Tauri: ~20-30ms latency, ~20MB per instance. For AI output (not vim), perfectly fine. The VTE we used in v1 GTK3 is actually slower at ~50ms.
--- ---
## 4. Zellij Architecture (Inspiration) ## 4. Zellij Architecture (v2 Inspiration, 2026-03-05)
**Source:** Research agent findings Zellij uses WASM plugins for extensibility: message passing at WASM boundary, permission model, event types for rendering/input/lifecycle, KDL layout files.
Zellij uses WASM plugins for extensibility: **Relevance:** We don't need WASM plugins — our "plugins" are different pane types. But the layout concept (JSON layout definitions) is worth borrowing for saved layouts.
- Plugins communicate via message passing at WASM boundary
- Permission model controls what plugins can access
- Event types for rendering, input, lifecycle
- Layout defined in KDL files
**Relevance:** We don't need WASM plugins. Our "plugins" are just different pane types (terminal, agent, markdown). But the layout concept (KDL or JSON layout definitions) is worth borrowing for saved layouts.
--- ---
## 5. 32:9 Ultrawide Design Patterns ## 5. Ultrawide Design Patterns (v2 Research, 2026-03-05)
**Key Insight:** 5120px width ÷ ~600px per useful pane = ~8 panes max, ~4-5 comfortable. **Key Insight:** 5120px width / ~600px per pane = ~8 panes max, ~4-5 comfortable.
**Layout Philosophy:** **Layout Philosophy:**
- Center of screen = primary attention (1-2 main agent panes) - Center = primary attention (1-2 main agent panes)
- Left edge = navigation (session sidebar, 250-300px) - Left edge = navigation (sidebar, 250-300px)
- Right edge = context (agent tree, file viewer, 350-450px) - Right edge = context (agent tree, file viewer, 350-450px)
- Never use tabs for primary content — everything visible - Never use tabs for primary content — everything visible
- Tabs only for switching between saved layouts - Tabs only for switching saved layouts
**Interaction Model:**
- Click sidebar session → opens in next available pane slot
- Agent spawns subagent → new pane auto-appears (or tree node if panes full)
- File reference in agent output → click to open markdown viewer pane
- Drag pane borders to resize
- Keyboard: Ctrl+1-8 to focus pane, Ctrl+Shift+Arrow to move pane
--- ---
## 6. Frontend Framework Choice ## 6. Frontend Framework Choice (v2 Research, 2026-03-05)
### Why Svelte 5 (revised from initial Solid.js choice) ### Why Svelte 5
- **Fine-grained reactivity** — $state/$derived runes match Solid's signals model
- **No VDOM** — critical when we have 4-8 panes each streaming data - **Fine-grained reactivity**`$state`/`$derived` runes match Solid's signals model
- **No VDOM** — critical when 4-8 panes stream data simultaneously
- **Small bundle** — ~5KB runtime vs React's ~40KB - **Small bundle** — ~5KB runtime vs React's ~40KB
- **Larger ecosystem** — more component libraries, xterm.js wrappers, better tooling - **Larger ecosystem** than Solid.js — more component libraries, better tooling
- **Better TypeScript support** — improved in Svelte 5
### Why NOT Solid.js (initially considered)
### Why NOT Solid.js (initial choice, revised)
- Ecosystem too small for production use - Ecosystem too small for production use
- Fewer component libraries and integrations
- Svelte 5 runes eliminated the ceremony gap - Svelte 5 runes eliminated the ceremony gap
### NOT React ### Why NOT React
- VDOM reconciliation across 4-8 simultaneously updating panes = CPU waste - VDOM reconciliation across 4-8 simultaneously updating panes = CPU waste
- Larger bundle - Larger bundle, state management complexity (Redux/Zustand needed)
- State management complexity (need Redux/Zustand for cross-pane state)
--- ---
## 7. Key Technical Risks ## 7. Claude Code CLI Observation (v2 Research, 2026-03-05)
| Risk | Mitigation | Three observation tiers for Claude sessions:
|---|---|
| **WebKit2GTK has NO WebGL** — xterm.js falls back to Canvas on Linux | Use xterm.js Canvas addon explicitly. For AI output (not vim), Canvas at 60fps is fine. |
| xterm.js performance with 4+ instances (Canvas mode) | Lazy init (create xterm only when pane visible), limit to 4-6 active terminals |
| Agent SDK TS package may not run in Tauri's webview | Run SDK in Rust sidecar process, stream to frontend via Tauri events |
| Tauri IPC bottleneck with high-throughput agent output | Batch messages, use Tauri events (push) not commands (pull) |
| File watcher flooding on rapid saves | Debounce 200ms in Rust before sending to frontend |
| Layout state persistence across restarts | SQLite for sessions + layout, atomic writes |
| Tauri multi-webview behind `unstable` flag | Single webview with CSS Grid panes, not multiple webviews |
--- 1. **SDK sessions** (best): Full structured streaming, subagent detection, hooks, cost tracking
2. **CLI with stream-json** (good): `claude -p "prompt" --output-format stream-json` — structured output but non-interactive
3. **Interactive CLI** (fallback): Tail JSONL session files at `~/.claude/projects/<encoded-dir>/<session-uuid>.jsonl` + show terminal via xterm.js
## 8. Claude Code CLI Observation (Alternative to SDK) ### JSONL Session Files
**Critical discovery:** We can observe ANY running Claude Code session (even interactive CLI ones) via two mechanisms: Path encoding: `/home/user/project` -> `-home-user-project`. Append-only, written immediately. Can be `tail -f`'d for external observation.
### A. `stream-json` output mode ### Hooks (SDK only)
```bash
claude -p "fix the bug" --output-format stream-json
```
Emits typed events: `stream_event`, `assistant`, `user`, `system` (init carries session_id), `result`.
### B. JSONL session file tailing
Session files live at `~/.claude/projects/<encoded-dir-path>/<session-uuid>.jsonl`. Append-only, written immediately. Can be `tail -f`'d for external observation.
Path encoding: `/home/user/project``-home-user-project`
### C. Hooks (SDK only)
`SubagentStart`, `SubagentStop` (gives `agent_transcript_path`), `PreToolUse`, `PostToolUse`, `Stop`, `Notification`, `TeammateIdle` `SubagentStart`, `SubagentStop` (gives `agent_transcript_path`), `PreToolUse`, `PostToolUse`, `Stop`, `Notification`, `TeammateIdle`
### Implication for BTerminal v2
**Three observation tiers:**
1. **SDK sessions** (best): Full structured streaming, subagent detection, hooks, cost tracking
2. **CLI sessions with stream-json** (good): Structured output, but requires spawning claude with `-p` flag (non-interactive)
3. **Interactive CLI sessions** (fallback): Tail JSONL session files + show terminal via xterm.js
--- ---
## 9. Agent Teams (Experimental) ## 8. Agent Teams (v2 Research, 2026-03-05)
`CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` enables full independent Claude Code instances sharing a task list and mailbox. `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` enables full independent Claude Code instances sharing a task list and mailbox.
- 3-5 teammates is the practical sweet spot (linear token cost) - 3-5 teammates is the practical sweet spot (linear token cost)
- Display modes: in-process (Shift+Down cycles), tmux (own pane each), auto - Display modes: in-process (Shift+Down cycles), tmux (own pane each), auto
- Session resumption is broken for in-process teammates - Session resumption is broken for in-process teammates
- BTerminal v2 could become the ideal frontend for Agent Teams — each teammate gets its own pane - Agent Orchestrator is the ideal frontend for Agent Teams — each teammate gets its own ProjectBox
--- ---
## 10. Competing Approaches ## 9. Competing Approaches (v2 Research, 2026-03-05)
- **claude-squad** (Go+tmux): Most adopted multi-agent manager. BTerminal v2 would replace this. - **claude-squad** (Go+tmux): Most adopted multi-agent manager
- **agent-deck**: MCP socket pooling (~85-90% memory savings). Could integrate as backend. - **agent-deck**: MCP socket pooling (~85-90% memory savings)
- **Git worktrees**: Dominant isolation strategy for parallel Claude sessions. BTerminal should support spawning agents in worktrees. - **Git worktrees**: Dominant isolation strategy for parallel Claude sessions
---
## 10. Adversarial Architecture Review (v3, 2026-03-07)
Three specialized agents reviewed the v3 Mission Control architecture before implementation. This adversarial process caught 12 issues (4 critical) that would have required expensive rework if discovered later.
### Agent: Architect (Advocate)
Proposed the core design:
- **Project Groups** as primary organizational unit (replacing free-form panes)
- **JSON config** for human-editable definitions, SQLite for runtime state
- **Single shared sidecar** with per-project isolation via `cwd`, `claude_config_dir`, `session_id`
- **Component split:** AgentPane -> AgentSession + TeamAgentsPanel
- **MVP boundary at Phase 5** (5 phases core, 5 polish)
### Agent: Devil's Advocate
Found 12 issues across the Architect's proposal:
| # | Issue | Severity | Why It Matters |
|---|-------|----------|----------------|
| 1 | xterm.js 4-instance ceiling | **Critical** | WebKit2GTK OOMs at ~5 instances. 5 projects x 1 terminal = immediate wall. |
| 2 | Single sidecar = SPOF | **Critical** | One crash kills all 5 project agents. No isolation. |
| 3 | Layout store has no workspace concept | **Critical** | v2 pane-based store cannot represent project groups. Full rewrite needed. |
| 4 | 384px per project on 1920px | **Critical** | 5 projects on 1920px = 384px each — too narrow for code. Must adapt to viewport. |
| 5 | Session identity collision | Major | Without persisted `sdkSessionId`, resuming wrong session corrupts state. |
| 6 | JSON + SQLite = split-brain risk | Major | Two sources of truth can diverge. Must clearly separate config vs state. |
| 7 | Dispatcher has no project scoping | Major | Singleton routes all messages globally. Needs projectId and per-project cleanup. |
| 8 | Markdown discovery undefined | Minor | No spec for which .md files appear in Docs tab. |
| 9 | Keyboard shortcut conflicts | Major | Three input layers can conflict without explicit precedence. |
| 10 | Remote machine support orphaned | Major | v2 remote UI doesn't map to project model. |
| 11 | No graceful degradation | Major | Broken CWD or git could fail the whole group. |
| 12 | Flat event stream wastes CPU | Minor | Messages for hidden projects still process through adapters. |
All 12 resolved before implementation. Critical items addressed in architecture. Major items implemented in MVP or deferred to v3.1 with rationale.
### Agent: UX + Performance Specialist
Provided concrete wireframes and performance budgets:
- **Adaptive layout** formula: 5 at 5120px, 3 at 1920px, 1 with scroll at <1600px
- **xterm budget:** 4 active max, suspend/resume < 50ms
- **Memory budget:** ~225MB total (4 xterm @ 20MB + Tauri + SQLite + agent stores)
- **Workspace switch:** <100ms perceived (serialize scrollbacks + unmount/mount)
- **RAF batching:** For 5 concurrent agent streams, batch DOM updates to avoid layout thrashing
---
## 11. Provider Adapter Coupling Analysis (v3, 2026-03-11)
Before implementing multi-provider support, a systematic coupling analysis mapped every Claude-specific dependency. 13+ files examined and classified into 4 severity levels.
### Coupling Severity Map
**CRITICAL — hardcoded SDK, must abstract:**
- `sidecar/agent-runner.ts` — imports Claude Agent SDK, calls `query()`, hardcoded `findClaudeCli()`. Became `claude-runner.ts` with other providers getting separate runners.
- `bterminal-core/src/sidecar.rs``AgentQueryOptions` had no `provider` field. `SidecarCommand` hardcoded runner path. Added provider-based runner selection.
- `src/lib/adapters/sdk-messages.ts``parseMessage()` assumed Claude SDK JSON format. Became `claude-messages.ts` with per-provider parsers.
**HIGH — TS mirror types, provider-specific commands:**
- `agent-bridge.ts``AgentQueryOptions` interface mirrored Rust with no provider field.
- `lib.rs``claude_list_profiles`, `claude_list_skills` are Claude-specific (kept, gated by capability).
- `claude-bridge.ts` — provider-specific adapter (kept, genericized via `provider-bridge.ts`).
**MEDIUM — provider-aware routing:**
- `agent-dispatcher.ts` — called `parseMessage()` (Claude-specific), subagent tool names hardcoded.
- `AgentPane.svelte` — profile selector, skill autocomplete assumed Claude.
**LOW — already generic:**
- `agents.svelte.ts`, `health.svelte.ts`, `conflicts.svelte.ts` — provider-agnostic.
- `bterminal-relay/` — forwards `AgentQueryOptions` as-is.
### Key Insights
1. **Sidecar is the natural abstraction boundary.** Each provider needs its own runner because SDKs are incompatible.
2. **Message format is the main divergence point.** Per-provider adapters normalize to `AgentMessage`.
3. **Capability flags eliminate provider switches.** UI checks `capabilities.hasProfiles` instead of `provider === 'claude'`.
4. **Env var stripping is provider-specific.** Claude strips `CLAUDE*`, Codex strips `CODEX*`, Ollama strips nothing.
---
## 12. Codebase Reuse Analysis: v2 to v3 (2026-03-07)
### Survived (with modifications)
| Component/Module | Modifications |
|-----------------|---------------|
| TerminalPane.svelte | Added suspend/resume lifecycle for xterm budget |
| MarkdownPane.svelte | Unchanged |
| AgentTree.svelte | Reused inside AgentSession |
| StatusBar.svelte | Rewritten for workspace store (group name, fleet status, attention queue) |
| ToastContainer.svelte | Unchanged |
| agents.svelte.ts | Added projectId field to AgentSession |
| theme.svelte.ts | Unchanged |
| notifications.svelte.ts | Unchanged |
| All adapters | Minor updates for provider routing |
| All Rust backend | Added new modules (btmsg, bttask, search, secrets, plugins) |
### Replaced
| v2 Component | v3 Replacement | Reason |
|-------------|---------------|--------|
| layout.svelte.ts | workspace.svelte.ts | Pane-based model -> project-group model |
| TilingGrid.svelte | ProjectGrid.svelte | Free-form grid -> fixed project boxes |
| PaneContainer.svelte | ProjectBox.svelte | Generic pane -> per-project container with 11 tabs |
| SessionList.svelte | ProjectHeader + CommandPalette | Sidebar list -> inline headers + Ctrl+K |
| SettingsDialog.svelte | SettingsTab.svelte | Modal dialog -> sidebar drawer tab |
| AgentPane.svelte | AgentSession + TeamAgentsPanel | Monolithic -> split for team support |
| App.svelte | Full rewrite | Tab bar -> VSCode-style sidebar layout |
### Dropped (v3.0)
| Feature | Reason |
|---------|--------|
| Detached pane mode | Doesn't fit workspace model (projects are grouped) |
| Drag-resize splitters | Project boxes have fixed internal layout |
| Layout presets | Replaced by adaptive project count from viewport |
| Remote machine UI | Deferred to v3.1 (elevated to project level) |
---
## 13. Session Anchor Design (v3, 2026-03-12)
Session anchors solve context loss during Claude's automatic context compaction.
### Problem
When Claude's context window fills up (~80% of model limit), the SDK automatically compacts older turns. This is lossy — important early decisions, architecture context, and debugging breakthroughs can be permanently lost.
### Design Decisions
1. **Auto-anchor on first compaction** — Automatically captures the first 3 turns when compaction is first detected. Preserves the session's initial context (task definition, first architecture decisions).
2. **Observation masking** — Tool outputs (Read results, Bash output) are compacted in anchors, but reasoning text is preserved in full. Dramatically reduces anchor token cost while keeping important reasoning.
3. **Budget system** — Fixed scales (2K/6K/12K/20K tokens) instead of percentage-based. "6,000 tokens" is more intuitive than "15% of context."
4. **Re-injection via system prompt** — Promoted anchors are serialized and injected as the `system_prompt` field. Simplest integration with the SDK — no conversation history modification needed.
---
## 14. Multi-Agent Orchestration Design (v3, 2026-03-11)
### Evaluated Approaches
| Approach | Pros | Cons | Decision |
|----------|------|------|----------|
| Claude Agent Teams (native) | Zero custom code, SDK-managed | Experimental, session resume broken | Supported but not primary |
| Message bus (Redis/NATS) | Proven, scalable | Runtime dependency, deployment complexity | Rejected |
| Shared SQLite + CLI tools | Zero deps, agents use shell | Polling-based, no real-time push | **Selected** |
| MCP server for agent comm | Standard protocol | Overhead per message, complex setup | Rejected |
### Why SQLite + CLI
Agents run Claude Code sessions with full shell access. Python CLI tools (`btmsg`, `bttask`) reading/writing SQLite is the lowest-friction integration:
- Zero configuration (`btmsg send architect "review this"`)
- No runtime services (no Redis, no MCP server)
- WAL mode handles concurrent access from multiple agent processes
- Same database readable by Rust backend for UI display
- 5s polling is acceptable — agents don't need millisecond latency
### Role Hierarchy
4 Tier 1 roles based on common development workflows:
- **Manager** — coordinates work (tech lead assigning sprint tasks). Unique: Task board tab, full bttask CRUD.
- **Architect** — designs solutions (senior engineer doing design reviews). Unique: PlantUML tab.
- **Tester** — runs tests (QA monitoring test suites). Unique: Selenium + Tests tabs.
- **Reviewer** — reviews code (processing PR queue). Unique: review queue depth in attention scoring.
---
## 15. Theme System Evolution (v3, 2026-03-07)
### Phase 1: 4 Catppuccin Flavors (v2)
Mocha, Macchiato, Frappe, Latte. All colors mapped to 26 `--ctp-*` CSS custom properties.
### Phase 2: +7 Editor Themes
VSCode Dark+, Atom One Dark, Monokai, Dracula, Nord, Solarized Dark, GitHub Dark. Same 26 variables — zero component changes. `CatppuccinFlavor` type generalized to `ThemeId`.
### Phase 3: +6 Deep Dark Themes
Tokyo Night, Gruvbox Dark, Ayu Dark, Poimandres, Vesper (warm dark), Midnight (pure OLED black). Same mapping.
### Key Decision
All 17 themes map to the same CSS custom property names. No component ever needs to know which theme is active. Adding new themes is a pure data operation: define 26 color values and add to `THEME_LIST`.
---
## 16. Performance Measurements (v3, 2026-03-11)
### xterm.js Canvas Performance
WebKit2GTK lacks WebGL — xterm.js falls back to Canvas 2D:
- **Latency:** ~20-30ms per keystroke (acceptable for AI output)
- **Memory:** ~20MB per active instance
- **OOM threshold:** ~5 simultaneous instances causes WebKit2GTK crash
- **Mitigation:** 4-instance budget with suspend/resume
### Tauri IPC Latency
- **Linux:** ~5ms for typical payloads
- **Terminal keystroke echo:** 5ms IPC + xterm render = 10-15ms total
- **Agent message forwarding:** Negligible (human-readable speed)
### SQLite WAL Concurrent Access
Both databases accessed concurrently by Rust backend + Python CLIs + frontend reads via IPC. WAL mode with 5s busy_timeout handles this reliably. 5-minute checkpoint prevents WAL growth.
### Workspace Switch Latency
- Serialize 4 xterm scrollbacks: ~30ms
- Destroy 4 xterm instances: ~10ms
- Unmount ProjectGrid children: ~5ms
- Mount new group: ~20ms
- Create new xterm instances: ~35ms
- **Total perceived: ~100ms** (acceptable)

View file

@ -1,6 +1,6 @@
# BTerminal v2 — Implementation Phases # BTerminal v2 — Implementation Phases
See [architecture.md](architecture.md) for system architecture and [v3-task_plan.md](v3-task_plan.md) for v3 design decisions. See [architecture.md](architecture.md) for system architecture and [decisions.md](decisions.md) for design decisions.
--- ---

View file

@ -1,6 +1,6 @@
# BTerminal v2 — Progress Log (Archive: 2026-03-05 to 2026-03-06 early) # v2 Progress Log (Archive: 2026-03-05 to 2026-03-06 early)
> Archived from [progress.md](progress.md). Covers research, Phases 1-6, polish, testing, agent teams, and subagent support. > Archived from [v2.md](v2.md). Covers research, Phases 1-6, polish, testing, agent teams, and subagent support.
## Session: 2026-03-05 ## Session: 2026-03-05

View file

@ -1,6 +1,6 @@
# BTerminal v2 — Progress Log # v2 Progress Log
> Earlier sessions (2026-03-05 to 2026-03-06 multi-machine): see [progress-archive.md](progress-archive.md) > Earlier sessions (2026-03-05 to 2026-03-06 multi-machine): see [v2-archive.md](v2-archive.md)
### Session: 2026-03-09 — AgentPane + MarkdownPane UI Redesign ### Session: 2026-03-09 — AgentPane + MarkdownPane UI Redesign

View file

@ -1,4 +1,4 @@
# BTerminal v3 — Progress Log # v3 Progress Log
### Session: 2026-03-07 — Architecture Planning + MVP Implementation (Phases 1-5) ### Session: 2026-03-07 — Architecture Planning + MVP Implementation (Phases 1-5)

View file

@ -1,4 +1,4 @@
# BTerminal v3.0 Release Notes # v3.0 Release Notes
## Mission Control — Multi-Project AI Agent Orchestration ## Mission Control — Multi-Project AI Agent Orchestration

View file

@ -1,251 +0,0 @@
# BTerminal v3 — Research Findings
## 1. Adversarial Architecture Review (2026-03-07)
Three specialized agents reviewed the v3 Mission Control architecture before implementation began. This adversarial process caught 12 issues (4 critical) that would have required expensive rework if discovered later.
### Agent: Architect (Advocate)
The Architect proposed the core design:
- **Project Groups** as the primary organizational unit (replacing free-form panes)
- **JSON config** (`groups.json`) for human-editable group/project definitions, SQLite for runtime state
- **Single shared sidecar** with per-project isolation via `cwd`, `claude_config_dir`, and `session_id`
- **Component split:** AgentPane → AgentSession + TeamAgentsPanel (subagents shown inline, not as separate panes)
- **New SQLite tables:** `agent_messages` (per-project message persistence), `project_agent_state` (sdkSessionId, cost, status)
- **MVP boundary at Phase 5** (5 phases for core, 5 for polish)
- **10-phase implementation plan** covering data model, shell, session integration, terminals, team panel, continuity, palette, docs, settings, cleanup
### Agent: Devil's Advocate
The Devil's Advocate found 12 issues across the Architect's proposal:
| # | Issue | Severity | Why It Matters |
|---|-------|----------|----------------|
| 1 | xterm.js 4-instance ceiling | **Critical** | WebKit2GTK OOMs at ~5 xterm instances. With 5 projects × 1 terminal each, we hit the wall immediately. |
| 2 | Single sidecar = SPOF | **Critical** | One sidecar crash kills all 5 project agents simultaneously. No isolation between projects. |
| 3 | Layout store has no workspace concept | **Critical** | The v2 layout store (pane-based) cannot represent project groups. Needs a full rewrite, not incremental modification. |
| 4 | 384px per project unusable on 1920px | **Critical** | 5 projects on a 1920px screen means 384px per project — too narrow for code or agent output. Must adapt to viewport. |
| 5 | Session identity collision | Major | Without persisting `sdkSessionId`, resuming the wrong session corrupts agent state. Per-project CLAUDE_CONFIG_DIR isolation is also needed. |
| 6 | JSON config + SQLite = split-brain | Major | Two sources of truth (JSON for config, SQLite for state) can diverge. Must clearly separate what lives where. |
| 7 | Agent dispatcher has no project scoping | Major | The singleton dispatcher routes all messages globally. Adding projectId to sessions and cleanup on workspace switch is essential. |
| 8 | Markdown discovery is undefined | Minor | No specification for which markdown files appear in the Docs tab. Needs a priority list and depth limit. |
| 9 | Keyboard shortcut conflicts | Major | Three input layers (terminal, workspace, app) can conflict. Needs a shortcut manager with explicit precedence. |
| 10 | Remote machine support orphaned | Major | v2's remote machine UI doesn't map to the project model. Must elevate to project level. |
| 11 | No graceful degradation for broken projects | Major | If a project's CWD doesn't exist or git is broken, the whole group could fail. Need per-project health states. |
| 12 | Flat event stream wastes CPU for hidden projects | Minor | Messages for inactive workspace projects still process through adapters. Should buffer and flush on activation. |
**Resolutions:** All 12 issues were resolved before implementation. Critical items (#1-4) were addressed in the architecture. Major items were either implemented in MVP phases or explicitly deferred to v3.1 with documented rationale. See [v3-task_plan.md](v3-task_plan.md) for the full resolution table.
### Agent: UX + Performance Specialist
The UX specialist provided concrete wireframes and performance budgets:
- **Adaptive layout:** `Math.min(projects.length, Math.max(1, Math.floor(containerWidth / 520)))` — 5 projects at 5120px, 3 at 1920px, 1 with scroll at <1600px
- **xterm.js budget:** 4 active instances max. Suspended terminals serialize scrollback to text, destroy the xterm instance, recreate on focus. PTY stays alive. Suspend/resume cycle < 50ms.
- **Memory budget:** ~225MB total (4 xterm @ 20MB + Tauri + SQLite + 5 agent stores). Well within WebKit2GTK limits.
- **Workspace switch performance:** Serialize all xterm scrollbacks, unmount ProjectGrid children, mount new group. Target: <100ms perceived latency (frees ~80MB).
- **Team panel:** Inline at >2560px viewport (240px wide), overlay at <2560px. Collapsed when no subagents.
- **Command palette:** Ctrl+K, floating overlay, fuzzy search across commands + groups + projects. 18+ commands across 6 categories.
- **RAF batching:** For 5 concurrent agent streams, batch DOM updates into requestAnimationFrame frames to avoid layout thrashing.
---
## 2. Provider Adapter Coupling Analysis (2026-03-11)
Before implementing multi-provider support, a systematic coupling analysis mapped every Claude-specific dependency in the codebase. 13+ files were examined and classified into 4 severity levels.
### Coupling Severity Map
**CRITICAL — hardcoded SDK, must abstract:**
- `sidecar/agent-runner.ts` — imports Claude Agent SDK, calls `query()`, hardcoded `findClaudeCli()`. Must become `claude-runner.ts` with other providers getting separate runners.
- `bterminal-core/src/sidecar.rs``AgentQueryOptions` struct had no `provider` field. `SidecarCommand` hardcoded `agent-runner.mjs` path. Must add provider-based runner selection.
- `src/lib/adapters/sdk-messages.ts``parseMessage()` assumes Claude SDK JSON format. Must become `claude-messages.ts` with per-provider parsers.
**HIGH — TS mirror types, provider-specific commands:**
- `src/lib/adapters/agent-bridge.ts``AgentQueryOptions` interface mirrors Rust struct with no provider field.
- `src-tauri/src/lib.rs``claude_list_profiles`, `claude_list_skills` are Claude-specific commands (kept as-is, gated by capability).
- `src/lib/adapters/claude-bridge.ts` — provider-specific adapter (kept, genericized via provider-bridge.ts).
**MEDIUM — provider-aware routing:**
- `src/lib/agent-dispatcher.ts` — calls `parseMessage()` (Claude-specific), subagent tool names hardcoded.
- `src/lib/components/Agent/AgentPane.svelte` — profile selector, skill autocomplete assume Claude.
- `ClaudeSession.svelte` — name says "Claude" but logic is mostly generic.
**LOW — already generic:**
- `agents.svelte.ts``AgentMessage` type has no Claude-specific logic.
- `health.svelte.ts`, `conflicts.svelte.ts` — provider-agnostic health and conflict tracking.
- `bterminal-relay/` — forwards `AgentQueryOptions` as-is.
### Key Insights from Analysis
1. **Sidecar is the natural abstraction boundary.** Each provider needs its own runner because SDKs are incompatible. The Rust sidecar manager selects which runner to spawn based on the `provider` field.
2. **Message format is the main divergence point.** Claude SDK emits structured JSON (assistant/user/result), Codex uses ThreadEvents, Ollama uses OpenAI-compatible streaming. Per-provider message adapters normalize everything to `AgentMessage`.
3. **Capability flags eliminate provider switches.** Instead of `if (provider === 'claude') showProfiles()`, the UI checks `capabilities.hasProfiles`. Adding a new provider only requires registering its capabilities — zero UI code changes.
4. **Environment variable stripping is provider-specific.** Claude needs `CLAUDE*` vars stripped (nesting detection). Codex needs `CODEX*` stripped. Ollama needs nothing stripped. Extracted to `strip_provider_env_var()` function.
---
## 3. Codebase Reuse Analysis (v2 → v3)
The v3 redesign reused significant portions of the v2 codebase. This analysis determined what could survive, what needed replacement, and what could be dropped entirely.
### Survived (with modifications)
| Component/Module | Modifications |
|-----------------|---------------|
| TerminalPane.svelte | Added suspend/resume lifecycle for xterm budget |
| MarkdownPane.svelte | Unchanged |
| AgentTree.svelte | Reused inside AgentSession |
| StatusBar.svelte | Rewritten for workspace store (group name, fleet status, attention queue) |
| ToastContainer.svelte | Unchanged |
| agents.svelte.ts | Added projectId field to AgentSession |
| theme.svelte.ts | Unchanged |
| notifications.svelte.ts | Unchanged |
| All adapters | Minor updates for provider routing |
| All Rust backend | Added new modules (btmsg, bttask, search, secrets, plugins) |
| highlight.ts, agent-tree.ts | Unchanged |
### Replaced
| v2 Component | v3 Replacement | Reason |
|-------------|---------------|--------|
| layout.svelte.ts | workspace.svelte.ts | Pane-based model → project-group model |
| TilingGrid.svelte | ProjectGrid.svelte | Free-form grid → fixed project boxes |
| PaneContainer.svelte | ProjectBox.svelte | Generic pane → per-project container with 11 tabs |
| SessionList.svelte | ProjectHeader + CommandPalette | Sidebar session list → inline headers + Ctrl+K |
| SettingsDialog.svelte | SettingsTab.svelte | Modal dialog → sidebar drawer tab |
| AgentPane.svelte | AgentSession + TeamAgentsPanel | Monolithic → split for team support |
| App.svelte | Full rewrite | Tab bar → VSCode-style sidebar layout |
### Dropped (v3.0)
| Feature | Reason |
|---------|--------|
| Detached pane mode | Doesn't fit workspace model (projects are grouped, not independent) |
| Drag-resize splitters | Project boxes have fixed internal layout |
| Layout presets (1-col, 2-col, etc.) | Replaced by adaptive project count from viewport |
| Remote machine UI integration | Deferred to v3.1 (elevated to project level) |
---
## 4. Session Anchor Design Analysis (2026-03-12)
Session anchors were designed to solve context loss during Claude's automatic context compaction. Research into compaction behavior informed the design.
### Problem
When Claude's context window fills up, the SDK automatically compacts older turns. This compaction is lossy — important early decisions, architecture context, and debugging breakthroughs can be permanently lost.
### Compaction Behavior (Observed)
- Compaction triggers when context exceeds ~80% of model limit
- The SDK emits a compaction event that the sidecar can observe
- Compacted turns are summarized, losing granular detail
- Multiple compaction rounds can occur in long sessions
### Design Decisions
1. **Auto-anchor on first compaction** — The system automatically captures the first 3 turns when compaction is first detected. This preserves the session's initial context (usually the task definition and first architecture decisions).
2. **Observation masking** — Tool outputs (Read results, Bash output) are compacted in anchors, but reasoning text is preserved in full. This dramatically reduces anchor token cost while keeping the important reasoning.
3. **Budget system** — Fixed budget scales (2K/6K/12K/20K tokens) instead of percentage-based. Users understand "6,000 tokens" more intuitively than "15% of context."
4. **Re-injection via system prompt** — Promoted anchors are serialized and injected as the `system_prompt` field. This is the simplest integration point with the SDK and doesn't require modifying the conversation history.
---
## 5. Multi-Agent Orchestration Design (2026-03-11)
Research into multi-agent coordination patterns informed the btmsg/bttask design.
### Evaluated Approaches
| Approach | Pros | Cons | Decision |
|----------|------|------|----------|
| Claude Agent Teams (native) | Zero custom code, SDK-managed | Experimental, session resume broken, no custom roles | Supported but not primary |
| Message bus (Redis/NATS) | Proven, scalable | Runtime dependency, deployment complexity | Rejected |
| Shared SQLite + CLI tools | Zero deps, agents use shell commands | Polling-based, no real-time push | **Selected** |
| MCP server for agent comm | Standard protocol | Overhead per message, complex setup | Rejected |
### Why SQLite + CLI
Agents run Claude Code sessions that have full shell access. A Python CLI tool (`btmsg`, `bttask`) that reads/writes SQLite is the lowest-friction integration:
- Agents can use it with zero configuration (just `btmsg send architect "review this"`)
- No runtime services to manage (no Redis, no MCP server)
- WAL mode handles concurrent access from multiple agent processes
- The same database is readable by the Rust backend for UI display
- Polling-based (5s) is acceptable for coordination — agents don't need millisecond latency
### Role Hierarchy
The 4 Tier 1 roles were chosen based on common development workflows:
- **Manager** — coordinates work, like a tech lead assigning tasks in a sprint
- **Architect** — designs solutions, like a senior engineer doing design reviews
- **Tester** — runs tests, like a QA engineer monitoring test suites
- **Reviewer** — reviews code, like a reviewer processing a PR queue
Each role has unique tabs (Task board for Manager, PlantUML for Architect, Selenium for Tester, Review queue for Reviewer) and unique bttask permissions (Manager has full CRUD, others are read-only with comments).
---
## 6. Theme System Evolution (2026-03-07)
### Original: 4 Catppuccin Flavors
v2 launched with 4 Catppuccin flavors (Mocha, Macchiato, Frappé, Latte). All colors mapped to 26 `--ctp-*` CSS custom properties.
### Extension: 7 Editor Themes
Added VSCode Dark+, Atom One Dark, Monokai, Dracula, Nord, Solarized Dark, GitHub Dark. Each theme maps to the same 26 `--ctp-*` variables — zero component changes needed. The `CatppuccinFlavor` type was generalized to `ThemeId` union type. Deprecated wrapper functions maintain backward compatibility.
### Extension: 6 Deep Dark Themes
Added Tokyo Night, Gruvbox Dark, Ayu Dark, Poimandres, Vesper (warm dark), Midnight (pure OLED black). Same 26-variable mapping.
### Key Design Decision
By mapping all 17 themes to the same CSS custom property names, no component ever needs to know which theme is active. This makes adding new themes a pure data operation — define 26 color values and add to `THEME_LIST`. The `ThemeMeta` type includes group metadata for the custom themed dropdown in SettingsTab.
---
## 7. Performance Findings
### xterm.js Canvas Performance
WebKit2GTK lacks WebGL, so xterm.js falls back to Canvas 2D rendering. Testing showed:
- **Latency:** ~20-30ms per keystroke (acceptable for AI output, not ideal for vim)
- **Memory:** ~20MB per active instance
- **OOM threshold:** ~5 simultaneous instances causes WebKit2GTK to crash
- **Mitigation:** 4-instance budget with suspend/resume for inactive terminals
### Tauri IPC Latency
- **Linux:** ~5ms for typical payloads (serialization-free IPC in Tauri 2.x)
- **Terminal keystroke echo:** 5ms IPC + xterm.js render ≈ 10-15ms total
- **Agent message forwarding:** Negligible — agent output arrives at human-readable speed
### SQLite WAL Concurrent Access
Both sessions.db and btmsg.db are accessed concurrently by:
- Rust backend (Tauri commands)
- Python CLI tools (btmsg, bttask from agent shells)
- Frontend reads via IPC
WAL mode with 5s busy_timeout handles this reliably. The 5-minute checkpoint prevents WAL file growth.
### Workspace Switch Latency
Measured during v3 development:
- Serialize 4 xterm scrollbacks: ~30ms
- Destroy 4 xterm instances: ~10ms
- Unmount ProjectGrid children: ~5ms
- Mount new group's ProjectGrid: ~20ms
- Create new xterm instances: ~35ms
- **Total perceived:** ~100ms (acceptable)

View file

@ -1,348 +0,0 @@
# BTerminal v3 — Mission Control Redesign
## Goal
Transform BTerminal from a multi-pane terminal/agent tool into a **multi-project mission control** — a helm for managing multiple development projects simultaneously, each with its own Claude agent session, team agents, terminals, and settings.
## Status: All Phases Complete (1-10) — Rev 3 (Sidebar Redesign)
---
## Core Concept
**Project Groups** are workspaces. Each group has up to 5 projects arranged horizontally. One group visible at a time. Projects have their own Claude subscription, working directory, icon, and settings. The app is a dashboard for orchestrating Claude agents across a portfolio of projects.
### Key Mental Model
```
BTerminal v2: Terminal emulator with agent sessions (panes in a grid)
BTerminal v3: Project orchestration dashboard (projects in a workspace)
```
### User Requirements
1. Projects arranged in **project groups** (many groups, switch between them)
2. Each group has **up to 5 projects** shown horizontally
3. Group/project config via **main menu** (command palette / hidden drawer, Ctrl+K)
4. Per-project settings: Claude subscription, working dir, icon (nerd font), name, identifier, description, enabled
5. Project group = workspace on screen
6. Each project box: Claude session (default, resume previous) + team agents (right) + terminal tabs (below)
7. **VSCode-style left sidebar**: Vertical icon rail (Sessions/Docs/Context/Settings) + expandable drawer panel + always-visible workspace
8. App launchable with `--group <name>` CLI arg
9. JSON config file defines all groups (`~/.config/bterminal/groups.json`)
10. Session continuity: resume previous + restore history visually
11. SSH sessions: spawnable within a project's terminal tabs
12. ctx viewer: workspace tab #3
---
## Architecture (Post-Adversarial Review)
### Adversarial Review Summary
3 agents reviewed the architecture: Architect (advocate), Devil's Advocate (attacker), UX+Performance Specialist.
**12 issues identified by Devil's Advocate. Resolutions:**
| # | Issue | Severity | Resolution |
|---|---|---|---|
| 1 | xterm.js 4-instance ceiling (WebKit2GTK OOM) | Critical | Lazy-init + scrollback serialization. Budget: 4 active xterm, unlimited suspended (text buffer). Enforced in code. |
| 2 | Single sidecar = SPOF for all projects | Critical | Accept for v3.0 (existing crash recovery). Per-project pool deferred to v3.1 if needed. |
| 3 | Session identity collision (sdkSessionId not persisted) | Major | Persist sdkSessionId in SQLite `project_agent_state` table. Per-project CLAUDE_CONFIG_DIR isolation. |
| 4 | Layout store has no workspace concept | Critical | Full rewrite: `workspace.svelte.ts` replaces `layout.svelte.ts`. |
| 5 | 384px per project unusable on 1920px | Major | Adaptive: compute visible count from viewport width (`Math.floor(width / 520)`). 5@5120px, 3@1920px, scroll-snap for rest. min-width 480px. |
| 6 | JSON config + SQLite = split-brain | Major | JSON for groups/projects config (human-editable). SQLite for session state. JSON loaded at startup only, no hot-reload. |
| 7 | Agent dispatcher is global singleton, no project scoping | Major | Add projectId to AgentSession. Dispatcher routes by project. Per-project cleanup on workspace switch. |
| 8 | Markdown discovery undefined | Minor | Priority list: CLAUDE.md, README.md, docs/*.md (max 20). Rust command scans with depth limit. |
| 9 | Keyboard shortcut conflicts (3 layers) | Major | Shortcut manager: Terminal layer (focused only), Workspace layer (Ctrl+1-5), App layer (Ctrl+K, Ctrl+G). |
| 10 | Remote machine support orphaned | Major | Elevate to project level (project.remote_machine_id). Defer integration to v3.1. |
| 11 | No graceful degradation for broken projects | Major | Project health state: healthy/degraded/unavailable/error. Colored dot indicator. |
| 12 | Flat event stream wastes CPU for hidden projects | Minor | Buffer messages for inactive workspace projects. Flush on activation. |
---
## Data Model
### Project Group Config (`~/.config/bterminal/groups.json`)
```jsonc
{
"version": 1,
"groups": [
{
"id": "work-ai",
"name": "AI Projects",
"projects": [
{
"id": "bterminal",
"name": "BTerminal",
"identifier": "bterminal",
"description": "Terminal emulator with Claude integration",
"icon": "\uf120",
"cwd": "/home/hibryda/code/ai/BTerminal",
"profile": "default",
"enabled": true
}
]
}
],
"activeGroupId": "work-ai"
}
```
### TypeScript Types (`v2/src/lib/types/groups.ts`)
```typescript
export interface ProjectConfig {
id: string;
name: string;
identifier: string;
description: string;
icon: string;
cwd: string;
profile: string;
enabled: boolean;
}
export interface GroupConfig {
id: string;
name: string;
projects: ProjectConfig[]; // max 5
}
export interface GroupsFile {
version: number;
groups: GroupConfig[];
activeGroupId: string;
}
```
### SQLite Schema Additions
```sql
ALTER TABLE sessions ADD COLUMN project_id TEXT DEFAULT '';
CREATE TABLE IF NOT EXISTS agent_messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id TEXT NOT NULL,
project_id TEXT NOT NULL,
sdk_session_id TEXT,
message_type TEXT NOT NULL,
content TEXT NOT NULL,
parent_id TEXT,
created_at INTEGER NOT NULL,
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
);
CREATE INDEX idx_agent_messages_session ON agent_messages(session_id);
CREATE INDEX idx_agent_messages_project ON agent_messages(project_id);
CREATE TABLE IF NOT EXISTS project_agent_state (
project_id TEXT PRIMARY KEY,
last_session_id TEXT NOT NULL,
sdk_session_id TEXT,
status TEXT NOT NULL,
cost_usd REAL DEFAULT 0,
input_tokens INTEGER DEFAULT 0,
output_tokens INTEGER DEFAULT 0,
last_prompt TEXT,
updated_at INTEGER NOT NULL
);
```
---
## Component Architecture
### Component Tree
```
App.svelte [REWRITTEN — VSCode-style sidebar]
├── CommandPalette.svelte [NEW]
├── GlobalTabBar.svelte [NEW] Vertical icon rail (36px, 4 SVG icons)
├── [Sidebar Panel] Expandable drawer (28em, max 50%)
│ ├── [Tab: Sessions] ProjectGrid [renders in sidebar when open]
│ ├── [Tab: Docs] DocsTab
│ ├── [Tab: Context] ContextPane
│ └── [Tab: Settings] SettingsTab
├── [Main Workspace] Always visible
│ └── ProjectGrid.svelte [NEW] Horizontal flex + scroll-snap
│ └── ProjectBox.svelte [NEW] Per-project container
│ ├── ProjectHeader.svelte [NEW] Icon + name + status dot
│ ├── ClaudeSession.svelte [NEW, from AgentPane] Main session
│ ├── TeamAgentsPanel.svelte [NEW] Right panel for subagents
│ │ └── AgentCard.svelte [NEW] Compact subagent view
│ └── TerminalTabs.svelte [NEW] Tabbed terminals
│ └── TerminalPane.svelte [SURVIVES]
├── StatusBar.svelte [MODIFIED]
└── ToastContainer.svelte [SURVIVES]
```
### What Dies
| v2 Component/Store | Reason |
|---|---|
| TilingGrid.svelte | Replaced by ProjectGrid |
| PaneContainer.svelte | Fixed project box structure |
| SessionList.svelte (sidebar) | No sidebar; project headers replace |
| SshSessionList.svelte | Absorbed into TerminalTabs |
| SettingsDialog.svelte | Replaced by SettingsTab |
| AgentPane.svelte | Split into ClaudeSession + TeamAgentsPanel |
| layout.svelte.ts | Replaced by workspace.svelte.ts |
| layout.test.ts | Replaced by workspace tests |
### What Survives
TerminalPane, MarkdownPane, AgentTree, ContextPane, StatusBar, ToastContainer, theme store, notifications store, agents store (modified), all adapters (agent-bridge, pty-bridge, claude-bridge, sdk-messages, session-bridge, ctx-bridge, ssh-bridge), all Rust backend (sidecar, pty, session, ctx, watcher), highlight utils.
---
## Layout System
### Project Grid (Flexbox + scroll-snap)
```css
.project-grid {
display: flex;
gap: 4px;
height: 100%;
overflow-x: auto;
scroll-snap-type: x mandatory;
}
.project-box {
flex: 0 0 calc((100% - (N-1) * 4px) / N);
scroll-snap-align: start;
min-width: 480px;
}
```
N computed from viewport: `Math.min(projects.length, Math.max(1, Math.floor(containerWidth / 520)))`
### Project Box Internal Layout
```
┌─ ProjectHeader (28px) ──────────────────┐
├─────────────────────┬───────────────────┤
│ ClaudeSession │ TeamAgentsPanel │
│ (flex: 1) │ (240px or overlay)│
├─────────────────────┴───────────────────┤
│ [Tab1] [Tab2] [+] TabBar 26px │
├─────────────────────────────────────────┤
│ Terminal content (xterm or scrollback) │
└─────────────────────────────────────────┘
```
Team panel: inline at >2560px, overlay at <2560px. Collapsed when no subagents.
### Responsive Breakpoints
| Width | Visible Projects | Team Panel |
|-------|-----------------|------------|
| 5120px+ | 5 | inline 240px |
| 3840px | 4 | inline 200px |
| 2560px | 3 | overlay |
| 1920px | 3 | overlay |
| <1600px | 1 + project tabs | overlay |
### xterm.js Budget: 4 Active Instances
| State | xterm? | Memory |
|-------|--------|--------|
| Active-Focused | Yes | ~20MB |
| Active-Background | Yes (if budget allows) | ~20MB |
| Suspended | No (HTML pre scrollback) | ~200KB |
| Uninitialized | No (placeholder) | 0 |
On focus: serialize least-recent xterm scrollback, destroy it, create new for focused tab, reconnect PTY.
### Project Accent Colors (Catppuccin)
| Slot | Color | Variable |
|------|-------|----------|
| 1 | Blue | --ctp-blue |
| 2 | Green | --ctp-green |
| 3 | Mauve | --ctp-mauve |
| 4 | Peach | --ctp-peach |
| 5 | Pink | --ctp-pink |
---
## Sidecar Strategy
**Single shared sidecar** (unchanged from v2). Per-project isolation via:
- `cwd` per query (already implemented)
- `claude_config_dir` per query (already implemented)
- `session_id` routing (already implemented)
No sidecar changes needed for v3.0.
---
## Keyboard Shortcuts
| Shortcut | Action | Layer |
|----------|--------|-------|
| Ctrl+K | Command palette | App |
| Ctrl+G | Switch group (palette filtered) | App |
| Ctrl+1..5 | Focus project by index | App |
| Alt+1..4 | Switch sidebar tab + open drawer | App |
| Ctrl+B | Toggle sidebar open/closed | App |
| Ctrl+, | Toggle settings panel | App |
| Escape | Close sidebar drawer | App |
| Ctrl+N | New terminal in focused project | Workspace |
| Ctrl+Shift+N | New agent query | Workspace |
| Ctrl+Tab | Next terminal tab | Project |
| Ctrl+W | Close terminal tab | Project |
| Ctrl+Shift+C/V | Copy/paste in terminal | Terminal |
---
## Implementation Phases
All 10 phases complete. Detailed checklists in [v3-progress.md](v3-progress.md).
| Phase | Scope | Status |
|-------|-------|--------|
| 1 | Data Model + Config (groups.rs, workspace store, SQLite migrations) | Complete |
| 2 | Project Box Shell (GlobalTabBar, ProjectGrid/Box/Header, App.svelte, sidebar redesign 2026-03-08) | Complete |
| 3 | Claude Session Integration (ClaudeSession.svelte wraps AgentPane) | Complete |
| 4 | Terminal Tabs (TerminalTabs.svelte, per-project tabbed terminals) | Complete |
| 5 | Team Agents Panel (TeamAgentsPanel, AgentCard) — **MVP boundary** | Complete |
| 6 | Session Continuity (persist/restore agent messages, sdkSessionId) | Complete |
| 7 | Command Palette + Group Switching (workspace teardown) | Complete |
| 8 | Docs Tab (DocsTab.svelte, markdown discovery) | Complete |
| 9 | Settings Tab (group/project CRUD, 5-project limit) | Complete |
| 10 | Polish + Cleanup (dead v2 components removed, StatusBar rewrite) | Complete |
---
## Decisions Log
| Decision | Rationale | Date |
|---|---|---|
| JSON for groups config, SQLite for session state | JSON is human-editable, shareable, version-controllable. SQLite for ephemeral runtime state. Load at startup only. | 2026-03-07 |
| Adaptive project count from viewport width | 5@5120px, 3@1920px, scroll-snap for overflow. min-width 480px. Better than forcing 5 at all sizes. | 2026-03-07 |
| Single shared sidecar (v3.0) | Existing multiplexed protocol handles concurrent sessions. Per-project pool deferred to v3.1 if crash isolation needed. Saves ~200MB RAM. | 2026-03-07 |
| xterm budget: 4 active, unlimited suspended | WebKit2GTK OOM at ~5 instances. Serialize scrollback to text buffer, destroy xterm, recreate on focus. PTY stays alive. | 2026-03-07 |
| Flexbox + scroll-snap over CSS Grid | Allows horizontal scroll on narrow screens. Scroll-snap gives clean project-to-project scrolling. | 2026-03-07 |
| Team panel: inline >2560px, overlay <2560px | Adapts to available space. Collapsed when no subagents running. | 2026-03-07 |
| VSCode-style left sidebar (replaces top tab bar + settings drawer) | Vertical icon rail (2.75rem, 4 SVG icons) + expandable drawer panel (28em, max 50%) + always-visible workspace. Settings is a regular tab, not special drawer. ProjectGrid always visible. Ctrl+B toggles sidebar. | 2026-03-08 |
| CSS relative units (rule 18) | Use rem/em for all layout CSS. Pixels only for icon sizes, borders, box shadows. Exception: --ui-font-size/--term-font-size store px for xterm.js API. | 2026-03-08 |
| Project accent colors from Catppuccin palette | Visual distinction: blue/green/mauve/peach/pink per slot 1-5. Applied to border + header tint. | 2026-03-07 |
| Remote machines deferred to v3.1 | Elevate to project level (project.remote_machine_id) but don't implement in MVP. | 2026-03-07 |
| Keyboard shortcut layers: App > Workspace > Terminal | Prevents conflicts. Terminal captures raw keys only when focused. App layer uses Ctrl+K/G. | 2026-03-07 |
| AgentPane splits into ClaudeSession + TeamAgentsPanel | Team agents shown inline in right panel, not as separate panes. Saves xterm/pane slots. | 2026-03-07 |
| Unmount/remount on group switch | Serialize xterm scrollbacks, destroy, remount new group. <100ms perceived. Frees ~80MB. | 2026-03-07 |
| All themes map to --ctp-* CSS vars | 17 themes in 3 groups: 4 Catppuccin + 7 Editor (VSCode Dark+, Atom One Dark, Monokai, Dracula, Nord, Solarized Dark, GitHub Dark) + 6 Deep Dark (Tokyo Night, Gruvbox Dark, Ayu Dark, Poimandres, Vesper, Midnight). All map to same 26 --ctp-* CSS custom properties — zero component changes needed. | 2026-03-07 |
| Typography via CSS custom properties | --ui-font-family/--ui-font-size + --term-font-family/--term-font-size in catppuccin.css :root. Restored by initTheme() on startup. Persisted as ui_font_family/ui_font_size/term_font_family/term_font_size SQLite settings. | 2026-03-07 |
| Tier 1 agents as ProjectBoxes via agentToProject() | Agents render as full ProjectBoxes (not separate UI). getAllWorkItems() merges agents+projects. Unified rendering = less code, same capabilities. | 2026-03-11 |
| extra_env 5-layer passthrough for BTMSG_AGENT_ID | TS → Rust AgentQueryOptions → NDJSON → JS runner → SDK env. Minimal surface — only agent projects get env injection. | 2026-03-11 |
| Periodic system prompt re-injection (1 hour) | LLM context degrades over long sessions. 1-hour timer re-sends role/tools reminder when agent is idle. autoPrompt/onautopromptconsumed callback pattern between AgentSession and AgentPane. | 2026-03-11 |
| btmsg/bttask shared SQLite DB | Both CLI tools share ~/.local/share/bterminal/btmsg.db. Single DB simplifies deployment, agents already have path. Read-only for non-Manager roles via CLI permissions. | 2026-03-11 |
| Role-specific tabs via conditional rendering | Manager=Tasks, Architect=Arch, Tester=Selenium+Tests. PERSISTED-LAZY pattern (mount on first activation). Conditional on isAgent && agentRole. | 2026-03-11 |
| PlantUML via plantuml.com server (~h hex encoding) | Avoids Java dependency. Hex encoding simpler than deflate+base64. Works with free tier. Trade-off: requires internet. | 2026-03-11 |
## Errors Encountered
| Error | Cause | Fix | Date |
|---|---|---|---|