PTY Log - Activity Logging System
MonoTerm includes a powerful activity logging system that tracks AI agent operations in real-time using Alacritty’s VTE parser.Copy
┌─────────────────────────────────────────────────────────────────┐
│ PTY LOG ARCHITECTURE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ PTY Output │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ VTE Parser │ Alacritty headless terminal │
│ │ (Rust) │ Processes ANSI escape sequences │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Gate Filter │ AI provider detection │
│ │ │ Claude, Codex, Gemini │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Block Detect │ Recognizes operations │
│ │ │ Read, Write, Edit, Bash │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ SQLite DB │ Activity records │
│ │ (WAL mode) │ Real-time events │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Gate Filter System
The system detects AI provider markers to filter and categorize activities.Copy
┌─────────────────────────────────────────────────────────────────┐
│ AI PROVIDER DETECTION │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Terminal Output Line │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Marker Detection │ │
│ │ │ │
│ │ Symbol AI Provider │ │
│ │ ────── ─────────── │ │
│ │ ⏺ Claude │ │
│ │ • Codex │ │
│ │ ✦ Gemini │ │
│ │ │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ Benefits: │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Filter activities by AI provider │ │
│ │ Track provider-specific patterns │ │
│ │ Extensible with custom markers │ │
│ └────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Damage-Based Change Detection
Efficient change detection using Alacritty’s damage API.Copy
┌─────────────────────────────────────────────────────────────────┐
│ SMART CHANGE DETECTION │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Traditional Approach │
│ ───────────────────── │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Check EVERY line for changes │ │
│ │ Even when cursor just blinks │ │
│ │ │ │
│ │ CPU: Always busy │ │
│ │ DB: Unnecessary writes │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ VS │
│ │
│ Damage-Based Approach (MonoTerm) │
│ ──────────────────────────────── │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Alacritty tells us which lines changed │ │
│ │ Only check damaged lines │ │
│ │ │ │
│ │ CPU: Minimal work │ │
│ │ DB: Only meaningful writes │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ Result: │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Progress bars No database writes │ │
│ │ Cursor movement No database writes │ │
│ │ Actual content Captured and stored │ │
│ └────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Block Detection
AI output is organized into logical blocks for meaningful tracking.Copy
┌─────────────────────────────────────────────────────────────────┐
│ BLOCK DETECTION STATE MACHINE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Claude Output Example: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ⏺ Read(/project/src/main.rs) │ │
│ │ 1. fn main() { │ │
│ │ 2. println!("Hello"); │ │
│ │ 3. } │ │
│ │ │ │
│ │ ⏺ Edit(/project/src/lib.rs) │ │
│ │ Updated function signature │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Detection Flow: │
│ │
│ ┌──────────────┐ │
│ │ IDLE STATE │ │
│ └──────┬───────┘ │
│ │ │
│ ▼ Line starts with ⏺/•/✦ │
│ ┌──────────────┐ │
│ │ BLOCK START │ │
│ └──────┬───────┘ │
│ │ │
│ ▼ Indented lines │
│ ┌──────────────┐ │
│ │BLOCK CONTENT │──────────┐ │
│ └──────┬───────┘ │ More indented │
│ │ │ │
│ ▼ New marker └─────────────────────────┘ │
│ ┌──────────────┐ │
│ │ BLOCK END │ Save to database │
│ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
DBWriter Architecture
Database writes are handled on a dedicated thread to prevent terminal lag.Copy
┌─────────────────────────────────────────────────────────────────┐
│ NON-BLOCKING DATABASE ARCHITECTURE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ The Problem: │
│ ┌────────────────────────────────────────────────────┐ │
│ │ SQLite writes block for 50-200ms │ │
│ │ During this time: │ │
│ │ Terminal input delayed │ │
│ │ PTY data queues up │ │
│ │ User feels lag │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ The Solution: │
│ ┌────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ VTE Parsing DBWriter │ │
│ │ (Tokio task) (std::thread) │ │
│ │ │ │ │ │
│ │ │ MPSC Channel │ │ │
│ │ │──────────────────▶│ │ │
│ │ │ (instant send) │ │ │
│ │ ▼ ▼ │ │
│ │ Continue SQLite │ │
│ │ processing (blocks only this thread) │ │
│ │ │ │ │ │
│ │ │ ▼ │ │
│ │ No lag Tauri Event │ │
│ │ "activity-added" │ │
│ │ │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ Result: Terminal stays responsive while logging │
│ │
└─────────────────────────────────────────────────────────────────┘
CJK Character Support
Proper handling of wide characters (Korean, Chinese, Japanese).Copy
┌─────────────────────────────────────────────────────────────────┐
│ WIDE CHARACTER HANDLING │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Alacritty Grid for "Hello": │
│ ┌───────┬───────┬───────┬───────┬───────┐ │
│ │ 'H' │ 'e' │ 'l' │ 'l' │ 'o' │ │
│ │ 1 cell│ 1 cell│ 1 cell│ 1 cell│ 1 cell│ │
│ └───────┴───────┴───────┴───────┴───────┘ │
│ │
│ Alacritty Grid for CJK characters: │
│ ┌───────────────┬───────────────┐ │
│ │ 'char' │ spacer │ │
│ │ 2 cells │ (skip!) │ │
│ └───────────────┴───────────────┘ │
│ │
│ Without proper handling: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Output: "word word " Extra spaces! │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ With MonoTerm handling: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Output: "word word" Correct! │ │
│ │ Spacers detected and skipped │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Real-Time Events
Activities are emitted to the frontend as they are detected.Copy
┌─────────────────────────────────────────────────────────────────┐
│ REAL-TIME EVENT FLOW │
├─────────────────────────────────────────────────────────────────┤
│ │
│ DBWriter Thread │
│ │ │
│ ▼ INSERT successful │
│ ┌─────────────────┐ │
│ │ Create Event │ │
│ │ - operation │ │
│ │ - target │ │
│ │ - timestamp │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ Tauri IPC │
│ ┌─────────────────┐ │
│ │ Frontend │ │
│ │ Listener │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Activity List │ Real-time UI update │
│ │ Updated │ │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Summary
Copy
┌─────────────────────────────────────────────────────────────────┐
│ PTY LOG IN ONE PICTURE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Terminal Output │
│ │ │
│ ▼ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │Alacritty│───▶│ Gate │───▶│ Block │───▶│ MPSC │ │
│ │ VTE │ │ Filter │ │ Detect │ │ Channel │ │
│ └─────────┘ └─────────┘ └─────────┘ └────┬────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ DBWriter Thread │ │
│ │ │ │
│ │ SQLite (WAL) ────▶ Tauri Event │ │
│ │ INSERT "activity-added" │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ Key Technologies: │
│ - Rust: Memory-safe VTE parsing │
│ - Alacritty: Battle-tested terminal library │
│ - Tokio + std::thread: Non-blocking architecture │
│ - SQLite WAL: Concurrent read/write │
│ - Tauri: Real-time frontend events │
│ │
└─────────────────────────────────────────────────────────────────┘