Omniscio documentation
Browse all documentation
  1. Getting Started19
  2. Sessions & Agents133
  3. Inbox & Notifications68
  4. Projects & Tasks98
  5. Automation & Scheduling74
  6. Knowledge & Memory28
  7. AI Features71
  8. Integrations112
  9. Plugins & Marketplace40
  10. Cloud & Teams51
  11. Settings & Customization74
  12. Account & Billing28
  13. Troubleshooting77
  14. CLI & API Reference28
  15. Legal & Policies5
  16. Uncategorised17

Plugin Run Keep-Alive

A plugin doing long work in its own page (a deck build, a narrated video) declares it with `runs.start`, beats with `runs.heartbeat` and ends it with `runs.finish`. While a run is live, opening another plugin no longer destroys that plugin's screen, and if the screen dies anyway the user gets one inbox card saying what stopped, why, and how to reopen the plugin.

What it is

Omniscio normally keeps only the last plugin you opened mounted in the background. Before this, a run living in a plugin's page died the moment you opened a second plugin, popped the first one out or quit, and nothing told you. The runs bridge methods let a plugin say "I'm working", so the host keeps that screen alive and never lets the work stop silently. It needs no manifest permission: a run can only keep the calling plugin's own screen alive.

Where to find it

There is nothing to switch on in Omniscio. A plugin calls the three methods from its own page through the bridge object the host hands it. What a user sees is the result: a busy plugin keeps working while they look at another one, and if a run is cut short, a card titled "<Plugin> stopped before it finished" appears in the inbox with an Open the plugin button.

How it behaves

if (typeof AgentMC.runs?.start === 'function') {
  const res = await AgentMC.runs.start({
    runId: 'motion-q3', // your id, 1-200 chars; starting it again just refreshes it
    label: "Motion for 'Q3 pitch'", // shown to the user if the run dies, 200 chars max
    inboxItemIds: ['motion-q3'] // optional: your own inbox.setItems / sidebar rows to clear then
  })
  // res: { ok: true, heartbeatEveryMs: 30000, staleAfterMs: 180000, maxRunMs: 7200000 }
  //   or { ok: false, reason: 'too-many-runs' | 'no-screen' }
}
await AgentMC.runs.heartbeat('motion-q3', { label: "Motion for 'Q3 pitch': slide 6 of 18" })
await AgentMC.runs.finish('motion-q3') // on success, failure AND cancel
  • The screen stays alive while any run is live, up to 3 plugin screens in total. Past that cap the oldest screen that is not the one on view is let go.
  • A run never stops silently. If the screen closes, crashes or reloads, Omniscio quits, or no heartbeat arrives for 3 minutes (plus a 60-second check, so a laptop waking from sleep is not a stop), the host removes the rows you named and posts one card per plugin with your latest label, the reason and an Open button. The card is the app's own, so it arrives even when agent alerts are switched off.
  • There are hard limits you cannot change. One run is kept for at most 2 hours (maxRunMs), however faithfully it beats, and starting it again does not restart that clock. One plugin may have 5 live runs across all its windows; a sixth start answers too-many-runs. A beat sooner than 5 seconds after the last one is ignored, so beat about every 30 seconds. The limits are fixed in the host: start refuses any field that tries to set them. A run stopped for running too long gets the same card, with its own reason.
  • The card is built by the host. It names the plugin by its manifest name and shows your label as one quoted phrase on a single line, so a label cannot pose as the card's own words. Only rows in your own plugin's lists are ever removed; naming another plugin's row does nothing.
  • Popping a busy plugin out is refused with a plain message, because the pop-out would replace the screen the run lives in.
  • Beat at least every 30 seconds. A hidden screen's timers can slow to once a minute, and the 3-minute window allows for that. heartbeat answers { ok: false, reason: 'unknown-run' } when the host no longer knows the run, so call start again.
  • On a phone the methods succeed silently and return nothing, because the phone's own browser holds the page. Read res?.ok rather than assuming an answer.

For agents

The host side is runs-handler.ts (the bridge namespace) over plugin-run-registry.ts (runs keyed by the calling screen), and the dashboard keeps screens through use-kept-plugin-screens.ts. The card's key is plugin-run-stopped:<pluginId>. The rules are in .claude/memory/contracts/plugin-run-keep-alive-contract.md.

Related

The rest of what a plugin can call is on the Plugin Bridge Capabilities page and its second part, which also covers the inbox rows (inbox.setItems) and cards (inbox.postAlert) a run names.

Last verified 2026-10-14