opta cli · masterclass

Opta CLI

Terminal-first AI coding assistant. Commands, daemon, agentic loop, 8 tool types, and full LMX routing — in one binary.

18 Features
8 Tool Types
2300+ Tests
v3 Protocol
Architecture Stack
  ┌─────────────────────────────────────────────────────┐
  │  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    │
  └─────────────────────────────────────────────────────┘
Quick Reference

Core Commands

opta chat "ask a question" opta tui # full TUI session opta do "run a task autonomously" opta account login opta daemon start | stop | status

TUI Shortcuts

Ctrl+M open menu overlay Ctrl+L clear screen Ctrl+T thinking toggle Tab autocomplete slash cmd ↑/↓ history navigation

Config & Models

opta config set lmx.url http://…:1234 opta models list opta models use mlx-community/… opta config set provider anthropic opta doctor --fix

Slash Commands

/help command palette /clear reset conversation /mode do agentic mode /lmx LMX model picker /export save session JSON
Commands
opta chat
One-shot and interactive inline chat without launching the full TUI. Fast, piped, or interactive — all in your current terminal.

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"]}
Provider fallback: opta chat uses the configured provider chain — LMX → Anthropic → OpenAI. Set OPTA_PROVIDER env var or opta config set provider to fix a target.
Commands
opta tui
Full Ink-powered terminal UI with persistent session, live streaming, overlays, model picker, and slash command palette.

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]                            │
└─────────────────────────────────────────┘
Ctrl+M opens the overlay stack: model picker, settings, manage slash commands. Press Esc to dismiss layers one at a time.
Commands
opta do
Autonomous agentic mode. Runs multi-turn tool loops with auto-approval for safe operations until the task is complete or a dangerous tool requires confirmation.

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?]
Permission gate: 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.
Commands
opta account
Supabase-backed authentication with browser OAuth flow, CLI token exchange, and vault key pull for cross-device secret sync.

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
Vault pull: After login, 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.
Agent Loop
Streaming Events
SSE-based event bus from daemon to CLI. Every token, tool call, tool result, and turn boundary arrives as a typed envelope. No polling — pure push.

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
Cursor resume: The CLI tracks lastReceivedSeq. On reconnect it passes ?afterSeq=N to skip already-processed events. This prevents duplicate tool executions after network drops.
Agent Loop
Permission Gate
Fine-grained tool authorization with per-tool policies, session mode flags, and interactive confirmation prompts for destructive operations.

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 session isolation: Browser tools operate in a sandboxed Playwright context. The permission gate additionally validates URL patterns against a domain allowlist before granting browser_open.
Agent Loop
Context Compaction
Automatic rolling summary when the conversation approaches 70% of the model's context window. Preserves key facts while shedding verbatim history.

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
Lossless facts: The compactor prompt instructs the LLM to preserve all file paths, function signatures, error messages, and explicit user decisions before summarizing conversational flow.
Agent Loop
Thinking Blocks
Extended reasoning via Claude's thinking feature. Thinking tokens stream separately and are displayed in collapsible TUI panels — never sent back as context.

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…
Streaming efficiency: Thinking events are NOT persisted to the session event log (the daemon skips them) to avoid polluting history. Only the final assistant text is stored.
Tools
Bash & File System Tools
Safe shell execution with pattern-based danger detection, plus direct file read/write/edit/glob/grep tools that bypass shell entirely for precision edits.

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
Parallel dispatch: The agent loop runs up to 8 tool calls in parallel by default (configurable to 16). File reads and greps are batched automatically when the model returns multiple tool calls in one response.
Tools
Browser Automation
Playwright-backed browser tools for clicking, form-filling, screenshot capture, JS evaluation, and network inspection — all from within the agent loop.

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…"
Peekaboo: The 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.
Tools
Web Search & Vision
Web search via configurable backends (SearXNG, DuckDuckGo, Brave), plus vision analysis of screenshots, images, and PDF pages using the Claude Vision API.

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?"
Local-first search: The default backend is SearXNG on Mono512, keeping searches private. Configure search.backend=brave for cloud fallback when LAN is unavailable.
Tools
MCP Bridge
Model Context Protocol integration. Registers external MCP servers as first-class tools in the agent loop — GitHub, Slack, Linear, Figma, and any custom MCP server.

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
Sandboxed start: MCP servers start as child processes owned by the CLI process. When the CLI exits, all MCP server children are reaped automatically. No dangling processes.
Daemon & Protocol
HTTP v3 REST
Typed REST API at 127.0.0.1:9999 (default). Zod-validated request/response schemas, Bearer token auth, and a full operation registry for daemon-managed resources.

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" }
Timing-safe auth: Token comparison uses crypto.timingSafeEqual to prevent timing-based token enumeration attacks on the local socket.
Daemon & Protocol
WebSocket Streaming
Bidirectional WebSocket channel for real-time event delivery to desktop clients. Token auth via query param, exponential backoff reconnect, cursor-based dedup.

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); }
}
SSE vs WS: CLI uses SSE (simpler, no upgrade handshake). Desktop uses WS for bidirectional cancellation signals. Both share the same event envelope schema.
Daemon & Protocol
Session Store
NDJSON-based persistent session storage on disk. Events append in order, replay on reconnect, and support cursor-based reads for efficient catch-up after disconnects.

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":{…}}
Path safety: Session IDs are validated against a strict SESSION_ID_RE pattern before being used as directory names, preventing path traversal attacks.
Power Features
Slash Commands
In-TUI command palette with Tab completion. Built-in commands for session control, model switching, LMX management, and extensible user-defined skill shortcuts.

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
Skill shortcuts: Custom slash commands can be added by registering skill entries in ~/.config/opta/skills.json. Each skill maps a slash prefix to a prompt template injected at the start of the turn.
Power Features
LMX Routing
Intelligent provider routing: LMX local inference (MLX / GGUF) → Anthropic cloud → OpenAI. Automatic mDNS discovery of LMX nodes on LAN, no manual IP config needed.

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"
Zero-config LAN: mDNS discovery uses src/daemon/mdns-discovery.ts which listens for _opta-lmx._tcp.local advertisements from Mono512. No manual IP configuration needed on the same network.
Power Features
Vault Sync
Encrypted API key sync between devices via Supabase. Pull secrets after login — Anthropic keys, LMX tokens, and provider credentials survive machine wipes.

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": []
}
Client-side encryption: Secrets are encrypted with AES-256-GCM using a key derived from your Supabase user ID + device fingerprint before leaving the device. The Supabase database never sees plaintext keys.