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)
This commit is contained in:
parent
8251321dac
commit
b6c1d4b6af
11 changed files with 2198 additions and 0 deletions
207
docs/production/features.md
Normal file
207
docs/production/features.md
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
# Production Features
|
||||
|
||||
User-facing production features: search, plugins, secrets, notifications, audit logging, error classification, and session metrics.
|
||||
|
||||
---
|
||||
|
||||
## FTS5 Full-Text Search
|
||||
|
||||
The search system uses SQLite's FTS5 extension for full-text search across three data types. Accessed via a Spotlight-style overlay (Ctrl+Shift+F).
|
||||
|
||||
### Architecture
|
||||
|
||||
```
|
||||
SearchOverlay.svelte (Ctrl+Shift+F)
|
||||
|
|
||||
+-- search-bridge.ts -> Tauri commands
|
||||
|
|
||||
+-- search.rs -> SearchDb (separate FTS5 tables)
|
||||
|
|
||||
+-- search_messages -- agent session messages
|
||||
+-- search_tasks -- bttask task content
|
||||
+-- search_btmsg -- btmsg inter-agent messages
|
||||
```
|
||||
|
||||
### Virtual Tables
|
||||
|
||||
| Table | Source | Indexed Columns |
|
||||
|-------|--------|----------------|
|
||||
| `search_messages` | Agent session messages | content, session_id, project_id |
|
||||
| `search_tasks` | bttask tasks | title, description, assignee, status |
|
||||
| `search_btmsg` | btmsg messages | content, sender, recipient, channel |
|
||||
|
||||
### Operations
|
||||
|
||||
| Tauri Command | Purpose |
|
||||
|---------------|---------|
|
||||
| `search_init` | Creates FTS5 virtual tables if not exist |
|
||||
| `search_all` | Queries all 3 tables, returns ranked results |
|
||||
| `search_rebuild` | Drops and rebuilds all indices (maintenance) |
|
||||
| `search_index_message` | Indexes a single new message (real-time) |
|
||||
|
||||
### Frontend (SearchOverlay.svelte)
|
||||
|
||||
- Triggered by Ctrl+Shift+F
|
||||
- Spotlight-style floating overlay centered on screen
|
||||
- 300ms debounce on input to avoid excessive queries
|
||||
- Results grouped by type (Messages, Tasks, Communications)
|
||||
- Click result to navigate to source (focus project, switch tab)
|
||||
|
||||
---
|
||||
|
||||
## Plugin System
|
||||
|
||||
The plugin system allows extending agor with custom commands and event handlers. Plugins are sandboxed JavaScript executing in a restricted environment.
|
||||
|
||||
### Plugin Discovery
|
||||
|
||||
Plugins live in `~/.config/agor/plugins/`. Each plugin is a directory containing a `plugin.json` manifest:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "my-plugin",
|
||||
"version": "1.0.0",
|
||||
"description": "A custom plugin",
|
||||
"main": "index.js",
|
||||
"permissions": ["notifications", "settings"]
|
||||
}
|
||||
```
|
||||
|
||||
The Rust `plugins.rs` module scans for `plugin.json` files with path-traversal protection (rejects `..` in paths).
|
||||
|
||||
### Sandboxed Runtime (plugin-host.ts)
|
||||
|
||||
Plugins execute via `new Function()` in a restricted scope:
|
||||
|
||||
**Shadowed globals (13):**
|
||||
`fetch`, `XMLHttpRequest`, `WebSocket`, `Worker`, `eval`, `Function`, `importScripts`, `require`, `process`, `globalThis`, `window`, `document`, `localStorage`
|
||||
|
||||
**Provided API (permission-gated):**
|
||||
|
||||
| API | Permission | Purpose |
|
||||
|-----|-----------|---------|
|
||||
| `bt.notify(msg)` | `notifications` | Show toast notification |
|
||||
| `bt.getSetting(key)` | `settings` | Read app setting |
|
||||
| `bt.setSetting(key, val)` | `settings` | Write app setting |
|
||||
| `bt.registerCommand(name, fn)` | (always allowed) | Add command to palette |
|
||||
| `bt.on(event, fn)` | (always allowed) | Subscribe to app events |
|
||||
|
||||
The API object is frozen (`Object.freeze`) to prevent tampering. Strict mode is enforced.
|
||||
|
||||
### Security Notes
|
||||
|
||||
The `new Function()` sandbox is best-effort — it is not a security boundary. A determined attacker could escape it. Landlock provides the actual filesystem restriction. The plugin sandbox primarily prevents accidental damage from buggy plugins.
|
||||
|
||||
35 tests cover the plugin system including permission validation, sandbox escape attempts, and lifecycle management.
|
||||
|
||||
---
|
||||
|
||||
## Secrets Management
|
||||
|
||||
Secrets (API keys, tokens) are stored in the system keyring rather than in plaintext files or SQLite.
|
||||
|
||||
### Backend (`secrets.rs`)
|
||||
|
||||
Uses the `keyring` crate with the `linux-native` feature (libsecret/DBUS):
|
||||
|
||||
```rust
|
||||
pub struct SecretsManager;
|
||||
|
||||
impl SecretsManager {
|
||||
pub fn store(key: &str, value: &str) -> Result<()>;
|
||||
pub fn get(key: &str) -> Result<Option<String>>;
|
||||
pub fn delete(key: &str) -> Result<()>;
|
||||
pub fn list() -> Result<Vec<SecretMetadata>>;
|
||||
pub fn has_keyring() -> bool;
|
||||
}
|
||||
```
|
||||
|
||||
Metadata (key names, last modified timestamps) is stored in SQLite settings. The actual secret values never touch disk — they live only in the system keyring (gnome-keyring, KWallet, or equivalent).
|
||||
|
||||
### No Fallback
|
||||
|
||||
If no keyring daemon is available (no DBUS session, no gnome-keyring), secret operations fail with a clear error message. There is no plaintext fallback — this is intentional to prevent accidental credential leakage.
|
||||
|
||||
---
|
||||
|
||||
## Notifications
|
||||
|
||||
Agor has two notification systems: in-app toasts and OS-level desktop notifications.
|
||||
|
||||
### In-App Toasts (`notifications.svelte.ts`)
|
||||
|
||||
- 6 notification types: `success`, `error`, `warning`, `info`, `agent_complete`, `agent_error`
|
||||
- Maximum 5 visible toasts, 4-second auto-dismiss
|
||||
- Toast history (up to 100 entries) with unread badge in NotificationCenter
|
||||
- Agent dispatcher emits toasts on: agent completion, agent error, sidecar crash
|
||||
|
||||
### Desktop Notifications (`notifications.rs`)
|
||||
|
||||
Uses `notify-rust` crate for native Linux notifications. Graceful fallback if notification daemon is unavailable (e.g., no D-Bus session).
|
||||
|
||||
### Notification Center (`NotificationCenter.svelte`)
|
||||
|
||||
Bell icon in the top-right with unread badge. Dropdown panel shows notification history with timestamps, type icons, and clear/mark-read actions.
|
||||
|
||||
---
|
||||
|
||||
## Audit Logging
|
||||
|
||||
All significant events are logged to the `audit_log` table:
|
||||
|
||||
| Event Type | Logged When |
|
||||
|-----------|-------------|
|
||||
| `message_sent` | Agent sends a btmsg message |
|
||||
| `message_read` | Agent reads messages |
|
||||
| `channel_created` | New btmsg channel created |
|
||||
| `agent_registered` | Agent registers with btmsg |
|
||||
| `heartbeat` | Agent sends heartbeat |
|
||||
| `task_created` | New bttask task |
|
||||
| `task_status_changed` | Task status update |
|
||||
| `wake_event` | Wake scheduler triggers |
|
||||
| `prompt_injection_detected` | Suspicious content in agent messages |
|
||||
|
||||
The AuditLogTab component displays audit entries with filtering by event type and agent, with 5-second auto-refresh and max 200 entries.
|
||||
|
||||
---
|
||||
|
||||
## Error Classification
|
||||
|
||||
The error classifier (`utils/error-classifier.ts`) categorizes API errors into 6 types with appropriate retry behavior:
|
||||
|
||||
| Type | Examples | Retry? | User Message |
|
||||
|------|----------|--------|--------------|
|
||||
| `rate_limit` | HTTP 429, "rate limit exceeded" | Yes (with backoff) | "Rate limited -- retrying in Xs" |
|
||||
| `auth` | HTTP 401/403, "invalid API key" | No | "Authentication failed -- check API key" |
|
||||
| `quota` | "quota exceeded", "billing" | No | "Usage quota exceeded" |
|
||||
| `overloaded` | HTTP 529, "overloaded" | Yes (longer backoff) | "Service overloaded -- retrying" |
|
||||
| `network` | ECONNREFUSED, timeout, DNS failure | Yes | "Network error -- check connection" |
|
||||
| `unknown` | Anything else | No | "Unexpected error" |
|
||||
|
||||
20 unit tests cover classification accuracy across various error message formats.
|
||||
|
||||
---
|
||||
|
||||
## Session Metrics
|
||||
|
||||
Per-project historical session data is stored in the `session_metrics` table:
|
||||
|
||||
| Column | Type | Purpose |
|
||||
|--------|------|---------|
|
||||
| `project_id` | TEXT | Which project |
|
||||
| `session_id` | TEXT | Agent session ID |
|
||||
| `start_time` | INTEGER | Session start timestamp |
|
||||
| `end_time` | INTEGER | Session end timestamp |
|
||||
| `peak_tokens` | INTEGER | Maximum context tokens used |
|
||||
| `turn_count` | INTEGER | Total conversation turns |
|
||||
| `tool_call_count` | INTEGER | Total tool calls made |
|
||||
| `cost_usd` | REAL | Total cost in USD |
|
||||
| `model` | TEXT | Model used |
|
||||
| `status` | TEXT | Final status (success/error/stopped) |
|
||||
| `error_message` | TEXT | Error details if failed |
|
||||
|
||||
100-row retention per project (oldest pruned on insert). Metrics are persisted on agent completion via the agent dispatcher.
|
||||
|
||||
The MetricsPanel component displays this data as:
|
||||
- **Live view** — fleet aggregates, project health grid, task board summary, attention queue
|
||||
- **History view** — SVG sparklines for cost/tokens/turns/tools/duration, stats row, session table
|
||||
Loading…
Add table
Add a link
Reference in a new issue