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

Inbox alerts (how an agent gets your attention) (part 5)

Acting on an alert: starting a session from one, the automatic remediation that fixes enrolled infra alerts, where an alert came from, and the once-a-day lifecycle digest.

What it is

The continuation of part 3: what you can do with an alert once it has arrived.

Where to find it

All of these act from the alert card itself or from the Alerts screen.

How it behaves

Start a session from an alert

Every agent-raised alert can kick off a Claude Code session about it. Open the alert and click Start session (the message-plus icon in the card's bottom action bar — available on desktop and mobile; Archive stays in the top-right corner of the header). A small dialog opens with two text boxes, a target-repo picker and a model/harness picker:

  • a Message box — empty at open. It is your own instruction, and it owns the attachment affordances (paste / drop / paperclip) because it is the composer. Plain Enter submits from here, per your send-key setting; and
  • an Alert details box — collapsed by default, and still fully editable once you expand it: a non-blank per-alert preset (sessionPrompt) leads, then the alert's title and content body (text / link / file), so the new session starts already briefed instead of with just the headline. Clicking the Alert details header reveals it. The alert text is reference material most sessions never edit and it pushed the rest of the dialog off screen, so it starts folded — the collapse changes what you see, never what is sent: the same text is attached to your message whether or not you open the box. Plain Enter stays a newline here, because it is a document to read and edit rather than a composer; and
  • a target repo — the alert's saved sessionProjectId if it still exists and is spawnable, otherwise the project the alert is grouped under, falling back to the Claude default. Several auto-lander notices set sessionProjectId so Start session opens in the affected repo — the in-process supervisor already holds the repo's project id, so the paused — uncommitted changes and stuck — nothing landing alerts set it directly. The paused alert waits out the self-heal window before it appears — a base-dirty pause is almost always a transient the auto-lander repairs itself within ~10 min, so the inbox row is held until the folder stays dirty past that window (a genuinely stuck checkout), then reads with a one-click Open Diagnostics button (the lander's status card) instead of the old "commit or stash" wording a non-programmer can't act on. Both clear themselves when the repo recovers — the paused row the moment the checkout goes clean again, the stuck row when the backlog lands or empties (mirroring the other self-clearing maintenance alerts above). A second, longer-window stuck escalation ("stuck — over 15 minutes") fires alongside the ~5-minute one when a wedge persists on the wall clock — a backstop that still catches a lander whose supervision ticks are being silently skipped under heavy load; it sets sessionProjectId and clears on recovery the same way. When the blocker is a foreign half-finished git operation in the repo's folder (a leftover merge / rebase that never clears itself), the stuck copy names exactly that instead of the old misleading "a land is already running", and both stuck alerts point you at Start session to clear it. (They carry no Open Diagnostics button — the whole auto-lander status/pileup family lost it on 2026-08-18 because it steered non-developers into a raw diagnostics screen; only the base-dirty paused, auto-preserved and tick-failing cards still deep-link there.) See auto-lander-contract.md (S13/S14/S20/S21). When the auto-lander cannot finish branches on its own — automatic rescues switched off, a rescue that could not even start, a session that went silent while holding the branch, or a set-aside it could not write (a branch whose rescues simply ran out is set aside quietly instead, see above) — the give-up notice ("N branches need a hand to finish landing", coalesced into one card per repo) is written for a non-programmer: it reassures you the work is safe and points you at Start session to see why each branch stalled (no Open Diagnostics button: buttonless status/pileup family) and decide whether to land them or set them aside. It deliberately does not pre-fill a one-click rebase-and-land agent — the automatic retry it would re-run has already failed — so the copy no longer promises an agent can "finish landing them for you". The universal Start-session button remains, and since 2026-09-29 it hands the agent a triage brief instead of nothing: it points at the card's LIVE branch set, says the card collects every give-up reason so two branches on it can differ, and tells the agent to read each branch's OWN recorded reason before acting, land what can land through the normal path, and say why in one line and set aside whatever genuinely cannot — never a blind re-run of the retry that already failed. It self-clears a branch the moment that branch has nothing left to land: it lands, its work already reached master through other branches (a net-empty / superseded duplicate, which is also retired), or its ref is gone — so a branch superseded after it was carded never lingers as a false "needs a hand" row (E5/E14). The paused ("uncommitted changes") and stuck ("nothing landing" / "over N minutes") alerts carry the same one-click treatment: clicking Start session launches an agent already briefed to resolve that specific blocker — safely, since the paused case touches a checkout with uncommitted changes: the agent is told to preserve any real work (stash / recovery branch) and never run a destructive git command on changes it didn't make, while the stuck-agent aborts only a clearly-abandoned half-finished merge/rebase (E14). The same one-click treatment covers the last two per-branch notices: a branch that moved after tagging (new commits since its ready-to-merge tag), whose agent re-runs the checks and re-tags it, and one blocked by a safety check (a possible secret in the diff, or missing translations), whose agent runs the translation step for missing translations or, for a flagged secret, removes and rotates it safely rather than leaking it (the alert never contains the secret value) (E14). A companion "N branches are waiting to land" card coalesces every branch that has stayed ready-but-unlanded past a short threshold into one card per repo (each branch's exact wait time + reason live on the lander's Diagnostics status card); it sets sessionProjectId + a paused-lander preset so Start session opens in the affected repo, is a buttonless Start-session card (status/pileup family), and self-clears as its branches land — see auto-lander-wait-visibility-contract.md (I3). The auto-lander's check its folder card (raised when a watched repo's folder looks moved, missing, or polluted) likewise self-clears once the repo checks out healthy again — and both its false-alarm shapes are caught before they alarm: a folder-health git probe killed under a startup load spike degrades to a quiet retry, and a "far more untracked files" overflow that is really the repo's OWN ignored deps + tracked source mis-scanned while a fleet of agents churns the checkout is confirmed against git's committed history (HEAD + the committed .gitignore, which a live scan race can't corrupt) before it alarms and otherwise degrades to a quiet retry — so neither leaves a stale "update your folder path" card (same contract, S18). Untracked clutter sitting INSIDE one of the repo's own tracked folders — an audit's saved copies, a tool's scratch — is never counted as a polluted folder at all, and a repo the lander does skip is named, with the reason, in its status line instead of reading as an idle sweep (S177). The "main checkout out of sync" notice arrives with no project (the merge worker can't know the project UUID), so POST /alert fills its sessionProjectId at ingest — resolving Omniscio's own checkout to its project (path-matched, spawnable-gated) — so Start session pre-selects Omniscio. The same ingest-time resolution covers the other projectless Omniscio-self maintenance cards keyed by their dedupKey: the cloud-base-broken card and the worktree-cleanup card ("Unmerged worktrees need inspection" / "Worktree triage", dedupKey: unmerged-inspection-queue, raised by a scheduled cleanup cron that likewise can't know Omniscio's project UUID). The seven cloud-fleet self-cards raised by the cloud-queue monitor do the same — three health verdicts ("Cloud fleet health degraded", "…failing systemically", "…split-brain") plus four informational status cards ("VM disk saturated", "GCP capacity exhausted", "spot-preemption wave", "queue fall-open storm"), each about Omniscio's own cloud test-offload fleet. Omniscio's two self-health alerts — "Unusual number of errors" (dedupKey: telemetry-error-spike) and "Sessions are failing to start" (dedupKey: telemetry-spawn-failures) — do the same, resolved in-process by the health monitor: best-effort, so a resolution hiccup never suppresses the alert, and off a packaged build it falls back to the Claude default. An explicit sessionProjectId still wins. See inbox-alert-contract.md (I14).
  • a model & harness picker — collapsed to the project's resolved default engine and model, so you can read what will run without touching anything. It is optional in the strong sense: an untouched picker forwards nothing, so a launch that ignores it is byte-identical to one made before the picker existed. Change it only to run this session on a different engine or model; it uses the same shared chips as the New Session screen and the mobile composer. The Model list here spans the whole harness, not just the engine your default resolves to: on a DeepSeek default you can still pick Opus, Sonnet, GLM, Kimi or any other brain the Claude Code harness runs, one row per model grouped by maker, and the pick carries its engine along with it. (Unlike the in-session picker, this dialog has no separate Provider control, so a provider-only list would leave everything but your default engine unreachable.)

The two boxes compose ONE opening message: your Message leads, the alert text follows, and a blank side is dropped. A left-empty Message box therefore sends exactly the alert text — what this dialog sent before the second box existed — and an emptied Alert details box sends your message alone.

The message the session actually receives also carries an alert-context block the boxes never show, appended at launch time by buildAlertContextNote (src/shared/alert-session-prompt.ts): the alert's type code, the subsystem and repo file(s) that raise it (resolved from the generated alert catalog, so the agent can go read the code behind the card instead of guessing from its prose), when it was first raised and how many times, and the GET /alert/:id route to read the row back. On a folded card — several same-title reports merged onto one row, which reads "N separate reports share this heading" — the block opens with one more line: how many reports the card lists, that starting the session dismissed all of them, and that the card's own instructions apply to every report, so the session handles each one rather than only the newest.

Edit any of them, then confirm to spawn the session (launch source alert-start-session). Confirming is optimistic: the dialog closes immediately and the alert is dismissed the instant you click — never blocking behind a spinning "Starting…" button or a ~1s pause — moving you straight to the next item that needs you while the session starts in the background, without pulling you into it. Your prompt and the agent's reply stream into the new session in the sidebar. (A rare failure to start brings the alert back with a toast so you can retry, since the dialog is already gone.) The button shows on every agent alert — the only exemptions the guard sanctions are a team-chat notice and a card whose bottom the reply box occupies (inbox-alerts.md) — and the agent does not have to attach a prompt for it to appear. The app-generated alerts listed above (stuck-task, low-spec, Low Power Mode, sync-drift, Gmail reconnect, GitHub reconnect, account re-auth, team-chat new message, release-notes, Anthropic status, …) each also show their own feature-specific button alongside it, never instead of it, with Start session leftmost in the bar so each card's own action stays rightmost. If no spawnable repo exists the button is disabled (never hidden) with a tooltip. The alert text is built by buildAlertSessionPrompt and the two boxes are joined by composeAlertSessionPrompt (both in src/shared/alert-session-prompt.ts), mirroring Drip's launch. This "every alert, apart from the two sanctioned exemptions" rule is build-enforced: alert-start-session-universal.test.ts (in the cross-cutting guard lane) fails the build if any change would let an alert ship without the button — the gate narrowed to exclude an alert, the button re-gated at its render site, or the button removed. See inbox-alert-contract.md (I8) and alert-start-session-optimistic-contract.md (the optimistic close + no-double-spawn invariants).

Auto-remediation (enrolled infra alerts auto-start a fix session)

For a curated set of Omniscio-infra alerts — cloud fleet degraded / failing-systemically / split-brain / offload-down, direct-SSH refused / firewall-failed, cq-monitor crashed, ops-deploy drift, Firebase degraded, the auto-lander / auto-merge daemon stalled, the worktree reconcile / trash-sweeper stuck, WAL checkpoint failing, a degraded freeze-prevention gate, and a Firebase website that failed to publish — Omniscio doesn't wait for you to click Start session: it auto-spawns the remediation session itself, in the background, into the Omniscio project, then silent-archives the card (the spawned session is the only signal). This generalizes the four bespoke cloud self-healers (cloud-base / seed / chain / deploy, which fire from the POST /alert route) to the shared createAlert chokepoint, so an in-process infra alert is covered too — enrollment is the autoRemediate flag on an alert type's row in alert-type-registry.ts (always a subset of isAmcSelfAlertDedupKey).

It is cost- and freeze-safe by construction: only a freshly-created enrolled alert spawns (a dedup bump never does); a 3-minute boot-grace suppresses the startup re-detection storm; a 6-hour per-condition cooldown (in-memory, surviving the card archive) stops a flapping alert re-spawning; and a global burst cap bounds a simultaneous multi-condition failure. The spawn also rides the existing daily spend-cap + disk/memory pacing in the session spawner. Deliberately excluded (they stay passive cards): informational / self-heal notices, anything that needs YOU (reconnect / reauth / low-spec / unsaved-changes worktree), the memory/CPU perf/pressure alerts (spawning under load would worsen a freeze), and the spawn-queue alerts (a remediation spawn could itself raise them — reentrancy).

One fault, one fixer. A single outage often raises several different alert types within minutes, and each used to start its own fix session. Now, before an auto-fix session — or one of the four cloud self-healers — starts, Omniscio looks for sessions that were started from an alert in the same area within the last two hours and are still running, and names up to five of them at the top of the new session's instructions. The new session reads what they are doing and stands down (handing its alert to that session) only if one is already working the same fault; otherwise it carries on and names the related session in its report. It never blocks a fix: if the lookup fails or takes more than two seconds, the session starts exactly as before. Every automatically started fix session also carries the same clickable Spawned from link to its alert that a card-started session has.

Turn it off at Settings → Lab → "Auto-fix infrastructure alerts" (autoRemediateAlertsEnabled, on by default) for a passive card you act on yourself — a fix session costs money, so the off switch lets you approve each one; the emergency env kill-switch is AMC_DISABLE_ALERT_AUTO_REMEDIATION=1. See alert-auto-remediation-contract.md.

Where an alert came from (provenance)

Every alert says where it came from. Open any alert and its detail view (AlertInboxViewer) names the origin right under the title, in one of two forms:

  • "Generated by <session name>" — when a session raised it. Captured from the X-AMC-Source-Session-Id header (Omniscio-spawned agents send it automatically) and persisted as the source_session_id snapshot column on inbox_alert_items. Click it to jump straight to that session.
  • "From <feature>" — when a background service raised it, which is the case for every built-in advisory (session load balancing, the spend monitor, the status pollers). These carry no session, so before this they showed no origin at all. The feature is named in plain words — never an internal id — and the name is a link to Settings → Notifications, so every card also carries a route to manage or turn off notifications, not just the few with their own off-switch. Resolved by describeAlertSource (alert-source.ts), which falls back to "Omniscio" for a producer it doesn't recognize.

The origin is detail-only — it never appears on the compact inbox row. A team-chat notice is the one exception to the two forms above: its header already leads with the sender's name and avatar, which is its provenance. See session provenance and inbox-alert-contract.md (I11 / I15c).

The daily lifecycle digest (landing and workspace notices arrive once a day)

Omniscio's landing and workspace machinery used to be by far the loudest thing in the inbox: measured over the week to 2026-09-09, it raised 41 cards a day, spread across 60+ different kinds of notice, most of which happened less than once a day. That spread is why fixing them one at a time never worked; none of them was big enough to matter on its own, and together they buried everything else.

They are now split by a rule:

  • A few genuinely need you. Six kinds still arrive as their own card, the moment they happen — a branch that changes dependencies and needs your OK, a broken build on master, a merge that could not land, a conflict the auto-resolver gave up on, workspace creation failing, and nowhere left on disk to put a workspace.

  • Most of the rest arrive once a day. The "landing is behind" family, cleanup pacing, "your unsaved work is kept safe", inventory counts — all gathered into one card per area per day: one for landing, one for workspaces. Each lists what happened, how many times, when it started and stopped, and how much of it fixed itself. That is about 31 notices a day folded into 2 cards.

  • A third group is deliberately left alone. Around 21 kinds of notice live in the same part of the app but are not part of this split — genuine infrastructure faults that almost never fire, so there was no evidence to justify quieting them. They behave as they always did, about 4 cards a day.

    One of them is "a project document could not be rebuilt after the last merge" (2026-09-23). Some documents in a project are written by the machine rather than by a person — a list of every script the project ships, for instance — and Omniscio rebuilds them automatically after each merge. When a rebuild fails, the saved copy may go out of date, and if it does, the next branch that touches that area gets turned away when it tries to merge, for rows it did not cause. Nobody working on that branch can see it coming, because those documents are only checked at merge time. So the failure now gets a card of its own, naming which documents may be out of date, instead of only a line in a log nobody reads. It is one card per project however many documents are affected, it updates itself as documents come back, and it disappears on its own once the last one is rebuilt. A rebuild that failed only because the machine was momentarily out of resources is retried automatically first, so the card appears only for a problem that is really stuck. A rebuild the machine stopped before it could finish — it ran out of time on a busy machine, or the machine refused to start it — tells us nothing about the document, so it is simply tried again on the next pass and raises no card; the card appears only if that keeps happening — three passes in a row, over at least half an hour (2026-09-26: a single timeout had raised it over merge helpers that were all up to date).

Altogether: about 13 cards a day instead of 41.

The big win is what you never see at all: 91% of the gathered notices resolve on their own within a day, so they are archived by the system before the digest is even written. A problem that fixes itself was never yours to do.

A day where everything fixed itself sends you nothing at all (2026-09-12). The digest is only written when at least one thing is still going on. It used to send a card on those days too — titled "everything sorted itself out", with nothing under it but a list of things that had already resolved — which is a card whose own title tells you not to bother reading it. The owner's rule: an alert that doesn't change what you'd do isn't worth sending.

The landing notices were skipping this until 2026-09-23. The hold that sends a notice to the daily digest lived inside one of the app's ways of raising a card, and the auto-lander raised its own cards another way. So "Auto-lander stuck", "a ready branch is blocked by a safety check" and the other landing notices listed above went straight to the inbox instead — 216 of them between 2026-09-08 and 2026-09-23, about 90% of which fixed themselves within minutes. The hold is now applied where every card is written, so no route can skip it.

"A branch was stopped past its time limit" joined the daily summary on 2026-09-24. Its own text always said the branch would be retried automatically — and it was: 24 of the last 30 such branches landed on that retry, typically about half an hour later — yet each card stayed until you archived it by hand. It is now one card per repository listing the branches, a branch comes off the moment it lands, and the card is held for the daily summary, so a branch that lands on its retry never interrupts you and one that never lands is named every day until it does.

Three changes on 2026-09-25. "Auto-lander is not reaching your waiting branches" now waits for the digest (29 of its last 32 cleared themselves within minutes), while unfinished work nobody is coming back for and a blocked branch landed with its author's sign-off keep their own card. A notice still going on after a day stays in the digest, named every day until it stops, instead of arriving as its own card two days in (17 did, 2026-09-10 to 09-25). A one-off heads-up that can never "clear", such as a landed branch had no session to notify, counts as settled and sends no card.

Six more kinds of notice joined the digest on 2026-09-28, and they are the ones there was genuinely nothing for you to do about. A session that could not be resumed after a restart (it tries again next time the app restarts), idle sessions parked to protect memory (that protection stands down by itself), a test result that could not be delivered (the retry and the session's own end handle it), the test-baseline readout (a status, not a fault), cloud test-machine faults repeating (the fix is a developer's command), and guard-baseline debt growing on master (also a developer's job). Measured over the eight days before the change: 57 of these arrived, every one cleared by hand, and not one of them cleared itself.

The readout is worth knowing about: it reports the result of each test-baseline run, and the digest shows the latest one each day rather than each run as it finishes. It also reports on healthy runs, so its card appears most days — that is deliberate, it is the one item here you asked to keep seeing.

On 2026-09-29 the digest took on the biggest cluster of all: the background machinery talking about itself. A daily card called Background jobs and housekeeping now carries the scheduled jobs that have not finished a run (they are still being tried on their normal schedule), the ones that keep failing (the notice clears the moment one run succeeds), a job that has stopped being attempted, a fleet status that keeps re-paging, background jobs using more of the computer than they should, a "still working" notice for a long wait, a tool with a newer version, and the "this PR body needs its real delta" / "nobody picked up that PR reply" cards — both of which tell a developer to run a command, not you. Alongside them, six finishing-touches notices from the workspace machinery ("a step is running but achieving nothing", "a step is running slow", a reclaim backlog, slow workspace creation, a git repository growing). Measured over the seven days before the change: these families sent 369 cards and every one was cleared by hand; not one of them cleared itself, and none of them asked you anything.

What deliberately stayed a card, because the rule says so rather than because of how loud it is: everything about your money (including the metered-vendor spend cards, which now come with a fix — see below), every notice that carries a button you can press, work that is at risk of being lost, and the performance notices. Those last ones are the app telling you your own machine was slow, and slowing you down to say it would be the wrong trade — so they keep arriving when they happen.

One bug came out of this pass. The "spend today is unusually high" card for a metered vendor was coming back every 15–45 minutes after you had already dismissed it — six fresh cards for one provider in a single day, each one closed by hand in the seven days measured. The cause was in the card's own escape hatch: a runaway is allowed to skip the once-a-day wait so it is never missed, and that skip was also skipping your dismissal. A card you close now stays closed for the rest of that day, and a genuinely new runaway another day still arrives immediately.

Nothing is hidden by that. The self-resolved notices are not thrown away — they are held, and if something real does turn up later the same day, that day's card appears with the new item and the earlier self-resolved ones listed under it. A condition that keeps happening is named in every day's digest until it stops, and if the digest itself ever stops running, the individual cards come straight back — the system is built to fail toward noise, never toward silence.

Turning a built-in notice off from the card

Omniscio's own advisory cards each carry a quiet "Turn off these notices" button in the card's bottom bar (pushed far left so it never out-shouts the card's main action). One click turns that one kind of card off, confirms with a toast, and archives the card; Settings → Notifications has the matching toggle to turn it back on. Turning a notice off only silences the card — the underlying work keeps running (turning off the load-balancing notice does not stop sessions being spread across your logins, exactly as turning off the stuck-install notice does not stop the cleanup).

Cards with their own off-switch today: low-memory warnings, AI-cost alerts, stuck-install cleanup notices, screen-grab block notices, inbox-backlog nudges, watch-time recaps, input-method shortcut warnings, and session load-balancing notices (the "your <login> is carrying N active sessions" card — loadBalancingNoticeEnabled). Alerts that report a genuine failure you need to act on — reconnect Gmail, sign in again, a dead keyboard shortcut — deliberately have no per-card off-switch, so a real problem can't be silently hidden.

Relationship to Drip

Drip is a second producer of the same primitive. On release, the scanner calls the same createAlert service, writing rows into the shared inbox_alert_items table with source_kind = 'drip'. Those rows surface via the drip inbox integration (listDripSourcedInboxItems, filtered by source_kind), NOT the alert integration — each agent-raised row has source_kind = 'agent', so the two integrations never overlap in the inbox.

A drip-sourced alert reuses its drip_item's id, so the inbox row (alert) and Drip's detail-view row (drip_item) are addressable by one id: DRIP_ITEM_ARCHIVE/UNARCHIVE dual-write both tables to keep the unified inbox and DripDetailView in sync. The synthetic "drip finished" completion row is the one item that stays a drip_item only (no alert), so it remains excluded from the cross-drip inbox as before. See inbox-alert-contract.md (I9, I10).

Related

Last verified 2026-10-05