agent-orchestrator/docs/architecture/data-model.md
Hibryda b6c1d4b6af docs: add 11 new documentation files across all categories
New reference docs:
- agents/ref-btmsg.md: inter-agent messaging schema and CLI
- agents/ref-bttask.md: kanban task board operations
- providers/ref-providers.md: Claude/Codex/Ollama/Aider comparison
- config/ref-settings.md: (already committed)

New guides:
- contributing/dual-repo-workflow.md: community vs commercial repos
- plugins/guide-developing.md: Web Worker sandbox API and publishing

New pro docs:
- pro/features/knowledge-base.md: persistent memory + symbol graph
- pro/features/git-integration.md: context injection + branch policy
- pro/marketplace/README.md: 13 plugins catalog

Split files:
- architecture/data-model.md: from architecture.md (schemas, layout)
- production/hardening.md: from production.md (supervisor, sandbox, WAL)
- production/features.md: from production.md (FTS5, plugins, secrets, audit)
2026-03-17 04:18:05 +01:00

251 lines
8 KiB
Markdown

# Data Model & Layout System
This document covers agor's data model (SQLite schemas, project group config), layout system, xterm budget management, and keyboard shortcuts.
---
## SQLite Databases
The backend manages two SQLite databases, both in WAL mode with 5-second busy timeout for concurrent access:
| Database | Location | Purpose |
|----------|----------|---------|
| `sessions.db` | `~/.local/share/agor/` | Sessions, layout, settings, agent state, metrics, anchors |
| `btmsg.db` | `~/.local/share/agor/` | Inter-agent messages, tasks, agents registry, audit log |
WAL checkpoints run every 5 minutes via a background tokio task to prevent unbounded WAL growth.
All queries use **named column access** (`row.get("column_name")`) — never positional indices. Rust structs use `#[serde(rename_all = "camelCase")]` so TypeScript interfaces receive camelCase field names on the wire.
---
## Project Group Config (`~/.config/agor/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": "agor",
"name": "Agents Orchestrator",
"identifier": "agor",
"description": "Terminal emulator with Claude integration",
"icon": "\uf120",
"cwd": "/home/user/code/Agents Orchestrator",
"profile": "default",
"enabled": true
}
]
}
],
"activeGroupId": "work-ai"
}
```
### TypeScript Types (`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.
---
## Adapters (IPC Bridge Layer)
Adapters wrap Tauri `invoke()` calls and `listen()` event subscriptions. They isolate the frontend from IPC details and provide typed TypeScript interfaces.
| Adapter | Backend Module | Purpose |
|---------|---------------|---------|
| `agent-bridge.ts` | sidecar + commands/agent | Agent query/stop/restart |
| `pty-bridge.ts` | pty + commands/pty | Terminal spawn/write/resize |
| `claude-messages.ts` | (frontend-only) | Parse Claude SDK NDJSON -> AgentMessage |
| `codex-messages.ts` | (frontend-only) | Parse Codex ThreadEvents -> AgentMessage |
| `ollama-messages.ts` | (frontend-only) | Parse Ollama chunks -> AgentMessage |
| `message-adapters.ts` | (frontend-only) | Provider registry for message parsers |
| `provider-bridge.ts` | commands/claude | Generic provider bridge (profiles, skills) |
| `btmsg-bridge.ts` | btmsg | Inter-agent messaging |
| `bttask-bridge.ts` | bttask | Task board operations |
| `groups-bridge.ts` | groups | Group config load/save |
| `session-bridge.ts` | session | Session/layout persistence |
| `settings-bridge.ts` | session/settings | Key-value settings |
| `files-bridge.ts` | commands/files | File browser operations |
| `search-bridge.ts` | search | FTS5 search |
| `secrets-bridge.ts` | secrets | System keyring |
| `anchors-bridge.ts` | session/anchors | Session anchor CRUD |
| `remote-bridge.ts` | remote | Remote machine management |
| `ssh-bridge.ts` | session/ssh | SSH session CRUD |
| `ctx-bridge.ts` | ctx | Context database queries |
| `memora-bridge.ts` | memora | Memora database queries |
| `fs-watcher-bridge.ts` | fs_watcher | Filesystem change events |
| `audit-bridge.ts` | btmsg (audit_log) | Audit log queries |
| `telemetry-bridge.ts` | telemetry | Frontend -> Rust tracing |
| `notifications-bridge.ts` | notifications | Desktop notification trigger |
| `plugins-bridge.ts` | plugins | Plugin discovery |
---
## 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.