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)
251 lines
8 KiB
Markdown
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.
|