AI Terminal
The AI Terminal — surfaced in-app as the Command Center — is a keyboard-first console for driving Olyron CRM. Type a short command like `leads`, `forecast`, or `view deal Acme Renewal` and it runs a scoped query against your workspace and paints an animated result panel — no clicking through menus. Commands that aren't recognized as built-ins are handed off for natural-language AI processing.
#What the Terminal is
The Terminal is a browser-based command line rendered with xterm.js. It pairs a large registry of built-in commands (which run deterministic, tenant-scoped Supabase queries) with an AI fallback for anything you phrase in plain English. Every command runs against your own workspace only — the server derives your tenant_id from your authenticated session, so you can never query another tenant's data.
- Instant analytics —
leads,deals,tasks,members,forecast,statusrender live stat panels. - Navigation —
go pipeline,home, orview lead John Smithjump you straight to a record or view. - Revenue & ledger —
invoices,quotes,revenue,ledger statuspull financial intelligence. - Voice control — say a wake word ("computer", "acc") and speak a command instead of typing.
- Natural language — anything not matched as a built-in is passed to the AI assistant.
/dashboard/terminal. It is a client-only component (xterm.js can't render on the server), so it loads with ssr: false.#Opening and driving the console
- 1Open the Command CenterNavigate to
/dashboard/terminal, or from anywhere in the app typego terminal. The keyboard shortcut ⌘J is reserved for opening the Terminal. - 2Type a commandStart with
helpto see every command grouped by area (Starship, Analytics, Navigation, Quick Actions, Search, Communications, Revenue, Accounts, Landing Pages, System, AI Mode). - 3Use autocomplete and historyPress Tab to complete a partial command; a single match completes inline, multiple matches list as suggestions. Use ↑ / ↓ to scroll through your command history.
- 4Read the result panelSuccessful commands print a short confirmation line and open an animated overlay panel. Press ESC to close the panel, or minimize it to a dock at the bottom of the screen.
| Key | Action |
|---|---|
| Tab | Autocomplete the current command |
| ↑ / ↓ | Cycle through command history |
| Ctrl+L | Clear the screen |
| Ctrl+C | Cancel the current input line |
| ESC | Close the active result panel |
| ⌘J | Open the Terminal |
Voice commands
The Command Center header includes a voice interface built on the browser's Web Speech API. Say a wake word — the defaults are "computer", "acc", and "hey acc" — then speak a request such as "show me today's leads". The transcript is parsed into a terminal command and executed, and (when enabled) the assistant speaks a short acknowledgement back. Voice requires a secure context (HTTPS or localhost) and a browser with speech recognition support.
#How a command is resolved
When you press Enter, the raw text is sent to POST /api/terminal/execute, which calls executeCommand() in the command registry. Resolution follows a fixed order — the first matching stage wins:
- Exact match — the first word matches a built-in command name or one of its aliases (e.g.
deals, or its aliaspipeline). - Prefix match — if the first word is at least 3 characters, it matches a command whose name or alias starts with it (so
foreresolves toforecast). - Revenue commands — invoices, quotes, payments, and revenue reports are checked next.
- Ledger commands — financial-intelligence commands like
ledger statusare checked after revenue. - Status heuristics — free text containing "ready", "status", or "how are we" runs the
statuscommand. - AI fallback — anything still unmatched returns
passToAI: true, marking it for natural-language handling.
tasks also answers to t, todo, and task-stats; /search also answers to find and /s; deals also answers to d and pipeline. Use help to discover them.#Command reference
Built-in commands are read-first: they query your workspace and render a panel rather than silently mutating data. Below are the most-used commands grouped by area.
| Command | What it does | Panel |
|---|---|---|
| help | List every command grouped by category | help |
| leads | Lead totals, status/source breakdown, 14-day sparkline | leads |
| tasks | Pending, overdue, due-today counts and completion rate | tasks |
| deals | Pipeline value (total + weighted) and top deals | deals |
| forecast | Weighted forecast for this month / next month / quarter | forecast |
| members | Active members and upcoming renewals | members |
| status | System health plus lead/task/deal/member counts | status |
| today | Today's tasks, overdue items, and new leads | orbit |
| hot | High-probability deals (probability >= 50) | intel |
| at-risk | Deals not updated in 7+ days | intel |
| /search <term> | Search leads, contacts, and deals at once | search |
| view <module> <name> | Open a lead, contact, deal, or task by name or ID (also show) | navigation |
| go <page> | Navigate to any page (pipeline, analytics, settings...) | navigation |
| accounts / vendors / products | List company accounts, vendors, or the product catalog | accounts / vendors / products |
| cadences / blueprints / approvals | Automation sequences, stage-gating rules, approval queue | cadences / blueprints / approvals |
| invoices / quotes / revenue | Recent invoices, quotes, and revenue reports | report |
| ledger status | Financial-intelligence overview | intel |
❯ deals
Pipeline: $2.4M total, $1.1M weighted
❯ view deal Acme Renewal
Opening Acme Renewal...
❯ stage Acme Renewal to Proposal
Ready to move "Acme Renewal" to Proposal
❯ forecast
Weighted forecast: $1.1Mstage <deal> to <stage> doesn't move the deal outright — it returns a panel with a stage_transition action that opens the deal and its stage-transition modal so you can confirm. Navigation commands return an href for the client to follow.#Natural language and the AI assistant
When no built-in matches, executeCommand returns passToAI: true. Conversational AI itself is served by a dedicated streaming endpoint, POST /api/ai/assistant, which the in-app AI Assistant panel uses. It is powered by Anthropic's Claude (model claude-sonnet-4-20250514) via the @anthropic-ai/sdk package and streams tokens back as Server-Sent Events.
The assistant is primed with an Olyron CRM system prompt so it answers in the product's terms — leads, contacts, deals, accounts, pipeline stages, blueprints, cadences, and landing pages. If you pass a context_type and context_id (contact, deal, or lead), the server injects a short snippet about that record into the prompt so replies are grounded in the record you're looking at. Conversations are persisted to the crm_ai_threads table so a thread can be continued via its thread_id.
curl -N -X POST https://app.olyron.com/api/ai/assistant \
-H "Content-Type: application/json" \
-d '{
"message": "Draft a renewal follow-up for the Acme deal",
"context_type": "deal",
"context_id": "3f9a...c2e1"
}'
# Response is text/event-stream:
# data: {"text":"Here's a draft"}
# data: {"text":" follow-up..."}
# data: {"done":true,"thread_id":"9b2e...44af"}| Provider | Package | Env var | Used by |
|---|---|---|---|
| Anthropic Claude | @anthropic-ai/sdk | ANTHROPIC_API_KEY | AI Assistant chat (/api/ai/assistant) |
| Google Gemini | @google/generative-ai | GOOGLE_AI_API_KEY | Gemini agent, Olyron narrator, social AI |
| OpenAI | (optional) | OPENAI_API_KEY | Reported by /api/ai-status when present |
ANTHROPIC_API_KEY is missing, the assistant endpoint returns HTTP 503 "AI service not configured". You can check which providers are wired up at GET /api/ai-status, which returns booleans for claude, gemini, and openai (never the key values).#The execute API
Every terminal command flows through one endpoint. It authenticates the caller, looks up their tenant_id from the profiles table, and runs the command with that tenant scope.
POST /api/terminal/execute
commandstring (required)- The raw command text, exactly as typed (e.g. "leads" or "open deal Acme"). Must be a non-empty string or the endpoint returns 400.
The server ignores any tenant or user identifiers sent in the body and instead derives them from the session, so the endpoint can't be used to reach another workspace. Responses have this shape:
successboolean- Whether the command executed successfully.
outputstring- A short human-readable result line (empty for AI-bound commands).
errorstring | undefined- Present only when success is false.
panelobject | undefined- Structured panel data for the animated overlay.
// Request
{ "command": "leads" }
// Response
{
"success": true,
"output": "Found 128 total leads",
"panel": {
"id": "a1b2c3d4-...",
"type": "leads",
"title": "Leads Analytics",
"subtitle": "6 new today, 21 this week",
"icon": "leads",
"data": { "stats": { "total": 128 }, "byStatus": {}, "bySource": {} },
"timestamp": "2026-07-10T14:22:00.000Z"
}
}tenant_id. All command-level errors are returned with success: false and an error message rather than an HTTP error status.#Limits & troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| "Unauthorized" / redirected to sign-in | No active session | Sign in again; the Terminal requires an authenticated user. |
| "No tenant associated with user" | Profile has no tenant_id | Finish account/workspace setup so your profile is linked to a tenant. |
| A short command does nothing useful | Prefix matching needs 3+ characters | Type at least 3 characters, or use the full command name. |
| Natural-language request returns nothing | AI not configured or invoked from the wrong surface | Use the AI Assistant panel and ensure ANTHROPIC_API_KEY is set. |
| Voice button does nothing | Insecure context or unsupported browser | Use HTTPS/localhost and a browser with Web Speech support. |
/search and view terms can't break out of the intended filter.There is also a separate, hidden Olyron mesh visualization at /crm/olyron, gated behind the NEXT_PUBLIC_OLYRON_ENABLED feature flag. It is not linked from navigation and is unrelated to the everyday Command Center — if you see "Olyron is not enabled", that flag is simply turned off.