Omniscio documentation
Browse all documentation
  1. Getting Started13
  2. Sessions & Agents115
  3. Inbox & Notifications59
  4. Projects & Tasks95
  5. Automation & Scheduling75
  6. Knowledge & Memory26
  7. AI Features60
  8. Integrations100
  9. Plugins & Marketplace33
  10. Cloud & Teams56
  11. Settings & Customization58
  12. Account & Billing28
  13. Troubleshooting84
  14. CLI & API Reference22
  15. Legal & Policies4
  16. Uncategorised22

CLI Control (control Omniscio from scripts and hotkeys)

CLI Control is the local-only HTTP door into Omniscio: how to turn it on, copy or regenerate its token, drive the app from a script or a hotkey, and what it refuses to do without your say-so. This overview covers what the server is, where its switch and token live, and the walkthrough for calling it.

What it is

CLI Control is a tiny HTTP server that Omniscio runs on your own machine at 127.0.0.1:19519. It lets any tool that can make an HTTP request — AutoHotKey, PowerShell, curl, Python, Bash, an external AI like Claude Code — navigate Omniscio, launch sessions with a pre-typed prompt, bring the window to front, pop a project or integration out into its own window, or create/schedule/toggle cron jobs. It's on by default, localhost-only (cannot be reached from other machines), and any mutation (starting a session, creating a cron job) requires a token that Omniscio auto-generates and stores at ~/.amc/cli-token with OS-level file-permission hardening. Read-only endpoints like /ping and /status are open, so your scripts can check health without handling the token.

Where to find it

CLI Control lives in Settings → CLI Control, which is where you switch the server on or off, read and copy its token, regenerate that token, and decide which outside requests must wait for your approval. It is not a panel you open to use; it is a door other programs knock on, and that Settings page is where you choose how far it opens.

How it behaves

How to use it

  1. Confirm it's on and copy your token. Open Settings → CLI Control. CLI Control ships enabled. The Token field shows a hex string you can copy; use Regenerate to invalidate the old one at any time. A small "Created N ago" line under the token shows its age and turns amber once it is over 90 days old, nudging you to Regenerate (the token itself never auto-expires). A fresh token is also mirrored to ~/.amc/cli-token (%USERPROFILE%\.amc\cli-token on Windows).
  2. Call the read-only endpoints. GET http://127.0.0.1:19519/ping returns {ok: true}. GET /status lists your projects and integrations. GET /cron/jobs, /cron/jobs/:id, /cron/jobs/:id/runs, /cron/runs/upcoming return cron state — these require Authorization: Bearer <token> (they surface private cron data) and share a per-token 60/min read budget. No token is needed for /ping and /status.
  3. Navigate or focus. GET /inbox, /focus, /project/<name> (fuzzy-matched, case-insensitive), or /superprompt/<id>. As of the CLI-server hardening these need a valid bearer token (Authorization: Bearer <token>) or a same-origin request from Omniscio's own UI — a header-less, tokenless call is now rejected with 403, closing a hole where any local program (or a malicious web page) could steal window focus or force navigation without your token. Hotkey macros must send the Authorization header. (/ping and /status stay open with no token.)
  4. Launch a session or create a cron. GET /project/<name>/new?token=<YOUR_TOKEN>&prompt=<url-encoded prompt> spawns a session and auto-sends the prompt. The spawn is created by the background engine and is durable — as of 2026-06-04 it no longer depends on the Omniscio window being responsive, so a 200 means the session was actually created, and a spawn survives a busy/frozen UI or an app restart mid-spawn (a rapid burst is paced, returning 202 for the queued ones). By default the new session opens silently in the background — Omniscio does NOT come to the foreground. That's the right default for agent-driven calls (the user is working in another app and shouldn't be yanked away). Hotkey-driven workflows that DO want focus must opt in with &focus=true (only the literal string true opts in; focus=yes / focus=1 are ignored). /focus and /window/open bring the window forward; /project/<name> (activate-project, no /new), /inbox, /settings/open, and the note / mind-map / Gmail-thread / saved-prompt routes SWITCH which screen you're looking at — and the "don't take over the user's screen" rule covers both. (a) Foreground: an agent-initiated /focus / /window/open (a call sending X-AMC-Source-Session-Id) is auto-blocked while a different app owns the foreground (returns focusSuppressed: true + an inbox note you can silence via its "Turn off these notices" button or Settings → Notifications → "Screen-grab block notices"); it still foregrounds when you're already in Omniscio, or when you opt in at Settings → CLI Control → "Let agents bring Omniscio to the front" (default off). (b) View-switch: an agent-initiated activate-project / /inbox / setting / note / mind-map / Gmail-thread / saved-prompt request no longer changes your view directly — while you're IN Omniscio it drops a click-to-go toast ("…wants to switch to X — Go there") that navigates only when you click, and while you're in another app it drops the same inbox note; either way it never moves you on its own, unless you opt in at Settings → CLI Control → "Let agents switch your view directly" (default off). A human's own hotkey, notification click, phone tap, or the in-app UI is never affected. /cron/jobs supports POST (create), PATCH /cron/jobs/:id (update), DELETE /cron/jobs/:id (delete), POST /cron/jobs/:id/run (fire now), and POST /cron/jobs/:id/toggle (enable/disable). All cron mutations require Authorization: Bearer <token> and are capped at 10 per minute. There is no ceiling on how many cron jobs an install may hold — the MAX_CRON_JOBS row-count cap (200, later 500) was removed on 2026-09-06 because it measured the wrong quantity: it counted every row in the table (inactive, rejected, spent one-shots, wake schedules), so an install with 199 dead rows was refused a create while one with 199 jobs firing every five minutes was not. What replaced it is the create-RATE policy above, which is what a runaway caller actually runs into; the single source is cron-job-create-rate.ts.
  5. Pop a project or integration into its own window. POST /window/open with a JSON body { "projectId": "<id>" } opens (or focuses) that project — a real project or an integration like Tasks — in its own themed desktop window, the HTTP half of the in-app "Open in new window" button. projectId takes a project UUID, a friendly alias, or an integration id such as tasks-v2. It's bearer-authed, shares the 10/min mutation cap, and is idempotent (a second call just focuses the existing window, returning state: "already-open"). Full details — id resolution, response shape, and the 404 / 409 (a dedicated window like KMS has its own route) / 400 (no panel to show) cases — live on the omniscio-control windows surface. (Yes, this is supported: earlier notes that called a CLI pop-out "out of scope" predate this route.)
    • POST variant for Unicode-safe prompts. POST /project/<name>/new exists alongside the GET form because Windows mangles non-ASCII chars (em-dash, arrows, accented chars, emoji, non-Latin scripts) in the cmd.exe / Git Bash argv pipeline before curl can encode them — they arrive at the spawned session as ? or U+FFFD replacement chars. The POST variant takes the prompt as a JSON body field, which streams from the socket as raw bytes and bypasses argv encoding entirely. Auth is header-only (Authorization: Bearer <token> — query-string ?token=... is rejected with 401), Content-Type must be application/json (charset suffix allowed), body schema is { prompt?: string, name?: string, provider?: ProviderId, focus?: boolean } (.strict()). Empty body is allowed for a source-less call (no prompt → blank session), but a prompt-less agent spawn — one sending X-AMC-Source-Session-Id — is rejected 400 ("a spawned session needs a prompt"): an agent always has a task for the child it spawns, so a missing prompt is a caller bug that would otherwise leave a dead empty session. Only literal boolean true opts into focus. provider forces the engine for this one session; omit it and the session uses the project's configured default provider (the one set via PATCH /project/:id defaultProvider, gated by the show-alternate-providers master toggle), falling back to Claude — the same provider the UI's + New button would pick, so a CLI / cron / recipe spawn into a project defaulted to e.g. Gemini now correctly starts on Gemini instead of silently using Claude. name stamps an exact session title instead of letting the AI titler infer one. The 1 MB body cap matches the other mutations, but /new is deliberately not on the 10/min mutation bucket — spawns are serialized by a FIFO spawn pacer at one every 30 s (≈2/min), and a burst is queued and released in order (each queued spawn returns 202) up to a 50-deep runaway backstop that returns 429. Validation errors are self-explanatory: a malformed JSON body returns 400 with the parser’s own message, the character position, and a short snippet of the body around the break (echoed only to the caller, never logged), and an unrecognized body field returns 400 with a did-you-mean hint (Unexpected field: message — Did you mean ‘prompt’? — common aliases like message/text/task map to prompt, and close typos suggest the nearest accepted field). An optional X-Client-Request-Id header (≤64 chars) makes a retry safe — reuse the same id and a duplicate POST returns 200 { idempotent: true } instead of spawning a second session (without it, /new does not dedup). That replay is a receipt, not a bare acknowledgement: it carries the ORIGINAL spawn's spawnId, plus status and sessionId once the session exists — so a caller that timed out and retried learns WHICH session its first call made instead of being told only that something happened. Source required by default: with requireSpawnSourceSession on (the default), both /new forms AND POST /agent/sessions refuse a spawn that sends no source with 400 — pass X-AMC-Source-Session-Id: $AMC_SESSION_ID (an Omniscio-spawned agent has it in env) so the child links back to its origin, or the user turns the setting off in Settings → CLI Control for anonymous script/hotkey spawns. A scoped agent token can't spawn by default: the /new forms accept the global CLI token and an in-app session, but an agent's scoped per-session token (the $AMC_CLI_TOKEN Omniscio injects into every spawned session) is refused (401/403) unless the user opts in at Settings → CLI Control → "Let agents spawn sessions with their own token" (allowAgentTokenSpawn, default off) — so a compromised MCP server / npm dep reading an agent's env can't spend money by spawning paid sessions; the narrowest per-MCP-server token never spawns. (The separate POST /agent/sessions agent-driven-spawn path has its own agentDrivenSessionsEnabled gate.)
    • Confirming a spawn — GET /spawn/:spawnId. Every /new reply (200 immediate, 202 queued, 202 starting) carries a durable spawnId; this route resolves it. Response { ok: true, spawnId, status, sessionId, error } where status is created (the session exists — sessionId names it), pending (accepted, not driven yet), failed (the driver gave up, or its caller withdrew it — error says why), or unknown (no spawn by that id). Resolved from the session's own origin_spawn_id anchor, so it is exact. Confirm with this, never by listing /sessions and taking the newest — a perf:instant-new-session prewarm shell is indistinguishable from a fresh spawn (both blank + ready), so a timestamp guess picks the wrong one. Read-only, on the 60/min read budget; the global CLI token sees any spawn, an agent's scoped token only spawns it originated (403 otherwise).
    • Withdrawing a queued spawn — DELETE /spawn/:spawnId. A spawn paced into the queue (202) can be taken back before it starts. The spawn pacer gives each caller a share of its 50-deep queue measured from the queue itself, so a request you no longer want holds a slot you cannot use — and until this route there was no way to give one back. Withdrawing cancels the request itself, not just its place in line, so nothing can start it later — GET /spawn/:spawnId then answers failed with the error "withdrawn by its caller". Answers 200 with withdrawn (how many queued entries were removed), cancelled (whether the spawn is withdrawn for good — false if it had already begun starting, or there was nothing to cancel) and queued (whether it is still waiting); an id that already fired or was never queued is a harmless 200 no-op, never a 404. The global CLI token may withdraw any spawn; an agent's scoped token only one it originated, never an operator's or a cron's (403 otherwise). On the mutation budget.
TOKEN=$(cat ~/.amc/cli-token)

# Unicode-safe — em-dash, arrows, emoji, Chinese, accents all survive intact
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"prompt":"Em-dash — and arrow → and emoji 🚀 and Chinese 你好"}' \
  http://127.0.0.1:19519/project/MyProject/new

# Hotkey workflow that wants the window in front
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"prompt":"continue from where we left off","focus":true}' \
  http://127.0.0.1:19519/project/MyProject/new
  1. Hand the token to an external AI safely. The omniscio-control skill bundle reads ~/.amc/cli-token automatically and POSTs with approval gating enforced server-side — see omniscio-control.md (the consolidated entry covering cron, automations, settings, sessions, recipes, projects, tags, away-mode, keybindings, and pending actions).
  2. Trigger pre-approved recipes. POST /recipes/run lets an authenticated agent fire a multi-step Claude workflow without opening Omniscio. Two orthogonal gates apply: the recipe must have agentTriggerable.enabled set in the Recipe Editor's "Agent triggering" card (others return 403 — an agent cannot trigger an arbitrary recipe) AND the recipe must have cleared the authoring approval gate (approvalStatus ∉ {pending, rejected}; pending/rejected recipes return 400 even when the agent-trigger flag is on). A 30-second cooldown per (recipeId, projectId) tuple prevents accidental retry-loop double-fires; the engine still enforces its singleton lock so concurrent triggers return 409. GET /recipes/triggerable is the discovery endpoint — agents call it first to see what's flagged. Full request/response shapes, error codes, and cost-cap behavior: agent-trigger-recipes.md.

For agents

Implementation

The HTTP listener binds to 127.0.0.1 (never 0.0.0.0) in /src/main/services/cli/cli-server.ts (the flat services/cli-server.ts is now a re-export shim; the impl + per-surface cli/cli-server-*-routes.ts files live under cli/), which also declares every route, enforces the per-token 10/min cron mutation limit, and hard-codes requiresApproval: true on AI-created jobs so clients can't override it. The token is generated in /src/main/services/config-store/accessors-runtime-state.ts via crypto.randomBytes(16).toString('hex') on first launch, stored encrypted in config.json, and mirrored to disk by /src/main/services/cli/cli-token-file.ts. Disk hardening: Unix writes with mode: 0o600 via fs.writeFile; Windows runs icacls <path> /inheritance:r /grant:r "<user>:F" (5-second timeout so antivirus scans can't hang startup). The settings UI is src/renderer/src/features/settings/sections/cli-control/CliControlSettings.tsx (show/hide + copy + regenerate). Regeneration flows through the CLI_TOKEN_REGENERATE IPC handler in /src/main/ipc/cli-token-handlers.ts, which rewrites the file in place — no restart needed. Session-spawn routing calls through to the same process manager that GUI launches use; cron mutation routing Zod-validates the body and hands off to /src/main/db/queries-cron-jobs.ts for persistence. User-facing marketing page: /docs/intro-sandbox/cli-control.html. The complete route inventory is machine-derived, not written here. Every registered route — with the gating tier read out of its own handler, its feature id and its source file — is in the CLI Control Server route gating catalog (2,917 routes across the hub and its path-range shards), regenerated by npm run cli-gating:reindex. Read that rather than treating this page, or any hand-written list, as the inventory of record: the generated one cannot miss a route or invent one, which a hand-kept list always can.

Related

  • omniscio-control.md — the skill bundle that uses /cron/jobs, /automation/*, /settings, /keybindings/*, /recipe/*, etc. from external AIs
  • create-cron-job-with-ai.md — user-facing walkthrough for the cron surface specifically
  • agent-trigger-recipes.md — POST /recipes/run + GET /recipes/triggerable in detail (agent-fired recipe runs)
  • bug-report-intake.md — PATCH /project/:id/bug-intake opt-in details and the email triage pipeline it controls
  • inbox-alerts.md — POST /alert in detail: how an agent drops a persistent row in the user's inbox
  • mobile-remote-access.md — a different server for remote (non-localhost) access from your phone
  • The CLI route gating catalog — the complete, generated route inventory (every route + its gating tier)

This page is split across three parts: part 2 covers the endpoints that change projects, sessions, project docs, away-mode rules and recipes, and part 3 covers the ones that read and drive what you are looking at — coaching data, bookmarks, inbox alerts, screen capture and on-screen highlighting.

Last verified 2026-09-28