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) (part 3)

Part 3 of the CLI Control page: the surfaces an outside AI can look at and drive — AI Coaching interviews and artifacts, bookmarks, inbox alerts, a snapshot or screenshot of the window, an on-screen spotlight it can point with, and a jump straight to one setting.

What it is

This is part 3 of the CLI Control (control Omniscio from scripts and hotkeys) page. It covers the endpoints an outside AI uses to look at and drive what is already in front of you — your coaching interviews and artifacts, your bookmarks, inbox alerts, an actual picture of the window, an on-screen spotlight it can point with, and a jump straight to one setting.

Where to find it

Same surface once more — one local address, one token from Settings → CLI Control. What changes here is what is being pointed at: these endpoints reach features you already know in the app, so an AI showing you a bookmark, dropping an alert in your inbox, reading a coaching artifact or circling a control on screen is touching the same thing you would click yourself.

How it behaves

AI Coaching — /ai-coaching/*

The /ai-coaching/* routes expose the AI Coaching virtual project — interview prompts, saved artifacts and their version history, the core profile and pinned context, session bookmarks, and compaction summaries — for external automation. Reads are bearer-gated and read-budgeted at 60/min per token-hash. Writes split two ways: approval-gated artifact and interview mutations (POST /ai-coaching/artifacts → ai_coaching.artifact_create, PATCH/DELETE /ai-coaching/artifacts/:id, POST /ai-coaching/interviews → ai_coaching.start_interview) land as pending rows in the same cli_pending_actions queue as cron/automation/away-mode/recipes, while the bookmark mutations (POST/PATCH/DELETE /ai-coaching/bookmarks) and the session-scoped POST /ai-coaching/sessions/:sessionId/artifact — the in-app coach's own title-locked save, confined to its own session — apply immediately. A kill switch at Settings → CLI Control (aiCoachingCliEnabled, default true) flips every route to 403 with disabled: true when off. PATCH carries optimistic concurrency via expectedLatestVersion (returns STALE_ARTIFACT on mismatch). Full request/response shapes, curl examples, and the approval-gated pipeline: cli-ai-coaching.md.

Bookmarks — /bookmarks/*

Six routes (GET /bookmarks, POST /bookmarks, PATCH /bookmarks/:id, DELETE /bookmarks/:id, POST /bookmarks/reorder, POST /bookmarks/:id/launch) expose the bookmarks feature for external automation. Mutations apply immediately (like keybindings) — they're personal launcher entries with no destructive cascade — and emit bookmarks:changed push so any open Omniscio UI re-renders. Two security rules apply: exe-kind launches are rejected at the CLI surface (403), and cmd first-run still requires user confirmation in the Omniscio popover — the CLI launch schema is z.object({}).strict() so a CLI caller cannot bypass via confirmed: true. A kill switch at Settings → CLI Control → Bookmarks API (bookmarksCliEnabled, default true) flips every route to 403 when off. Read endpoint is bearer-gated and read-budgeted at 60/min per token-hash. Full request/response shapes, curl examples, and the reorder all-or-nothing contract: bookmarks.md.

Inbox alerts — /alert

Seven routes (POST /alert, GET /alert, GET /alert/:id, POST /alert/:id/archive, POST /alert/:id/unarchive, DELETE /alert/:id, POST /alert/:id/stuck-task-helper) let any session or agent drop a persistent row in the user's inbox — a build broke, a PR is ready, a long job finished. Creating one applies immediately (no approval round-trip — a benign, reversible attention row, unlike the billable spawn routes), so it's the one agent-facing way to proactively surface something. A kill switch at Settings → Features → Allow agents to raise inbox alerts (agentAlertsEnabled, default on) flips POST /alert to 403 when off; the read / archive / unarchive / delete routes are never gated. The seventh route — POST /alert/:id/stuck-task-helper (accept a "want a hand getting unstuck?" offer carried by the alert) — is the exception: it is approval-gated and billable because accepting it spawns a paid coach session, so it enqueues a stuck_task.start_helper approval (idempotent via X-Client-Request-Id) rather than applying immediately. The create body is title plus a contentType of text / link / file and its one matching content field (text, or fileBase64 + fileName); add an optional dedupKey to coalesce repeats into one ×N row, or a projectId to also surface it in that project's Needs You section. Mutations share the 10/min bucket; reads the 60/min budget. Full request/response shapes, the ~750 KB file ceiling, dedup, and inbox behaviour: inbox-alerts.md.

TOKEN=$([ -n "$AMC_CLOUD_SESSION_BOX" ] && printf '%s' "$AMC_CLI_TOKEN" || cat ~/.amc/cli-token)

# Drop a text alert in the inbox (applies immediately — no approval round-trip)
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -H "X-AMC-Source-Session-Id: $AMC_SESSION_ID" \
  -d '{"title":"Build failed on main","contentType":"text","text":"The 14:02 CI run failed — needs a look.","dedupKey":"ci-main-fail"}' \
  http://127.0.0.1:19519/alert

UI Highlight, Discovery + Screenshot — /ui/highlight, /ui/snapshot, /ui/screenshot

Six routes (GET /ui/snapshot, GET /ui/screenshot, POST /ui/highlight, POST /ui/highlight/clear, GET /ui/highlight/status, POST /ui/open) let an external AI see what's on screen, point the user at it, know when the user acts, and open a feature surface. /ui/snapshot is the agent's structural eyes (a JSON list of anchored elements + positions); /ui/screenshot is its camera (an actual PNG of the window, for when text isn't enough); /ui/highlight is its finger (an ad-hoc spotlight + tooltip on one or more DOM elements — "open this menu", "flip this toggle", "the X you're asking about lives here"); /ui/highlight/status is its ears — it reports back when the user actually clicks a highlighted element, so the agent can drive a genuinely interactive, click-to-advance walkthrough (see the target → wait for the click → react / draw the next step). Use a single highlight step for one-off pointing; use a multi-step flow when the user needs Next/Previous navigation between several places; add advanceOn to a step to make it wait for the user's real click instead of a Next button.

Anchor-only contract. /ui/snapshot emits ONLY elements that carry data-ui-anchor="<stable-name>" — a curated registry of UI surface that the AI is allowed to point at. There is no auto-selector synthesis, no text/aria scraping, no element cap. If an element doesn't have an anchor, the AI can't see it. The trade-off is intentional: the agent gets a small, stable, human-labelled list (with description, when, related) instead of a 300-element auto-derived blob whose selectors break on every layout shuffle. blindSpots tells the agent how many interactives are out there but unreachable, so an answer like "that button doesn't have an anchor yet — file an issue" is grounded.

  • GET /ui/snapshot (auth, 200 OK) — walk the live DOM in the renderer for [data-ui-anchor] elements and return a JSON snapshot. Response shape: { ok: true, snapshot: { route, viewport, capturedAt, blindSpots, elements: [...] } }. Each element entry has { anchor, selector, label, kind, rect, visible, value?, description?, when?, related? }. selector is always [data-ui-anchor="<name>"] — the only stable selector shape. label comes from the registry's description or the element's aria-label (no fallback to text content). kind comes from the registry (button, link, input, toggle, tab, menuitem, row, region, composite). description / when / related are human-written metadata from src/shared/ui-anchor-registry.ts — the agent uses these to choose which anchor to highlight. blindSpots: { unanchored, shadowDom, webview } counts interactives (buttons, links, inputs, role=button) that are visible + in-viewport but lack data-ui-anchor, so the agent knows how much of the surface is currently un-pointable. No element cap — the registry is curated and small by construction.

  • GET /ui/screenshot (auth, 200 OK) — capture the renderer window as a PNG. By default returns raw image/png bytes (so curl -o screen.png saves it and the agent can read the file); pass ?format=base64 for a JSON body { ok: true, format: "png", width, height, dataBase64 } when the caller can't consume binary. The image is downscaled so its long edge is ≤ 1568 px (the threshold AI vision pipelines downscale to anyway — bounds payload + token cost with no detail loss). Uses Electron's webContents.capturePage(), which captures ONLY this window's own pixels (not the desktop, not other apps). Errors: 401 (missing/invalid token), 429 (own 30/min budget drained), 503 ({ ok: false, error } — window missing/destroyed/minimized or a blank frame; bring Omniscio to the foreground and retry), 500 (capture/encode failed). Pairs with /ui/snapshot: snapshot tells you what's there and where; screenshot shows you what it looks like. This is also how the in-app Ask Omniscio agent sees the screen (it holds the same bearer token).

  • POST /ui/highlight (auth, 200 OK) — show the overlay. Two body shapes (both .strict()):

    • Single-step (shorthand): { selector, title?, message?, mode?, autoDismissMs?, requestId? }. The route normalizes this to a one-element steps array before emitting.
    • Multi-step: { steps: [{ selector, title?, message? }, ...], startIndex?, mode?, autoDismissMs?, requestId? }. steps is 1–20 entries; startIndex is clamped to a valid index. The renderer shows Previous · "Step N of M" · Next/Finish in the footer; Arrow Left / Arrow Right also navigate. Steps with unresolvable selectors auto-advance forward (and back) so a stale anchor in the middle doesn't trap the user.
    • Each step's selector is any CSS selector document.querySelector understands (1–500 chars; canonical is [data-ui-anchor="…"] from /ui/snapshot but #id / [aria-label="…"] / .class still work for ad-hoc cases). title (≤80 chars) renders in the tooltip header — defaults to "AI Tip" when omitted. message (≤2000 chars) renders in the body. Both title and message accept Markdown (bold, italics, inline code, links, lists) — rendered with the same ProseBlock pipeline as agent chat messages. mode is reserved for future variants and currently only accepts "spotlight". autoDismissMs (500–60 000) overrides the default; pass null to disable auto-dismiss entirely. Defaults: single-step auto-dismisses after 8 s; multi-step does NOT auto-dismiss (stays until the user finishes / dismisses) — multi-step flows can have unbounded reading + clicking time. requestId (≤64 chars) is echoed in not-found logs so a caller can correlate which highlight failed. Response shape: { ok: true, found: boolean[], steps: number } — found[i] is whether step i's selector resolves to a visible element (real on-screen layout size) at request time, NOT mere existence. An off-screen-but-sized element is found: true (the overlay scrolls it into view) — EXCEPT one inside the conversation message scroller ([data-scroll-container]), which can't be scrolled into view there (raw scrolling fights the chat scroll engine) and so is found: false, matching what the overlay actually shows; a 0×0 / display:none match is found: false because highlighting it would dim the screen with no visible cutout. So treat found: false as "this highlight won't actually show — pick a different, visible target" rather than retrying the same selector. The route still emits the push event even when one or more steps return found: false (the renderer's per-step retry loop catches late-rendering targets and the auto-advance handles permanent misses).
    • Interactive (click-to-advance) steps. Any step may carry advanceOn to make the overlay wait for the user to act, then record it and advance — instead of the read-and-Next default. advanceOn is a discriminated union: {"type":"click"} (the user clicks the highlighted selector) or {"type":"anchor-appears","anchor":"<name>"} (a named data-ui-anchor element mounts — use this to confirm an outcome, e.g. a success toast, without intercepting a click). A click step also honors suppressAction (boolean, click-steps only): omitted/false = REAL — the overlay is click-through, so the click performs the real action (really opens the menu, really flips the toggle) and the tour advances; true = PRETEND — a transparent click-catcher detects the click but suppresses the real handler, a safe demo that changes nothing. The mode is per-step, so one flow can mix real and pretend steps. Each acted step is recorded to the renderer's event bucket for /ui/highlight/status to report. advanceOn composes with multi-step footers (the user can still use Next/Previous), and an interactive single-step flow does not auto-dismiss (it waits for the act).
  • POST /ui/highlight/clear (auth, 200 OK) — dismiss any active overlay. Body { requestId? } (.strict()). Idempotent — succeeds with 200 even if no overlay is showing.

  • GET /ui/highlight/status (auth, 200 OK) — "has the user acted yet?" Returns the interactive-step outcomes the overlay recorded (from advanceOn steps). Query params (both optional): requestId filters to one highlight's events (pass the same requestId you sent to /ui/highlight); waitMs (0–25 000) turns the call into a bounded long-poll — the route re-checks every 250 ms and returns as soon as an event arrives or the deadline passes, so an agent can BLOCK on the user's click without busy-polling. Response shape: { ok: true, clicked: boolean, events: [...] } — clicked is true when at least one matching event exists; each event is { requestId?, stepIndex, selector, type: "click" | "anchor-appears", mode: "real" | "pretend", at } (at = epoch ms). The event bucket is cleared each time a new highlight is shown, so a stale click from a prior highlight never leaks in (scope with requestId for belt-and-suspenders). Read-only — never spawns, spends, or mutates. Errors: 401 (missing/invalid token), 429 (own 120/min budget drained), 503 ({ ok: false, error } — main window missing/destroyed).

  • POST /ui/open (auth, 200 OK) — open a feature surface in the renderer, the CLI twin of the per-feature open hotkeys. Body { target } (.strict()) where target is one of mindmap, whiteboard, scratchpad, alarm, meetings, super-prompts, question-widget, ask (ask-about-this-page popover), quick-replies, help (help & docs panel), tag-palette (tag picker). Apply-immediately, shares the 10/min mutation bucket, purely visual — it emits the same push the open hotkey fires (so each surface's own feature gate + layout logic stays single-sourced), can't spawn / spend / destroy. A 200 means the open was accepted (a feature-gated target no-ops; meetings / question-widget toggle rather than always open, matching the hotkey).

  • POST /ui/deep-target (auth, 200 OK) — navigate to a view AND spotlight a control in one call. Body: { path, anchor, title?, message?, autoDismissMs?, requestId? } (.strict()). path is a navigate-only deep-link path string — same namespace as omniscio:// routes (e.g. setting/cli-control, project/Foo, session/<id>, note/<vault-path>) — and anchor is a data-ui-anchor name (lowercase alphanumeric + hyphens; invalid charset returns 400). Spawn paths and any non-navigation action kind return 400. After navigating, the renderer waits (bounded ~6 s, MutationObserver) for the anchor to mount, then spotlights it with the same overlay as POST /ui/highlight. An agent call drops a click-to-go toast (same agent-foreground guard as all other view-switch routes); the spotlight spec is carried inside the toast and replays when the user clicks through. Gated by the deep-target-highlight unreleased feature (settingKey: deepTargetHighlightEnabled): returns 403 when the feature is off. Shares the 10/min mutation pool. For a shareable / clickable version of the same operation, append ?highlight=<anchor>[&highlightTitle=&highlightMessage=] to any navigate-only omniscio:// deep link instead of calling this route.

Visual. The spotlight uses a thickened 3 px blue ring with an outer halo glow and a gentle 2-second pulse animation so small toolbar icons are obvious — it's deliberately more prominent than the app-tour spotlight (which uses a thin 2 px ring). The tooltip has a header bar with the title on the left and the X dismiss button on the right (X stays in the header, not the body, so the rich-text body uses the full width). Multi-step flows add a footer row with Previous · "Step N of M" · Next/Finish.

Snapshot transport — dead-reliable two-path. /ui/snapshot first tries mainWindow.webContents.executeJavaScript('window.__amcCollectUiSnapshot()') — the fast path, a renderer bridge installed at preload time (via contextBridge.exposeInMainWorld, not from a React component) so the bridge is available the moment the renderer process starts. If the fast path returns null (bridge not yet installed) or throws (renderer crashed mid-collect), the route falls back to inline injection: a self-contained collector script with the STATIC_UI_ANCHORS registry baked in as a JSON literal, executed via the same executeJavaScript channel. The inline collector walks the DOM identically to the preload bridge and returns the same shape. Either path can succeed independently — /ui/snapshot only returns 503 when BOTH return null (the main window is destroyed or the renderer is totally unresponsive). The request is bounded by a 3 s timeout per path so a hung renderer can never pin the request thread. Single-flight lock: concurrent callers share one in-flight Promise. The practical result: an external AI session can call /ui/snapshot against any build (dev, packaged, sandbox) at any time without first verifying the preload bridge is current.

Highlight transport. /ui/highlight and /ui/highlight/clear are fire-and-forget on the renderer side — they emit a push event (UI_HIGHLIGHT_SHOW / UI_HIGHLIGHT_HIDE) and return immediately. /ui/highlight also probes every step's selector synchronously in the renderer first so it can report the per-step found[] array in the response. The renderer overlay resolves the selector for the active step, retries 5×30 ms (~150 ms) for late-rendering targets, and renders the overlay. It only ever targets a visible element: it prefers an in-viewport match, else scrolls an off-screen-but-sized match into view first (EXCEPT inside the conversation message scroller, where raw scrolling would fight the chat scroll engine), and NEVER resolves a zero-size element — a 0×0 rect would paint a full-screen dim with a collapsed, invisible cutout ("screen dims, card shows, nothing highlighted"). Selector matches nothing visible → the renderer logs a warn-level entry to <userData>/logs/main.log (with selector + requestId); in multi-step flows the active step auto-advances forward (or back, if you came from the right) to the next resolvable step; in single-step flows the overlay silently dismisses. Single-instance — a new SHOW replaces any active overlay. User dismissal paths: × button in the header, Escape key, click anywhere outside the tooltip (capture phase, doesn't block the underlying click — clicks INSIDE the tooltip on Next/Previous never dismiss), the auto-dismiss timer (single-step only by default), or POST /ui/highlight/clear.

No setting kill-switch — the overlay is purely visual, can't spawn processes, can't spend money, and can't perform destructive actions. Disabling means rotating the bearer token via Omniscio → Settings → CLI Control → Regenerate. Rate limits: /ui/highlight and /ui/highlight/clear share the global 10/minute mutation pool. /ui/snapshot has its own 60/minute read budget so a polling agent can refresh every second without burning the mutation pool that writers depend on (drained budget returns 429 { ok: false, error: "Rate limit exceeded (60 snapshots/minute)", retryAfter: 60 }). /ui/screenshot has its own 30/minute read budget (lower than snapshot because a PNG is a much heavier payload), also separate from the mutation pool. /ui/highlight/status has its own 120/minute read budget (generous because it's a poll / long-poll endpoint), also separate from the mutation pool. The raw-PNG response carries the same security-header floor (X-Content-Type-Options: nosniff, X-Frame-Options: DENY, CSP, Referrer-Policy: no-referrer) as the JSON responses. Bearer-token auth required (no query-string ?token=).

TOKEN=$([ -n "$AMC_CLOUD_SESSION_BOX" ] && printf '%s' "$AMC_CLI_TOKEN" || cat ~/.amc/cli-token)

# 1) Discover what's on screen — agent reads this first to choose a selector
curl -H "Authorization: Bearer $TOKEN" http://127.0.0.1:19519/ui/snapshot
# {"ok":true,"snapshot":{
#   "route":"#/settings","viewport":{"w":1280,"h":800,"scrollY":0},
#   "capturedAt":"2026-05-15T07:00:00.000Z",
#   "blindSpots":{"unanchored":12,"shadowDom":0,"webview":0},
#   "elements":[
#     {"anchor":"app-inbox-button","selector":"[data-ui-anchor=\"app-inbox-button\"]",
#      "label":"Go to inbox","kind":"button","rect":{"x":16,"y":12,"w":24,"h":24},
#      "visible":true,"description":"Top-left Omniscio logo button — jumps to the unified inbox.",
#      "when":"Always present in the title bar.",
#      "related":["app-attention-count"]},
#     ...
#   ]
# }}

# 1b) Grab an actual picture of the window, then read it
curl -sH "Authorization: Bearer $TOKEN" http://127.0.0.1:19519/ui/screenshot -o /tmp/amc-screen.png
# (now open /tmp/amc-screen.png — e.g. an agent reads the image file)
# JSON variant for clients that can't save binary:
curl -sH "Authorization: Bearer $TOKEN" "http://127.0.0.1:19519/ui/screenshot?format=base64"
# {"ok":true,"format":"png","width":1280,"height":800,"dataBase64":"iVBORw0KG..."}

# 2) Single-step highlight with Markdown body (default 8s auto-dismiss)
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"selector":"[data-ui-anchor=\"app-inbox-button\"]","title":"**Your inbox**","message":"Click here to triage *cross-project* alerts.\n\nKeyboard shortcut: `Ctrl+Q`"}' \
  http://127.0.0.1:19519/ui/highlight
# {"ok":true,"found":[true],"steps":1}

# 3) Multi-step flow — guided sequence with Next/Previous (no auto-dismiss)
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{
    "steps": [
      {"selector":"[data-ui-anchor=\"app-inbox-button\"]","title":"Step 1","message":"This is your **inbox** — every alert lands here."},
      {"selector":"[data-ui-anchor=\"app-focus-pill\"]","title":"Step 2","message":"This is **focus mode** — batches notifications so you only get pinged on a threshold."},
      {"selector":"[data-ui-anchor=\"app-settings-button\"]","title":"Step 3","message":"Open **Settings** to configure rules and thresholds."}
    ]
  }' \
  http://127.0.0.1:19519/ui/highlight
# {"ok":true,"found":[true,true,true],"steps":3}

# 4) Stale selector — emits anyway so renderer can log + auto-advance in multi-step
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"selector":"[data-ui-anchor=\"removed-anchor\"]","message":"…"}' \
  http://127.0.0.1:19519/ui/highlight
# {"ok":true,"found":[false],"steps":1}

# 5) Interactive (click-to-advance) — point at a real control, then WAIT for the user to click it
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"selector":"[data-ui-anchor=\"app-settings-button\"]","title":"Open Settings","message":"Click the gear to open Settings — I'\''ll continue once you do.","advanceOn":{"type":"click"},"requestId":"tour-1"}' \
  http://127.0.0.1:19519/ui/highlight
# {"ok":true,"found":[true],"steps":1}

# ...then long-poll for the click (blocks up to 20s, returns the instant they click)
curl -H "Authorization: Bearer $TOKEN" \
  "http://127.0.0.1:19519/ui/highlight/status?requestId=tour-1&waitMs=20000"
# {"ok":true,"clicked":true,"events":[{"requestId":"tour-1","stepIndex":0,
#   "selector":"[data-ui-anchor=\"app-settings-button\"]","type":"click","mode":"real","at":1750000000000}]}

# Safe DEMO variant — suppressAction detects the click but suppresses the real action (nothing opens)
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"selector":"[data-ui-anchor=\"app-settings-button\"]","message":"Try clicking it — this is just a demo, nothing will actually happen.","advanceOn":{"type":"click"},"suppressAction":true}' \
  http://127.0.0.1:19519/ui/highlight
# {"ok":true,"found":[true],"steps":1}

# Manually dismiss
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{}' \
  http://127.0.0.1:19519/ui/highlight/clear

Dev tool. npm run ui-snapshot (or npm run ui-snapshot:summary for a one-line-per-anchor overview) hits /ui/snapshot against the running app and pretty-prints the JSON — useful when wiring new data-ui-anchor attributes. See scripts/dump-ui-snapshot.js.

Adding an anchor. New trainable element? Add data-ui-anchor="<kebab-name>" to its JSX, then add a matching entry to your feature's co-located *.ui-anchors.ts file with { description, kind, when?, related? } and run npm run ui-anchors:reindex (per ui-anchor-colocation-contract.md) — src/shared/ui-anchor-registry.ts is now a generated re-export barrel; never edit it or the generated file directly. Internal-only anchors used by tests/keyboard nav (not user-trainable) get internal: true and are stripped from the snapshot output. The collector is the only consumer of the registry, so no other wiring is needed.

Navigate to a setting — GET /settings/open

Take the user straight to a specific setting from a script or an AI. GET /settings/open?q=<query> (auth, 200 OK) emits the same open-setting deep link the in-app Settings-search "jump to this setting" uses: Omniscio opens Settings, jumps to the matching section, scrolls to the row, and flashes it. q is plain English — it resolves through the SAME fuzzy catalog the Settings search box uses (labels + keywords + synonyms), so q=backup%20mirror, q=spend%20cap, and q=default%20model each land on the right row. Read-only and free — it navigates, changes nothing.

Like the other view-switch routes, an agent-initiated /settings/open (one sending X-AMC-Source-Session-Id) no longer jumps your view directly: while you're in Omniscio it drops a click-to-go toast and returns { ok: true, action: "open-setting", suggested: true, reason: "nav-suggested" } (the pane opens only when you click the toast); while a different app owns the foreground it drops an inbox note and returns { ok: true, action: "open-setting", focusSuppressed: true, reason: "user-in-another-app" }. Opt in at Settings → CLI Control → "Let agents switch your view directly" (default off) to restore an immediate jump to the matched pane. It's the CLI twin of the agentmc://setting/<query> deep link.

Pair it with the read/patch settings routes: GET /settings/open NAVIGATES the user to a setting, GET /settings/:key READS a value, and PATCH /settings/:key CHANGES one (approval-gated — see the omniscio-control settings surface). GET /settings/search?q= returns the matching setting candidates (via a renderer round-trip, so the app window must be open) — use it to inspect what would match, then /settings/open to take the user there. And GET /deep-link/resolve?url= dry-runs any omniscio:// link, returning the action it resolves to (or a "did you mean") without navigating — for a setting link it also confirms the setting really exists, so one that would dead-end comes back as a failure naming the nearest real settings instead of a false green (with the app closed it says the setting could not be verified rather than guessing either way). A setting link may name its target by the AppSettings key these very routes use (gitGuardrailsReadyTagGateEnabled), a setting id, a section id, or a phrase.

TOKEN=$([ -n "$AMC_CLOUD_SESSION_BOX" ] && printf '%s' "$AMC_CLI_TOKEN" || cat ~/.amc/cli-token)

# Jump the user straight to the Backup Mirror setting
curl -sH "Authorization: Bearer $TOKEN" \
  "http://127.0.0.1:19519/settings/open?q=backup%20mirror"
# {"ok":true,"action":"open-setting","query":"backup mirror"}

Related

The endpoints that change projects, sessions, docs, away-mode rules and recipes are in part 2, and switching the server on plus calling it from a script is on the parent page. The coaching data these routes expose is described in cli-ai-coaching.md, the alert surface in inbox-alerts.md, and the launcher behind the bookmarks routes in bookmarks.md.

Last verified 2026-09-28