---
title: Restart offer (when a sync pulls new code under a running dev app)
---
# Restart offer (when a sync pulls new code under a running dev app)

## What it is

When you run Omniscio from source, the app keeps running the code that was on disk when it started — so a background sync can pull newer code underneath it with nothing on screen changing. The restart offer is how Omniscio tells you that happened and lets you choose when to pick the new code up, instead of restarting on you.

## Where to find it

There is nothing to open or configure: the offer appears on its own inside the running app when a background sync pulls new code underneath it.

## How it behaves

### What problem this solves

Running Omniscio from source (`npm run dev`), the app builds whatever is on disk when it
starts. If you also run the 2-hourly **Sync Master** job, that job then rewrites those same
files underneath the running app — it pulls the latest `master` into your checkout.

Nothing about that reaches the window you are looking at. Backend changes make the dev
launcher relaunch the app on its own, but a change to the interface does not (live UI
swapping is deliberately off in this repo so the dev window stays stable). So you can sit
on hours-old code with nothing telling you, and the only reliable fix — restarting — is
something you had to think to do.

The obvious fix is worse than the problem: an automatic restart is an unannounced outage of
several minutes (the app shuts down, the launcher rebuilds the latest code, and the app boots
again). So Omniscio **offers**, and you decide.

### What Omniscio does

When the 2-hourly Sync Master finishes a clean sync that **actually advanced** your local
`master`, it raises one inbox card:

> **2 new commit(s) synced — restart to use them**
> Sync Master just pulled 2 new commit(s) into this checkout, but the app is still running
> the code it started with.
> Nothing restarts unless you say so — this is only an offer. Ignore or archive this card
> and the app keeps running exactly as it is.

The card carries one button, **Restart now**. Pressing it opens the same *"Restart
Omniscio?"* confirmation the header's restart button uses — the one that warns the app will
be gone for a few minutes while it rebuilds, that it reopens by itself, and that your running
sessions come back automatically. Nothing happens until you confirm.

- **Confirm** → Omniscio quits gracefully (saving your running sessions for auto-resume),
  the dev supervisor rebuilds and relaunches, and the card archives itself so you are never
  left looking at a stale offer. There is nothing to start by hand: if you run `npm run dev`
  while the restart is still on its way, it simply says the app is already restarting and
  exits, rather than starting a second copy that would race the relaunch.
- **Cancel** → nothing at all happens, and the card stays put for later.
- **Ignore or archive it** → nothing at all happens. The app keeps running as it is.

The card is deduplicated, so a repeat sync updates the same row instead of stacking a new
card every two hours.

### When you will NOT see it

The card only appears when a restart would genuinely help and would genuinely work. It stays
silent when:

- the sync found nothing new (you are already current);
- the sync was skipped (uncommitted changes, or you are not on `master`), or failed;
- the sync had to auto-recover from a conflict — that already raises its own card, and two
  cards about one event is noise;
- the run was a read-only `--check` or a manual `--recover`;
- there is no dev restart supervisor — most importantly **a packaged install**, where there
  is no `npm run dev` to relaunch and the button could only refuse.

That last one is why this is a developer-facing feature: on a normal packaged install of
Omniscio, nothing is rewriting your code underneath you, so the card never appears.

### Why it can only ever ask

The button does not restart anything itself. It dispatches the same internal request the
header's restart button sends, and a single app-level owner shows the one confirmation
dialog and performs the restart. That indirection is deliberate: anything that can post an
inbox alert could raise a card carrying this button, so the button is built so that a card
can never restart the app without a human clicking it **and** confirming. The separate
command-line restart route stays owner-gated off by default and is untouched by this.

## Related

- [restart-attribution.md](restart-attribution.md) — why no restart is ever anonymous.
- Contract: `restart-amc-invariants-mechanism-contract` (`I11`) · `inbox-alert-contract` (I20).
