English · 简体中文
Arm one or more opencode sessions, give them an end time, then go to sleep. Night-shift keeps them working — and stops on schedule.
Install · Quick start · Configuration · How it works · FAQ
There are already several auto-continue / loop plugins for opencode (opencode-auto-resume, opencode-loop, goal-mode plugins). They answer "don't stop". Night-shift answers a different question: "work a shift for me."
| Typical auto-continue / loop | Night-shift | |
|---|---|---|
| Stop condition | run forever / until a goal is done | until an end time (endTime, e.g. 08:30) |
| Sessions | usually one | many sessions in one shift, counted per session |
| Message | fixed "continue" | template with real-clock anchors ({time} / {remaining}) |
| Busy sessions | few handle it | checked before every send — never queues into a running turn |
| Completion | global stop | removes just that session, the rest keep working |
| Dependencies | varies | zero |
Typical use: hand your overnight work to a shift, sleep, and in the morning read night-shift.log to see how many times each session was picked up and when the shift ended.
- Shift window —
enabled+endTime; the shift stops globally when the time is reached. - Multi-session — supervise several sessions at once; a completion marker removes only that session.
- Real-clock anchors —
{time}/{remaining}are rendered from the actual local clock, which also helps against "it must be morning by now" hallucinations. - False-positive guards — the plugin never reacts to its own messages;
别收工("don't stop") does not stop; completion markers are only recognized on the last line (markdown bold and full-width brackets tolerated). - Busy-aware — skips a session while it is
busy/retryingand resumes on the next idle. - No session aborts — the plugin never kills a running turn; stalled-session recovery is left to specialists.
- Fast checks — tracks the last assistant message via
message.updatedand fetches only that one (fallback: full list). - Tested — 22 unit tests, CI on Linux + Windows × Node 20/22.
Requirements: opencode (plugin API @opencode-ai/plugin 1.18.x), Node ≥ 20. No runtime dependencies.
Option A — from npm (recommended)
Option B — manual
Copy src/night-shift.js into ~/.config/opencode/plugins/ and restart opencode.
Data lives in:
- running from a source checkout →
<repo>/data/ - installed from npm →
~/.local/share/opencode-night-shift/
Both can be overridden with OC_NIGHT_DIR.
Create (or edit) night-shift.json in the data directory — the plugin hot-reloads on file changes, no restart needed:
{
"enabled": true,
"endTime": "08:30",
"message": "Now {time} ({remaining} left).\n\nContinue the task: do not stop, do not wait for user input.\nIf everything is done, review or run tests to verify.\nWhen fully verified, end your last line with: [task done]",
"sessions": [
{ "id": "ses_your_session_id", "sent": 0, "lastSentAt": 0 }
]
}Find session IDs in opencode (they are ses_...), or use the optional web dashboard to tick sessions and set the shift.
Stopping a shift — any one of:
- the clock reaches
endTime(global stop) - a short message starting with a stop phrase in any watched session:
收工/先收工吧/停止夜班,睡觉了(别收工will not trigger it) - the model ends its last line with
[夜间任务完成]/[task done](that session only)
Watch it work — night-shift.log in the data directory records every continuation, skip reason, and stop.
| Field | Description |
|---|---|
enabled |
shift on/off |
endTime |
local HH:MM; global stop at that time |
endAt |
absolute epoch ms — optional, derived from endTime when omitted |
message |
continuation template ({time} {remaining} supported) |
sessions[] |
{ id, sent, lastSentAt } per watched session |
Environment variables:
| Variable | Default | Description |
|---|---|---|
OC_NIGHT_DIR |
see above | data directory |
OC_NIGHT_CONFIG / OC_NIGHT_LOG |
inside it | override config / log path |
OC_NIGHT_DELAY_MS |
15000 |
wait before sending after a session goes idle |
OC_NIGHT_MIN_INTERVAL_MS |
30000 |
minimum gap between two continuations in one session (blocked idles are retried, never dropped) |
OC_NIGHT_SHIFT |
— | set to 0 to disable the plugin entirely |
The plugin subscribes to three event types:
session.idle— is this session armed? was the last turn an error (leave it to a network-recovery plugin)? does it end with a completion marker? if not → send the template after a short delay.session.status— trackbusy/retryper session and re-check right before sending, so a continuation never queues into a running turn.message.updated— remember the last assistant message id so the check fetches a single message instead of the whole history.
Config I/O is multi-process friendly: BOM tolerance, unknown-field preservation, legacy-format migration, mtime-based hot reload.
| Situation | What you do |
|---|---|
| Overnight refactor or long build/fix loop | arm the session, set endTime: 08:30, sleep |
| Several agents running in parallel | arm all of them — each gets its own counter and completion state |
| Want a morning report | read night-shift.log (or the dashboard) when you wake up |
| Keep a session alive but stop before a deadline | endTime gives you a hard stop instead of an infinite loop |
Important
Night-shift makes no network requests, only reads/writes three local files, and never aborts a running session. It can, however, send messages into sessions — with a permissive permission setup a continued session may run commands, exactly like a normal user turn. Use the stop phrases or endTime if a shift should end early.
- Does it kill stuck sessions? No. Recovery for frozen streams belongs to dedicated plugins; night-shift deliberately never aborts your long-running work.
- Does it upload anything? No. Local files only.
- Does it conflict with network-error auto-resume plugins? No — night-shift skips turns that ended in an error and leaves them to those plugins.
- Logs and messages are Chinese? Defaults are Chinese;
messageis a template you can write in any language, and the completion marker accepts[task done].
npm test # node:test — 22 casessrc/night-shift.js plugin (zero dependencies)
test/night-shift.test.mjs unit tests with a mock opencode client
.github/workflows/ci.yml CI: Linux + Windows × Node 20/22
Contributions are welcome. Please keep changes covered by tests and keep README.md / README.zh-CN.md in sync.