Terminal-first AI coding assistant. Commands, daemon, agentic loop, 8 tool types, and full LMX routing — in one binary.
┌─────────────────────────────────────────────────────┐ │ CLI Entry Point · src/index.ts · Commander.js │ │ opta chat │ opta tui │ opta do │ opta account … │ └───────────────────────┬─────────────────────────────┘ │ command dispatch ┌───────────────────────▼─────────────────────────────┐ │ Agent Loop · src/core/agent.ts │ │ Streaming parser │ Permission gate │ Tool scheduler │ │ Context compactor │ Thinking blocks │ Turn stats │ └───────────────────────┬─────────────────────────────┘ │ tool dispatch ┌───────────────────────▼─────────────────────────────┐ │ Tool Executors · src/core/tools/ │ │ bash │ read_file │ write_file │ browser_open │ │ web_search │ vision │ mcp_call │ think │ └───────────────────────┬─────────────────────────────┘ │ HTTP v3 / WebSocket ┌───────────────────────▼─────────────────────────────┐ │ Daemon · 127.0.0.1:9999 · src/daemon/ │ │ Session store │ Event bus │ Vault sync │ LMX proxy │ │ Installer (launchd / systemd / schtasks) │ └───────────────────────┬─────────────────────────────┘ │ OpenAI-compatible API ┌───────────────────────▼─────────────────────────────┐ │ Opta LMX · 192.168.188.11:1234 │ │ MLX (Apple Silicon) │ GGUF fallback │ mDNS peer │ └─────────────────────────────────────────────────────┘
opta chat "ask a question"
opta tui # full TUI session
opta do "run a task autonomously"
opta account login
opta daemon start | stop | status
Ctrl+M open menu overlay
Ctrl+L clear screen
Ctrl+T thinking toggle
Tab autocomplete slash cmd
↑/↓ history navigation
opta config set lmx.url http://…:1234
opta models list
opta models use mlx-community/…
opta config set provider anthropic
opta doctor --fix
/help command palette
/clear reset conversation
/mode do agentic mode
/lmx LMX model picker
/export save session JSON
opta chat is the quickest way to talk to an LLM from the terminal. Pass a prompt inline for one-shot answers, pipe stdin for document context, or run it without arguments to open a readline-style interactive chat in-place.
# Inline one-shot opta chat "explain this error: segfault at 0x00" # Pipe context from a file cat package.json | opta chat "list all dev dependencies" # Specific model opta chat --model mlx-community/Mistral-7B-v0.3-4bit \ "summarize the release notes" # Output format opta chat --json "list 5 npm scripts from package.json" {"scripts":["build","test","lint","dev","typecheck"]}
opta chat uses the configured provider chain — LMX → Anthropic → OpenAI. Set OPTA_PROVIDER env var or opta config set provider to fix a target.
opta tui launches the interactive TUI powered by React + Ink. It connects to the running daemon, loads the latest session, and begins streaming. The UI adapts to terminal width with a collapsible sidebar for session history.
# Start with latest session opta tui # Start fresh session opta tui --new # Restore specific session opta tui --session sess_01J5X3… # With thinking enabled (extended reasoning) opta tui --thinking ┌─ Opta ─────────────────── Ctrl+M menu ─┐ │ > What can I help with today? │ │ │ │ [type here] │ └─────────────────────────────────────────┘
opta do sets mode: "do" on the daemon session, which auto-approves read-only tools (bash reads, file reads, web fetches) and requires explicit confirmation for destructive writes. Ideal for hands-off batch tasks.
# Run a task autonomously opta do "audit all TypeScript files for missing return types" # With specific working directory opta do --cwd ./src "add JSDoc to every exported function" # Dry run — show what would happen opta do --dry-run "update all package versions to latest" ◆ Planning... → read_file src/index.ts → bash: tsc --noEmit ✓ 12 files checked, 3 issues found → write_file src/types.ts [confirm?]
edit_file, write_file, and run_command with destructive patterns always pause for user confirmation, even in do-mode. Safe tools (reads, status checks) run immediately.
Authentication uses a browser-redirect PKCE flow. The CLI starts a local HTTP listener, opens the accounts portal in the browser, and captures the auth token when the portal redirects back. Tokens are stored in the OS keychain via the vault.
# Login (opens browser) opta account login ◆ Opening accounts.optalocal.com... Waiting for callback on :9998... ✓ Authenticated as [email protected] # View current account opta account status # Logout and clear tokens opta account logout # Pull API keys from vault opta account sync
opta account sync calls the daemon's vault.pull operation which fetches encrypted secrets from Supabase and writes them to the local keychain. API keys survive machine wipes.
The daemon streams events over GET /v3/sessions/:id/stream using Server-Sent Events. The CLI agent loop in src/core/agent-streaming.ts consumes these events, reconstructing the model's response turn in real time.
# Event envelope shape (TypeScript) interface StreamEnvelope { seq: number; // monotonic sequence event: 'turn.token' | 'turn.thinking' | 'tool.call' | 'tool.result' | 'turn.done' | 'turn.error' | 'session.cancelled'; payload: unknown; } # Reconnect with cursor GET /v3/sessions/:id/stream?afterSeq=142
lastReceivedSeq. On reconnect it passes ?afterSeq=N to skip already-processed events. This prevents duplicate tool executions after network drops.
Every tool call passes through src/core/agent-permissions.ts before execution. The gate evaluates the tool name and parameters against a layered policy: global defaults → session mode → user-approved list → per-call confirmation.
# Always auto-approved (read-only) read_file, list_dir, bash (safe patterns) web_search, vision, think # Requires confirmation in any mode write_file, edit_file run_command (destructive patterns: rm, drop, truncate) browser_exec (JS injection) # Session policy flags opta tui --approve-writes # auto-approve file writes opta tui --approve-all # fully autonomous
browser_open.
The agent loop tracks token usage reported by the daemon's turn.done event. When accumulated context crosses 70% of the configured limit, it triggers a compaction pass: a summarization call is made to the LLM, the summary replaces prior turns, and the conversation continues seamlessly.
# Compaction threshold (config) opta config set agent.compactionThreshold 0.70 # turn.done payload shows token usage { event: 'turn.done', payload: { inputTokens: 45231, outputTokens: 1204, contextUsed: 0.68, // 68% — near threshold elapsed: 4820 } } ◆ Context at 71% — compacting… ✓ Summary: 45k tokens → 3.2k tokens
When --thinking is active (or Ctrl+T in TUI), the agent loop enables extended thinking. The model emits interleaved turn.thinking and turn.token events. Thinking content is displayed in a dimmed panel but is NOT re-injected as assistant context in subsequent turns.
# Enable thinking opta chat --thinking "design the optimal DB schema" # Set thinking budget (tokens) opta config set thinking.budget 8000 # Event shape { event: 'turn.thinking', payload: { text: "Let me analyze…" } } { event: 'turn.token', payload: { text: "The optimal schema…" } } ┌─ thinking ─────────────────────────────┐ │ [considering constraints...] dim │ └────────────────────────────────────────┘ The optimal schema uses a polymorphic…
Six dedicated file system tools avoid shell injection risks: read_file, write_file, edit_file, list_dir, glob, grep. The bash tool runs arbitrary shell commands but passes output through a danger pattern scanner first.
# Tool schema (simplified) read_file { path: string, startLine?: number, endLine?: number } write_file { path: string, content: string } edit_file { path: string, old: string, new: string } glob { pattern: string, cwd?: string } grep { pattern: string, path?: string, flags?: string } bash { command: string, timeout?: number } # Danger patterns → require confirmation rm -rf, DROP TABLE, git push --force, truncate, dd if=, format, mkfs
Browser tools use a long-lived Playwright Chromium session managed by src/browser/live-host.ts. The session persists across tool calls within a turn, preserving cookies and navigation state. An MCP interceptor in src/browser/mcp-interceptor.ts bridges browser events to the tool result channel.
browser_open { url: string } browser_click { selector: string } browser_type { selector: string, text: string } browser_screenshot { fullPage?: boolean } → base64 PNG browser_eval { js: string } # ← requires confirm browser_network {} → request log # Example: scrape and summarize opta do "go to docs.python.org and summarize the asyncio page" → browser_open https://docs.python.org/asyncio → browser_screenshot → [model reads screenshot + DOM text] → "asyncio provides…"
src/browser/peekaboo.ts module surfaces a lightweight "peek" UI that shows browser state in the TUI sidebar so you can watch what the agent is doing in real time.
web_search fetches results from the configured search backend and returns structured snippets with URLs. vision accepts a base64 image or file path and queries the multimodal model — useful for reading screenshots, analyzing diagrams, or extracting data from PDFs.
web_search { query: string, maxResults?: number } → [{ title, url, snippet }, …] vision { image: string, prompt: string } # image: base64 | file path | URL → { description: string } # Config opta config set search.backend searxng opta config set search.url http://192.168.188.11:8080 # Use case: analyze a UI screenshot opta chat --attach screenshot.png \ "what UX issues do you see?"
search.backend=brave for cloud fallback when LAN is unavailable.
The CLI's MCP registry at src/mcp/registry.ts discovers configured MCP servers from ~/.config/opta/mcp.json, starts them as child processes, and exposes their tools through the same tool dispatch pipeline as built-in tools. The model sees all tools in one unified list.
# ~/.config/opta/mcp.json { "servers": { "github": { "command": "npx", "args": ["@modelcontextprotocol/server-github"], "env": { "GITHUB_TOKEN": "ghp_…" } } } } # Agent can now use GitHub tools opta do "create a PR for my current branch" → mcp__github__create_pull_request {…} ✓ PR #42 created
The daemon HTTP server exposes the v3 protocol contract defined in src/protocol/v3/. All request bodies and responses are validated against Zod schemas at runtime. The operation registry at src/daemon/operations/registry.ts maps operation names to handlers.
# Core endpoints POST /v3/sessions # create session GET /v3/sessions # list sessions GET /v3/sessions/:id # session detail POST /v3/sessions/:id/turns # submit user turn GET /v3/sessions/:id/stream # SSE event stream POST /v3/sessions/:id/cancel # cancel active turn POST /v3/operations # daemon operations # Auth: all requests need Bearer token Authorization: Bearer opta_tok_… # Operation examples POST /v3/operations { op: "vault.pull" } POST /v3/operations { op: "models.list" }
crypto.timingSafeEqual to prevent timing-based token enumeration attacks on the local socket.
The daemon upgrades GET /v3/sessions/:id/ws to a WebSocket. Desktop clients (Opta Code Desktop) use this instead of SSE for lower latency and bidirectional communication. The auth token is passed as ?token=T since browser WebSocket doesn't support custom headers.
# WebSocket connection (desktop client) ws://127.0.0.1:9999/v3/sessions/sess_01/ws?token=opta_tok_… # Same envelope format as SSE { seq: 45, event: 'turn.token', payload: { text: "Hello" } } # Reconnect pattern (client pseudocode) let delay = 500; while (shouldRun) { ws = connect(`?afterSeq=${lastSeq}`); ws.onClose = () => { await sleep(delay); delay = min(delay*2, 30000); } }
Sessions are stored as append-only NDJSON log files at ~/.config/opta/daemon/sessions/. Each session directory contains meta.json (session metadata) and events.ndjson (the event stream). The session store in src/daemon/session-store.ts handles concurrent writes with race-safe mkdir.
# Session directory layout ~/.config/opta/daemon/sessions/ sess_01J5X3.../ meta.json # id, title, createdAt, model events.ndjson # one JSON envelope per line # meta.json { "id":"sess_01J5…", "title":"Refactor types", "createdAt":"2026-03-06T…", "model":"claude-sonnet-4-6" } # events.ndjson (append-only) {"seq":0,"event":"turn.token","payload":{"text":"Sure…"}} {"seq":1,"event":"turn.token","payload":{"text":", let"}} {"seq":2,"event":"turn.done","payload":{…}}
SESSION_ID_RE pattern before being used as directory names, preventing path traversal attacks.
Slash commands are registered in src/commands/slash/ and surfaced by the TUI input handler. Typing / triggers the autocomplete overlay. Commands execute in the same turn context — they can reference conversation history and trigger daemon operations.
# Session control /clear clear conversation history /new start new session /export save session as JSON /title My task rename current session # Model & routing /model open model picker overlay /lmx switch to LMX local inference /cloud switch to Anthropic API # LMX operations /lmx status show LMX health + loaded model /lmx load … load a model on LMX /lmx unload unload current model # Utility /help list all slash commands /mode do switch to agentic mode
~/.config/opta/skills.json. Each skill maps a slash prefix to a prompt template injected at the start of the turn.
The provider manager at src/providers/manager.ts implements a prioritized chain: first checks LMX reachability (cached 10s), falls back to Anthropic, then OpenAI. All providers normalize to the same OpenAI-compatible streaming interface via adapters in src/providers/.
# Provider chain priority 1. LMX (local inference, 192.168.188.11:1234) 2. Anthropic claude-sonnet-4-6 3. OpenAI gpt-4o # LMX preflight: cached 10s GET http://192.168.188.11:1234/healthz → { "status": "ok", "model": "mlx-community/…" } # mDNS auto-discovery (no IP needed) opta config set lmx.discovery mdns ◆ Discovered LMX at 192.168.188.11:1234 (_opta-lmx._tcp) # Override provider for session OPTA_PROVIDER=anthropic opta chat "hello"
src/daemon/mdns-discovery.ts which listens for _opta-lmx._tcp.local advertisements from Mono512. No manual IP configuration needed on the same network.
The vault system at src/accounts/vault.ts encrypts secrets client-side before storing in Supabase. The daemon operation vault.pull fetches the encrypted blob, decrypts with the device key derived from the Supabase session, and writes individual secrets to the OS keychain.
# Pull vault (after login) opta account sync ◆ Pulling vault from accounts.optalocal.com… ✓ ANTHROPIC_API_KEY synced ✓ OPENAI_API_KEY synced ✓ LMX_TOKEN synced → 3 keys written to keychain # Daemon operation (v3) POST /v3/operations { "op": "vault.pull" } # Response { "ok": true, "syncedKeys": ["ANTHROPIC_API_KEY", "OPENAI_API_KEY"], "failedKeys": [] }