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

Plugin Marketplace

Omniscio’s built-in plugin catalogue: what the Marketplace is, where to find it, and how browsing, installing, uninstalling and updating work — the auto-update check, the version compatibility rules, the gate on unverified third-party plugin backends, and the approval card an agent’s install request raises.

Building your OWN plugin from a local source folder (no packaging/marketplace steps) is Plugin Developer Mode — Settings → Plugins.

What it is

A built-in catalog inside Omniscio that lets you browse, install, update, rate, and uninstall Omniscio plugins — without copying files, editing JSON, or restarting the app. Plugins are first-class extensions of Omniscio: they can add virtual sidebar projects (like RepoGuard), drop new menu entries, expose webview-based UIs, and call a sandboxed bridge into Omniscio's IPC.

The marketplace lives in two places: a standalone Marketplace view (Store icon, accessible as a virtual project in the sidebar, with its own category sidebar beside a search + sort toolbar) for browsing, and the legacy Settings → Plugins card for plugins you already have installed — which now carries its own search box, A–Z/Z–A sort, and status (enabled/disabled) + source (built-in/marketplace/dev) filters over the installed list, shown once you have enough plugins to warrant the bar (the filter/sort logic is the pure, unit-tested plugin-list-filter.ts, and the bar reuses the same SearchInput + Select primitives the Marketplace toolbar does). The standalone view is where ratings, plugin-detail pages, and the developer dashboard live.

The marketplace solves four concrete problems: (1) you don't have to know which .json manifests Omniscio expects, (2) plugin files are checksum-verified so a tampered registry can't silently swap a malicious bundle into your install, (3) updates look after themselves — an update that asks for nothing new is applied in the background, and one that wants new access is a single click — Omniscio compares your installed version against the registry and shows an amber Update chip next to anything stale, and (4) ratings + reviews let you see what other users think before installing.

Availability (ON by default)

The Marketplace is on by default since 2026-05-28. The sidebar row and Settings → Plugins browser render for every user. To hide it, toggle Settings → Workflow → Features → Enable Marketplace (marketplaceEnabled, default true).

A one-time reset on 2026-05-26 (force-off-features-migration.ts) originally flipped this flag — along with KMS, Marketplace Review, and Tasks Outliner — OFF for every install, including anyone who had been using the pre-flag Marketplace. A follow-up one-shot migration on 2026-05-28 re-enabled marketplace for existing users whose flag had been set to false by that reset, and dropped marketplace from the force-off list (KMS / Marketplace Review / Tasks Outliner are still reset). After that one-time fix, your toggle choice is authoritative.

What ships with Omniscio

Eight plugins are built in — they are already on disk when you install Omniscio, so there is nothing to download and they show in Settings → Plugins with their source as built-in. Only Nighty Tidy is switched on for you; the other seven are one toggle away in the same list.

Plugin What it does
AutoHotkey (autohotkey) A no-code manager for AutoHotkey hotstrings, hotkeys and snippets — author entries in the app and it generates the .ahk file for you. See AutoHotkey integration.
Books (books) Import and read the EPUB and PDF books you own. See Books.
Cashbox (cashbox) Money in, money out and profit for each of your side projects, captured in plain words; the numbers stay on this computer. See Cashbox.
Daily Spend Report (daily-spend-report) Posts a daily inbox card summarising your AI coding value and real out-of-pocket spend from your live ledger. See Daily Spend Report.
Nighty Tidy (nightytidy2) A standalone code-maintenance audit panel — its own audit list, run history and manual Start Run. Ships enabled. See Nighty Tidy 2.
Pattern Oracle (pattern-oracle) Analyses PRs and sessions across your projects for recurring patterns, errors and optimisation opportunities, and delivers weekly intelligence.
Virtual Pets (virtual-pets) A pixel-art companion that roams your Omniscio window, reacts to your sessions, and keeps you company. See Virtual Pets.
Whiteboard (whiteboard) A freeform infinite canvas for sketching and diagramming, with a board library and an AI agent that can read and draw on a board. See Whiteboard.

Foundry (prdstack) is a separate case: it is not bundled, so it arrives through the Marketplace, but Omniscio turns it on for you on first run alongside Nighty Tidy. Everything else in the Marketplace — including the plugins listed in Plugin CLI Discovery — is optional and you install it yourself.

Where to find it

The Marketplace is a virtual project in the sidebar — look for the entry carrying the Store icon, usually labelled Marketplace. Opening it gives you the catalogue: a category sidebar down the left, and a search + sort toolbar above the plugin grid.

What you already have installed is also listed in Settings → Plugins, which carries its own search box, A–Z / Z–A sort, and enabled/disabled + source filters. That page is also where the per-plugin switches live: the auto-update check, unverified plugin backends, the session-history access panel, and the one-click re-approval a plugin may need.

Two further views hang off the same feature — the Plugin Developer view, a separate virtual project where a plugin author tracks their own submissions, and Marketplace Review, the admin queue that triages them.

How it behaves

Browsing

  1. Open the Marketplace. Click the Marketplace entry in the sidebar (Store icon). It opens as two panes: a left filter sidebar (the category list, plus a footer summarizing what you have installed and whether it's current) and the panel holding the search box, the sort dropdown, and the plugin grid.
  2. Filter and sort. Seven categories run down the sidebar: All, Planning, Development, Testing, DevOps, Productivity, Other. Four sort options live in the panel toolbar's dropdown: Most Popular (download count), Highest Rated (average stars), Newest (most recent publish), and A–Z (alphabetical).
  3. Search. The search box sits in the panel toolbar beside sort, and matches against plugin name, description, author, and the developer-declared tags. Empty search shows everything in the current category.

One control, one home. These three used to be drawn TWICE — once in the sidebar and once in the Browse toolbar — bound to the same store state, so they mirrored each other live. Each now has a single home, chosen by what it acts on: search and sort sit next to the grid they reorder; categories sit in the sidebar, where seven items stay visible as a column instead of scrolling off the right edge of a toolbar with no affordance saying so. The same layout serves desktop and mobile — there is deliberately no form-factor variant.

Two things about that split are load-bearing:

  • The sidebar's category labels resolve through marketplaceView.category*. They were raw English literals while the (now-removed) panel pills were translated, so a Spanish user saw an English list mirroring a Spanish one. Now that this is the app's ONLY category filter, an untranslated label would be the only one 17 languages ever see — and no guard catches it, because the hardcoded-string detector cannot see literals inside a const-array of objects.
  • The panel's search box is the shared SearchInput, not a hand-rolled <input>. The box this file used to carry was 14px text with no minimum height (a checked-in lint exemption). INPUT_CLASS carries text-base md:text-sm + min-h-tap precisely because iOS Safari auto-zooms on a sub-16px input and index.html sets no maximum-scale — so as the app's only plugin search, the hand-rolled one would zoom an iPhone and never zoom back. A test asserts the rendered classes so a future hand-roll cannot quietly return.

On mobile the two panes are separate SCREENS, so handleSelectCategory navigates to the results screen unconditionally — including when you re-tap the category you are already on. That is not a redundancy: it is the only route from the filter screen to the results. An early-return-if-unchanged would strand the user on a dead list, so a named test locks it.

  1. Featured row. In the default browse state (no search, category All) a Featured section headlines the view with a curated shortlist of up to three plugins. There is no editorial featured flag on the registry — the picks are derived client-side from the two public signals every plugin carries (rating quality and download popularity) via a Bayesian-weighted curatedScore, so a single 5-star review can't outrank a broadly-liked, widely-installed plugin. Only plugins with some signal (a rating or a download) are eligible, so a brand-new/empty registry simply hides the row. The moment you search or pick a category the Featured row steps aside, and its picks are held out of the main All plugins list below so nothing is listed twice.
  2. Read the cards. Each plugin card shows the icon, name, one-line description, average star rating, download count, version, author, and category. An amber Update chip appears if you have it installed and the registry has a newer version. The download count goes up with every package download (a first install, a reinstall and an applied update all count), so it measures downloads rather than people. Test and throwaway copies of Omniscio do not download Foundry automatically, so they do not inflate its count (details).
    • Trust signals (A3) let you judge a plugin before opening it. A blue Official badge next to the name marks a plugin built and maintained by the Omniscio team (a Community badge marks every other, third-party plugin). Both are derived from a fixed first-party id allowlist in src/shared/marketplace-trust-signals.ts — never a registry-supplied flag, so a third party can't claim "Official". Below the description a row of permission chips shows exactly what the plugin requests: elevated-access capabilities (network, process, filesystem, cloud, or your identity) are amber warning chips with a shield icon; benign ones (storage, sessions, notifications…) are neutral. Past four chips the rest collapse into a +N more chip, and elevated-risk chips are always shown first so a benign one can't push a risky one under the fold.
  3. Open the detail page. Click a card's name, icon, description or star rating to open the plugin's full page; the name is a real button, so Tab then Enter opens it too. The card's Install / Update / Uninstall / on-off / Settings controls keep their own jobs and never open the page. The page takes over the Marketplace panel (loaded on demand through lazyNamedView, with a skeleton while its code loads) and shows the full description, a clickable author that opens the developer's GitHub profile (openExternalUrl, plain text when no GitHub handle), a metadata grid (category, license, package size, minimum-Omniscio version, last-updated — each field self-omits when absent, and the whole card is hidden if the registry record carries none of them), permissions, version history, install/uninstall button, and the ratings panel (which leads with the average score + review count). Opening it fetches: selectPlugin(id) loads the MarketplacePluginDetail record (MARKETPLACE_GET_PLUGIN_DETAIL) and the first page of reviews (MARKETPLACE_GET_RATINGS). Back, Esc (ignored while typing or while a dialog is open) or the Browse breadcrumb returns to the grid and puts keyboard focus back on the plugin's name (use-plugin-page-navigation.ts); a failed load keeps a Back button beside Retry. At phone width the install/uninstall button wraps under the description.
    • The page once had no way in for four months. A May 2026 change dropped the view's only mount of the page while the page itself kept compiling and passing its own tests. The guard renderer-screens-have-a-production-importer.test.ts now fails when any renderer screen loses its last production importer.

Installing & uninstalling

  1. Install. From either the card or the detail view, click the blue Install button. A consent dialog (PluginConsentDialog) appears summarizing the plugin's declared permissions; click Install to confirm. The button swaps to a spinner; on success a toast confirms (Installed <plugin name>). The plugin's files land in <userData>/plugins/<plugin-id>/, the sidebar surfaces any new virtual projects the plugin declared, and any IPC bridges come online. The plugin is also added to enabledPlugins in settings.
  2. Uninstall. On the detail view, click the Uninstall button (red, with trash icon). Same spinner/toast pattern; the plugin's directory is deleted recursively and the virtual project is soft-deleted from the sidebar. Uninstalling also deletes everything the plugin saved — its records (plugin_<id>_* tables), its settings (plugin_kv) and its stored passwords (plugin_secrets), all in one transaction. Reinstalling brings the plugin back but not the data, and the confirm dialog says so before you commit. This is the only path that deletes it: merely disabling a plugin keeps everything (disable is reversible), and so does the automatic check that removes a plugin pulled from the registry — a plugin revoked that way keeps its rows until you uninstall it yourself. A few plugins are exempt outright, either because their data has no second home or because it was migrated out of an Omniscio table and can't be restored by reinstalling; see plugin-data-purge-contract.md.
  3. Update. In-place reinstall — click Install again on a row showing the Update chip and Omniscio atomically swaps in the newer files. Local plugin data is untouched; only the bundle files are replaced.

Auto-update (applies the safe ones, asks about the rest)

Omniscio keeps your installed plugins current by itself, and stops only where it would otherwise hand a plugin access you never agreed to.

  • An update that requests nothing new is installed automatically, in the background, with no click. This is the common case, and it is why you rarely have to think about plugin versions at all.
  • An update that wants access the running version did not have — a new permission, or a background service where there was none — is never applied on its own. It waits, with the permission list shown, until you say yes.

Both decisions are made in the app's main process, against the plugin's actual downloaded package rather than the marketplace listing, so a listing that under-reports what a version asks for cannot slip past. A refusal leaves your installed version exactly as it was. Four more cases wait for you rather than update: a disabled plugin (updating one would switch it back on), one whose stored approval is already behind its installed version, one you are running as a developer build, and anything the app cannot read.

When an update does wait for you, you see three non-intrusive cues:

  • A count badge on the Browse tab and a dismissible "N plugin updates available · Review all" banner at the top of the Browse view.
  • An inbox card ("N plugin updates available") with a Review updates button, which opens the Updates Review modal straight from the inbox. It lists what is waiting by name and version, so the card answers "what changed?" on its own without opening anything. It dedupes on the exact set, so the launch check, the 6-hour interval check and the window-focus re-check all collapse onto one row — and a newly published update still raises a fresh card after you dismissed the last one.
  • The Updates Review modal (opened by the badge/banner/card). It lists each waiting plugin with its version bump (v1.0.0 → v2.0.0), a short changelog snippet, and — critically — the permissions the new version newly requests (a "Requests new:" row). You apply per-row with Update, or all at once with Update all.

A background update is silent on purpose; a broken one is not. The app updates itself the same way — quietly, with no popup — and this subsystem already had a plugin-update toast removed three times, so nothing here raises one. The single exception is a half-landed update: if a plugin's files are replaced but its background service fails to restart, you get the same warning the manual path gives, because an enabled plugin with a dead service is otherwise silent.

Why a card and not a toast for the ones that wait. The check runs three ways you never asked for (launch, every 6 hours, every window focus), so a toast popped over whatever you were doing — and then auto-dismissed, routinely taking its own Review button with it before it could be clicked. The card is raised over MARKETPLACE_NOTIFY_UPDATES and keyed by plugin-updates-alert.ts. The toast was removed and came back three times before this stuck, so it is now banned repo-wide rather than merely removed — re-adding it fails plugin-updates-never-a-toast.test.ts, which also fails if the card is dropped without a replacement.

The check runs on launch (deferred, after first paint), on a 6-hour interval, and on window focus. It's on by default and reuses the existing registry read (MARKETPLACE_FETCH_REGISTRY) — no new network surface. Turn it off at Settings → Plugins → Check for plugin updates (pluginAutoCheckUpdates, default true); with it off, nothing is checked and nothing is updated in the background. It's also gated on marketplaceEnabled, so hiding the marketplace disables it too.

Check on demand. Two buttons run the check immediately, for anyone who'd rather not wait for the automatic pass:

  • Marketplace sidebar, in its own footer below the category list (MarketplaceSidebarFooter.tsx). The footer renders one of four states:

    • Loading… — before the first registry read has completed.
    • Couldn't reach the marketplace — the first read failed outright.
    • No plugins installed yet, with a Browse plugins link that clears the category filter back to All (and, on mobile, also drills straight into the results grid) — there's nothing to check yet, so the button below is omitted entirely.
    • Otherwise, a three-tier hierarchy, top to bottom: your installed count (e.g. 5 installed) headlines the block; a status line underneath reads Up to date, N updates, or check failed, with a checked {when} freshness stamp that ages every 60 seconds (the stamp is omitted on failure — the line turning red already says so); the Check for updates button sits below that. It's shown whenever at least one plugin is installed, including when everything is already current — the update badge/banner/card only appear once updates are already known, so with nothing to report the Marketplace previously offered no way to ask at all.

    The installed count replaced an earlier category-derived plugin total that silently tracked whichever category the user had last clicked in the list above it (never actually a total) and, at public scale, told the user nothing they could act on — "2,847 plugins" says nothing about you.

  • Settings → Plugins, a Check now button beside the auto-check toggle.

They differ in how they answer, and deliberately so. The sidebar button answers in place, on its own status line and freshness stamp — two separate lines, not one — because that footer sits inside one bordered block with the button and persists, so question and answer share one region. The Settings button has no such line next to it (reportUpToDate), so it is never a silent click: "All plugins are up to date" and a failed check still toast, and a check that finds updates opens the Updates Review modal right there rather than pointing you at an inbox card you did not know you were getting. Either way the pending set also lands in the inbox, so closing the modal loses nothing.

A press must always be visible, even when nothing changed. The sidebar button used to feel broken: pressing it while everything was already current changed nothing on screen — the status line already showed the verdict, the forced re-fetch commonly answers in ~200ms (too fast for a spinner to read as anything but a flash), and the sidebar button deliberately never toasts (see above). A user genuinely could not tell a working button from a dead one. The fix, entirely in MarketplaceSidebarFooter.tsx:

  • The button's label swaps to Checking… and HOLDS that state for a minimum window (MIN_PENDING_MS, 700ms) even when the reply is instant, so the press is never a same-tick flash.
  • The freshness stamp resets to "checked just now" unconditionally, whether or not the verdict changed. This is the load-bearing part: "Up to date" is already on screen before the press and stays there after it, so the stamp is the only thing a successful press can ever visibly change. Skip the reset and a click that finds nothing new goes back to being silent — by design this time, instead of by accident.
  • On success only, the status line takes a brief accent pulse (dropped under prefers-reduced-motion) — never on failure, since the line turning red already says the press did something.
  • A screen-reader-only live region announces the outcome in the same words the visible line shows, and only a manual press writes to it. The automatic checks (launch, the 6-hour interval, window focus) still keep the stamp truthful, but must never claim the acknowledgment a manual press earns — an automatic refresh writing to that region would interrupt a screen-reader user roughly once a minute forever, and again on every alt-tab back into the app.

Both buttons spin while working and ignore a second click until the first settles (AsyncButton). Neither installs anything itself: a check asks main for the pass that applies the updates requesting nothing new (see above), and anything wanting new access still waits for your click.

A manual check is a REAL check. fetchRegistry() is TTL-cached for 5 minutes (CACHE_TTL_MS) and opening the Marketplace warms that cache on mount, so an unforced click would have answered straight from cache — reporting "up to date" without a single network call. Both manual buttons therefore pass force, which makes the handler drop the cache (invalidateRegistryCache()) before fetching. The automatic check deliberately does not force — the TTL still shields the remote registry, and a test locks that asymmetry. force is an optional field on the existing MARKETPLACE_FETCH_REGISTRY read: no new IPC channel, and the shared marketplace rate limit still applies.

force means "the user asked for this", and carries three things at once — they're one concept, so they ride one flag (marketplace-store.ts):

  1. Drop the main-side TTL cache — see above.
  2. Bypass the renderer's in-flight dedup — a click moments after mount would otherwise piggyback the very cached load it meant to skip.
  3. Never touch isLoading — that flag swaps the whole plugin grid into skeleton boxes (BrowseTab.tsx), so a manual check used to blank the catalog the user was reading, for no visible reason. A forced load skips the flag entirely; the button's own spinner is the acknowledgment.

A forced load also does not eagerly clear registryError. Clearing it at load start made the status line read "up to date" — no error plus a stale count — while the check was still running, a confident wrong answer moments before it snapped to "check failed". The line now holds its last honest value until a real result lands.

Concurrent loads are ordered, not last-write-wins. Because a forced load bypasses the dedup, it runs alongside the mount's cached load and both write plugins on settle. Without ordering, the older cached response could land second and silently overwrite the fresh registry the user explicitly asked for — and the sidebar would then report against data it had just discarded. A monotonic request id gates the write, so only a response at least as new as the newest one already applied may commit.

Permission escalation is never silent. When you apply an update whose new version requests a permission the installed one didn't have, the consent dialog (PluginConsentDialog) highlights each new permission with a New badge and leads with "This update requests new permissions." The diffPermissions helper (src/shared/plugin-permissions.ts) computes installed-vs-incoming and drives both the modal row and the consent dialog.

Version compatibility (a plugin can be refused)

A plugin declares two version requirements, and Omniscio checks both when it loads one. If either fails, the plugin is marked incompatible: it stays visible in Settings but is withheld from the sidebar and the toolbar, and Omniscio records a plain-language reason for why.

  • minAppVersion — the plugin needs a newer Omniscio than you are running ("Needs Omniscio 0.2.0 or newer (you have 0.1.86)."). Fix by updating the app.
  • sdkVersion — the plugin was built against a version of the plugin SDK this Omniscio build does not implement ("Built for plugin SDK ^3.0.0, but this version of Omniscio provides 2.0.0."). Fix by updating the app, or by the author publishing a build for the SDK you have.

This build implements SDK 2.0.0, matching the published @agent-mc/plugin-sdk on npm. Keeping those two numbers equal is the whole job: the check refuses anything above what the app implements, so if the app lags the published SDK, an author who installs the current SDK and declares the version they installed gets a plugin this app will not load — and sdkVersion is a required manifest field, so they cannot opt out of the mismatch. That is exactly what happened between 2026-08-11 and 2026-08-28, when the SDK went to 2.0.0 and the app still said 1.2.0 (a version npm never had).

The sdkVersion half is new as of 2026-07-27. Before that the field was read only to tell an old-style plugin from a worker-isolated one, and was never checked for compatibility — so a plugin built against a future, incompatible SDK loaded anyway and failed somewhere deep in a bridge call with nothing pointing at the real cause. The check is what makes a future SDK major version safe to ship.

The check is deliberately forgiving, because wrongly refusing a working plugin is worse than a clear runtime error. A plugin with no sdkVersion is always accepted. A bare version like 1.0.7 (which every plugin published so far declares) is read as a minimum, not an exact match, so those keep working as the SDK moves forward — that is why the move to a 2.0.0 host refused nothing already in the marketplace. Only a real range like ^3.0.0 can actually refuse, and an unparseable value is ignored rather than treated as a failure.

Workspace-only plugins

A plugin can be limited to one workspace. Its manifest names the workspace (plugin.requiresOrganization), and Omniscio then shows it in Settings → Plugins and lets you turn it on only while that workspace is your active one. Anyone else never sees it, and turning it on from the CLI (POST /plugins/:id/enable) is refused with a plain "only available to members of its workspace" message. Switch to the right workspace and it appears.

This hides the plugin; it does not protect data. The plugin's code ships in every install, so a workspace-only plugin must keep its data behind its own server-side lock — the first one, the JLS SOP Assistant, keeps its library behind database rules that refuse anyone outside the workspace.

Third-party plugin backends (security gate)

Some plugins ship a backend that runs with full system access (file system, network, child processes). Omniscio cannot verify a third-party (marketplace) plugin's backend, so by default it is refused at activation. The plugin looks like it enables, but its backend never starts and the toggle rolls back. To run one, turn on Settings → Plugins → Allow unverified plugin backends (allowUnverifiedPluginBackends, default false). Only do this if you trust the plugin's author. Built-in plugins ship with Omniscio and are always allowed, so this toggle never affects them.

An update to a running plugin takes effect immediately — its background half is restarted as part of the update. A plugin's background half is a separate program that loaded its code when it started, so swapping the files underneath it changes nothing about what it is executing. Applying the update therefore stops that program and starts a fresh one from the new files, and the update is not finished until it has. Before this, an update replaced the files but left the old program running: the plugin kept behaving as the previous version for the rest of the session while the version number, the files on disk and their checksums all reported the new one — a mismatch nothing surfaced. If the restart itself fails you are told so ("… its background service didn't restart"), the plugin stays switched on, and the next launch retries it. A floating overlay window and a popped-out panel are refreshed by the same update, so they cannot keep showing the previous version's screen either.

A background plugin stays approved across its updates — and tells you exactly which one if it doesn't. When you apply an update to a plugin whose background half is running, Omniscio records your permission for the new version (whichever way you approved it, you were shown the newly-requested permissions first — see the next section), so the restart above does not stop to re-ask, and the next launch cannot strand the plugin on a stale permission record either. In the rare case a background plugin still needs re-approval at startup — for example, an older plugin whose stored permission is out of date — Omniscio raises a one-time inbox notice that names the affected plugin ("GitHub needs your permission again"; for two, "GitHub and Calendar need…"; for more, "GitHub and 2 others…") and deep-links to Settings → Plugins. There the plugin's own card carries a persistent amber "Needs your permission" callout and a one-click Re-approve button that re-grants and restarts it in a single step (no toggle off-then-on) — and opening the page scrolls straight to it. It stays one notice no matter how many plugins are affected, and never silently leaves a plugin's background half dead and looping.

That same "Needs your permission" callout + Re-approve now appears everywhere you might meet the dead plugin, not just Settings: on its Marketplace card and its Marketplace detail page (so browsing to a misbehaving plugin offers Re-approve instead of only Uninstall). And the moment you open a plugin that needs re-approval — when its panel would otherwise just sit there loading, because the UI opens but its background half is dead — a toast fires that names the plugin ("GitHub needs your permission again") with a Re-approve button that jumps straight to its callout in Settings. The toast shows once per open, never stacks, and stays silent for a healthy plugin and on mobile (where a plugin backend can't run at all). All four surfaces (Settings, the Marketplace card + detail, and the toast) reuse ONE shared callout component and the existing translated strings — so they can never drift, and the recovery is reachable from wherever you are.

When an agent asks to install a plugin (the approval card)

An agent can request a plugin install over the CLI control server (POST /plugins/install). It cannot install anything on its own — the request becomes an approval card in your inbox, and nothing is downloaded until you approve it.

The card tells you what approving actually grants. It names the plugin, the exact version being installed, and the permissions that version is asking for. If you already have the plugin, the card reads as an update — Update plugin "Foo" from v1.4.0 to v2.1.0 — and lists only the permissions the new version wants that you have not already granted, the same "requests new" comparison the in-app Updates modal shows. An update that asks for nothing new says exactly that, so a card with no permission line never leaves you guessing whether it was checked. Every requested permission is listed; the card never abbreviates the list, because the order they appear in is chosen by the plugin's author and a shortened list could hide the one that matters.

This matters because asking to install a plugin you already have is how an update gets applied. Approving the card is what grants the new version's permissions, so the card has to say what they are.

Clicking Approve shows you what the plugin will be able to do, the same way the Marketplace does. Approving an agent's install request IS the consent — nothing prompts you a second time afterwards — so the confirm that opens lists each capability in plain words ("Storage — read and write plugin data, files, and database records"), flags elevated ones, and calls out separately that the plugin runs its own background program with access the permission list cannot limit. It is an amber caution, not a red destructive warning, because installing a plugin deletes nothing; it says so outright, and Enter defaults to Cancel so a stray keypress cannot grant anything. Turning a plugin on or off reads the same way. Uninstalling keeps the red warning, because it really does delete the plugin's files and everything it saved. If the capability list genuinely cannot be loaded, the confirm shows the card's own description instead of an empty list, so a failed lookup never reads as "this plugin asks for nothing".

If Omniscio can't describe the install, it won't ask you to approve it. A plugin id the marketplace doesn't carry, a marketplace it can't reach, or a listing it can't make sense of all refuse the request outright rather than raising a vague card. You will never be asked to approve an install described only as "runs third-party plugin code".

What you approve is what installs. The version named on the card is locked in. If the marketplace publishes a newer version while the card is sitting in your inbox, approving it does not quietly install that newer one — the install is refused and you are told to request it again, so you can see what the new version is asking for. A repair or reinstall of the same version is unaffected.

Installing from the Marketplace yourself is unchanged: you see the permissions on the detail page and in the consent dialog before you click, so there is no gap for the version to move in.

For agents

The rest of the Marketplace — what a plugin may read from your history and boards, what it can watch you doing, ratings and review submission, the error taxonomy, the developer and publisher surfaces, package signing, and the registry, install and IPC internals — is in Plugin Marketplace (part 2).

Related

Last verified 2026-09-29