---
title: Night Shift (a queued plan of work that runs while you sleep)
---

# Night Shift (Overnight Task Sequencer)

## What it is

### What it is

Night Shift is Omniscio's overnight task orchestration layer. You define a **plan** — an ordered list of **phases** — and Night Shift runs them sequentially, one at a time, while you sleep. Each phase can wait for sessions to finish, spawn batches of new sessions, spawn fix sessions from audit findings, delay for a set time, or run a recipe.

The sequencer ticks every 60 seconds. Progress appears as an inbox card. When the plan completes, a summary card shows per-phase outcomes, total sessions spawned, cost, and duration.

## Where to find it

The **Night Shift panel** in the app, which shows the plan and its progress; a plan is started by asking a session to queue one, or from the control server.

## How it behaves

### How to use it

### UI — Plan Builder

Open the Night Shift panel (sidebar) and switch to the **Builder** tab. A 3-step wizard walks you through creating a plan:

1. **Metadata** — plan title and watchdog stall minutes (how long before a stall alert fires)
2. **Phases** — add phases, pick a type, configure each one, reorder with move-up/move-down buttons
3. **Review** — summary card showing all phases; click **Create Plan** to submit

The new plan appears in the Plans tab immediately. All 5 phase types are supported in the builder: delay, wait for sessions, spawn batch, spawn from findings, and run recipe.

### CLI API

All routes require the Omniscio bearer token. Base URL: `http://127.0.0.1:19519`.

### Create a plan

```
POST /night-shift/plans
```

Body:

```json
{
  "title": "Nightly audit + fixes",
  "watchdogStallMinutes": 30,
  "phases": [
    {
      "title": "Wait for NightyTidy",
      "type": "wait_for_sessions",
      "config": { "sessionIds": ["session-id-here"] }
    },
    {
      "title": "Spawn fixes for critical findings",
      "type": "spawn_from_findings",
      "config": { "sourcePhaseIndex": 0, "severityFilter": ["critical", "high"] }
    },
    {
      "title": "Delay 1 hour",
      "type": "delay",
      "config": { "minutes": 60 }
    },
    {
      "title": "Run MC test scenarios",
      "type": "spawn_batch",
      "config": {
        "tasks": [{ "prompt": "Run scenario 1", "projectId": "proj-id", "label": "Scenario 1" }],
        "concurrency": 5
      }
    }
  ]
}
```

Returns `{ ok: true, data: { planId, phaseIds } }` with status 201.

### Start a plan

```
POST /night-shift/plans/:id/start
```

Returns 409 if another plan is already running (only one plan runs at a time).

### Check plan status

```
GET /night-shift/plans/:id
```

Returns the plan with all its phases, including current status, session IDs, and results.

### List plans

```
GET /night-shift/plans?status=running
```

Optional `status` filter: `created`, `running`, `completed`, `stalled`, `aborted`.

### Abort a plan

```
POST /night-shift/plans/:id/abort
```

Stops phase advancement. Does NOT kill any sessions that are already running.

### Phase types

| Type                  | Config                                                                                 | What it does                                                                          |
| --------------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| `wait_for_sessions`   | `{ sessionIds: string[] }`                                                             | Watches sessions until all reach a terminal status                                    |
| `spawn_batch`         | `{ tasks: [{prompt, projectId, label?}], concurrency?: number, maxFailures?: number }` | Spawns sessions one per tick up to concurrency limit                                  |
| `spawn_from_findings` | `{ sourcePhaseIndex: number, severityFilter?: string[] }`                              | Reads a prior phase's session output, finds findings by severity, spawns fix sessions |
| `delay`               | `{ minutes: number }`                                                                  | Waits for the specified duration (restart-safe, stored in DB)                         |
| `run_recipe`          | `{ recipeId: string, targetProjectId: string, customMessage?: string }`                | Triggers a recipe run and waits for it to complete                                    |

### Auto-monitoring (scoped to the plan's sessions)

While a plan runs, Omniscio keeps the plan's sessions moving overnight — without waiting on you, and without touching your other sessions:

- **Auto-continue** — a plan session that stops mid-task is nudged onward instead of parking as "Needs You"
- **Auto-nudge** — a plan session that sits waiting gets a periodic check-in
- **Session health monitor** — a plan session that stalls is detected and recovered

This covers two kinds of sessions:

1. **Spawned sessions** — sessions the plan itself created (from its `spawn_batch` / `spawn_from_findings` phases), identified by `source: 'night-shift'`
2. **Watched sessions** — pre-existing sessions that a `wait_for_sessions` phase is watching, identified by their presence in an active or pending wait phase's session list

Your unrelated sessions are **never** auto-continued, nudged, or health-checked just because a plan is running, and your own global monitoring switches are left exactly as you set them. If you keep those features on globally for yourself, every session is covered as usual; if you keep them off, only the plan's sessions are driven while it runs. When no plan is active, behavior is exactly your own global settings.

This is controlled by the **Auto-enable monitoring** setting (`nightShiftAutoMonitoringEnabled`, default on). Turn it off and Night Shift won't drive even its own sessions.

> Earlier builds enabled these three settings **globally** for every session while a plan ran (snapshotting and restoring your values around the plan). That's been replaced by the scoped behavior above so an overnight plan never changes how your unrelated sessions behave. A one-time cleanup on upgrade restores any values a previous build had left enabled.

### Stall detection

If a phase shows no progress for `watchdogStallMinutes` (default 30), a warning alert appears in the inbox. The alert clears when progress resumes.

### In-app panel

Night Shift has a panel in the sidebar (Automation group) with two tabs:

- **Plans** — lists all plans with status badges, cost, and elapsed time. Desktop uses a master/detail split; mobile uses single-column with a back button. Selecting a plan shows its phases timeline with per-phase status, duration, cost, and session count. Auto-refreshes every 30 seconds.
- **Settings** — toggle for auto monitoring (scoped driving of the plan's own sessions while it runs).

### Example: NightyTidy audit workflow

1. Start NightyTidy in a session manually
2. Create a Night Shift plan:
   - Phase 1: `wait_for_sessions` — wait for the audit session
   - Phase 2: `spawn_from_findings` — auto-fix critical/high findings
   - Phase 3: `delay` — wait 1 hour for fixes to settle
   - Phase 4: `spawn_batch` — run integration test scenarios
3. Start the plan and go to sleep
4. Check the completion summary in the inbox the next morning

## Related

- [cron-session-jobs.md](cron-session-jobs.md) — recurring scheduled work, for jobs that repeat rather than run once.
- [automations-and-auto-replies.md](automations-and-auto-replies.md) — the automation engine a Night Shift plan can sit on top of.
- [nighty-tidy-2.md](nighty-tidy-2.md) — the overnight audit workflow the worked example on this page walks through.

