---
title: App is already running, or frozen — restart the stuck copy
---

# App is already running, or frozen — restart the stuck copy

## What it is

### The short version

Omniscio only lets one copy run at a time. If you try to launch it while it's already open:

- **Normal case:** the copy already running comes to the front and you see a small notification, "Omniscio is already running — brought the existing window to the front." Nothing new opens because nothing needs to.
- **Frozen case (new):** if the copy already running has **frozen** — it's still there but has stopped responding — Omniscio now notices, and instead of doing nothing it shows you a dialog:

  > **Omniscio is not responding**
  > Omniscio is already running but has stopped responding.
  > *You can restart it now — this closes the frozen copy and opens a fresh one. Any unsaved work in the frozen copy may be lost.*
  > **[ Restart Omniscio ]  [ Cancel ]**

  Click **Restart Omniscio** and it force-closes the stuck copy, waits for it to fully exit, and opens a fresh, working one. Click **Cancel** and the launch simply closes (the frozen copy is left as-is).

### Why this exists

Before this, launching Omniscio while the running copy was frozen did **nothing at all** — no window, no message. It looked like the app "won't open," and the only fix was to hunt down the stuck process in Task Manager or reinstall. Now the app tells you what's wrong and offers a one-click fix. It also quietly records a diagnostic when this happens, so the problem can be investigated even though the frozen copy itself can't report anything.

And after an automatic restart, the fresh copy leaves a short, informational note in your inbox — *"Omniscio recovered from a freeze"* — so you have a durable, visible record that it happened. It needs no action (the app has already recovered); it's there so a one-off freeze isn't invisible and a repeating one is easy to spot.

## Where to find it

There is nothing to switch on or open — this is automatic, and it happens at the moment you launch Omniscio while another copy is already running. The running copy comes to the front with a small notification, or, if it has frozen, a dialog offers **Restart Omniscio** and **Cancel**. After an automatic restart, the record of it appears in your Inbox as the *"Omniscio recovered from a freeze"* note.

## How it behaves

### The safety rules (so it never restarts the wrong thing)

Force-closing a running program is a big hammer, so Omniscio is careful:

- **Won't mistake "busy" or "just starting" for "frozen".** A copy that's still starting up is never treated as frozen, and a busy one only counts as frozen after about 10 minutes with no sign of life (Omniscio's internal heartbeat has gone quiet). Even then it waits 30 seconds and checks again, and confirms the process really is Omniscio, before it records anything or shows the dialog.
- **Double-checks before closing anything.** When you click Restart, it re-confirms the copy is still frozen (if it recovered in the meantime, it tells you so and closes nothing) and verifies the process it's about to close is genuinely Omniscio — never some unrelated program.
- **Won't loop forever.** If restarting doesn't help and Omniscio keeps freezing, it stops offering to restart and instead says: *"Omniscio keeps freezing — please reinstall Omniscio or contact support."*
- **If it can't close the stuck copy** (for example your security software blocks it), it tells you plainly to close it from Task Manager (or restart your computer) rather than leaving you stuck.
- **The extra copy always closes itself.** Whatever you choose, the copy you just launched closes on its own once its diagnostic report has gone out, or been saved to send on the next launch. After a restart it waits only a few seconds, so the fresh copy isn't held up.
- **It respects your crash-email settings.** Before the extra copy sends its diagnostic, it reads your saved settings (without ever changing them), so if you've turned crash emails off, none is sent. A second launch also no longer wipes the running copy's crash record, so if that copy crashes later, the next start still notices.

### What this does NOT cover

If Omniscio won't open for a reason **outside the app itself** — a corrupted install, antivirus blocking it, a missing system component, or a graphics-driver problem — none of Omniscio's own code runs, so it can't show you anything. In that case a reinstall (or checking your antivirus/quarantine) is the right move.

## For agents

### Under the hood (for agents)

The single-instance gate ([single-instance.ts](../../src/main/app/single-instance.ts)) has a losing
(duplicate-launch) copy read the primary's heartbeat sentinel
([single-instance-liveness.ts](../../src/main/app/single-instance-liveness.ts)) to classify it
HEALTHY / HUNG / UNKNOWN — read-only, never touching the primary's state. A HUNG result is written
to a durable bootstrap-log line and routed (via `index.ts`) to a post-`whenReady` recovery handler
([hung-primary-recovery.ts](../../src/main/app/hung-primary-recovery.ts) +
[hung-primary-recovery-deps.ts](../../src/main/app/hung-primary-recovery-deps.ts)) that captures a
diagnostic, shows the dialog, and — on confirm — verifies-then-force-restarts. Every outcome then ends
the duplicate itself: it waits for its crash report to send or spool, bounded by the crash email's
give-up time (a few seconds on a restart), and exits (contract I17). That recovery runs in
the dying secondary, which has no database, so it can't raise a durable inbox card there; instead the
RELAUNCHED primary raises a deduped, informational `primary-hung-recovered` card on its next boot
([hung-recovery-boot-alert.ts](../../src/main/app/hung-recovery-boot-alert.ts), F054) — after the DB
is open, by reading the persisted restart-state within a tight recency window. Invariants:
[single-instance-liveness-contract.md](../../.claude/memory/contracts/single-instance-liveness-contract.md).

**When the lock is enforced (2026-07-23 fix).** The machine single-instance lock is keyed on the
isolated-instance marker `AMC_INSTANCE_ID`, NOT on `DATA_DIR`
([single-instance-policy.ts](../../src/main/app/single-instance-policy.ts)) — so a user who
relocated their data dir with `DATA_DIR` (e.g. to another drive) is still their PRIMARY and keeps
single-instance protection: a second launch can't run two copies on one database. Only a
deliberately-isolated NAMED instance (E2E `AMC_INSTANCE_ID=e2e`, the sandbox `claude-sandbox`) skips
the lock and coexists (contract I10). Separately, a developer `npm run dev` that finds a HEALTHY
primary already running on the same data dir hands off to the in-app restart instead of stacking a
second copy — the "restart shortcut = restart" path
([dev-single-instance.js](../../scripts/lib/dev-single-instance.js) →
[electron-dev.js](../../scripts/electron-dev.js)). That hand-off is GUARDED: it fires ONLY for an
interactive human launch — an agent-initiated (`AMC_SESSION_ID` set) or non-interactive (no TTY)
`npm run dev` is DECLINED (it exits cleanly without a second copy and raises a `dev-relaunch-blocked`
inbox card naming the source session), so a stray agent/script `npm run dev` can never silently
restart the user's live app. A stale/hung sentinel or unreachable CLI server falls through to a
normal launch where the lock is the backstop; kill switch `AMC_DISABLE_DEV_RELAUNCH_TAKEOVER`
(contract I11).

### The dev launcher and a frozen app (developers running `npm run dev`)

**The plain version.** The program that starts the app in development (`npm run dev`) also
restarts it when a build-config file changes on disk. It asks the app to restart politely, and if
the app cannot answer it now checks the app's heartbeat, the "I am alive" note the app writes every
5 seconds, before doing anything drastic. A fresh heartbeat means the app is just busy, so it is
left alone. A heartbeat that has gone quiet while the app's process is still there means the app is
**frozen**: the launcher waits, checking every 10 seconds for up to 30 minutes, asks politely again
the moment the app thaws, and never force-closes it. Only an app whose process is genuinely gone
gets cleaned up. If a restart was accepted, the pre-launch checks that run before the relaunch now
have a 15-minute limit, so a stuck check can no longer leave the app dead for the evening. Pressing
Ctrl+C while those checks are running stops them at once and the app is not relaunched — the
launcher writes down that it skipped the relaunch on your request. And every one of these decisions
is written to a log file, so an outage is never a mystery afterwards.

**For agents.** [electron-dev.js](../../scripts/electron-dev.js) `requestConfigRestart` reads
`devAppLiveness` (alive / frozen / gone / unknown, from
[dev-single-instance.js](../../scripts/lib/dev-single-instance.js) `classifyDevAppLiveness`) and
waits out `frozen` (`awaitThawOrGone`, 10 s polls, 30 min cap, `'deferred'` past the cap, a
required `shouldAbort` tied to the child); the relaunch refresh is bounded by
`AMC_DEV_PREDEV_TIMEOUT_MS` (default 15 min, `0` = none) and abortable (`shutdown()` fires the
`AbortController` behind `refreshForRelaunch`; a relaunch during shutdown is a `relaunch-skipped`
row); decisions go to `~/.amc/dev-crash-forensics.log` through
[dev-supervisor-log.js](../../scripts/lib/dev-supervisor-log.js), every kind a value of its
`SUPERVISOR_EVENT_KIND` map.
Invariants: [restart-amc-contract.md](../../.claude/memory/contracts/restart-amc-contract.md) I5 /
I8(d) / I19. A launcher change takes effect only at the next top-down `npm run dev` — the running
launcher keeps the code it loaded at start.

## Related

Sibling pages on the same machinery: [crash-recovery.md](crash-recovery.md) covers what
Omniscio does with your sessions after an unexpected exit, [blank-screen-recovery-button.md](blank-screen-recovery-button.md)
covers recovering a window that comes up blank, and [main-heartbeat.md](main-heartbeat.md) documents
the heartbeat the freeze classification reads.
