ANDREW PIEPLOW

NIGHTSHIFTI got tired of babysitting AI coding sessions.

Claude and Codex could do a lot of the coding, but the project around them was still fragile. Sessions ended. Limits got hit. Context disappeared. A worker would say something was done, and I still had to figure out whether it actually worked. So I started building Nightshift to keep the work organized even when the AI, terminal, or session changes.

WORKER_DONE != VERIFIED
In plain EnglishNightshift remembers the job, gives AI workers isolated places to work, keeps track of what happened, checks the result separately, and lets interrupted work continue instead of starting over.
Core stack
TypeScriptBunGit WorktreestmuxClaude CodeCodexMCPVitest
01 / Why I built it

The annoying part wasn't getting AI to write code.

The annoying part was everything I still had to remember and babysit around it: what the goal was, which worker was doing what, whether two jobs could collide, what had already failed, whether “done” really meant done, and how to recover when a long session stopped halfway through.

I wanted the project to survive the model session, instead of the model session becoming the project.
01

Remember the job

The mission and task history live outside the AI conversation.

02

Swap workers

Claude or Codex can do the work without owning the project state.

03

Keep changes apart

Each coding task gets its own Git worktree instead of sharing one messy checkout.

04

Check the answer

A worker saying “done” starts validation. It does not end it.

05

Pick up later

Attempts, events, handoffs, and recovery state are saved so the work can resume.

The actual Nightshift interfaceREAL CAPTURE / NOT A MOCKUP
Actual Nightshift Terminal Reality interface capture
The UI shows the same mission and worker state Nightshift is actually tracking. It is not a fake activity animation layered on top.click to inspect
HOW I BUILT IT: This project is heavily AI-assisted. I use Claude Code and Codex as coding and review workers. I decide what problem they are solving, give them the constraints, inspect the result, reject bad work, change direction, and define the acceptance bar. Hiding that would make the project sound less true, not more impressive.
02 / What was hard

Four things I cared about enough to design around.

These started as practical annoyances, not architecture buzzwords. The technical design came afterward.

01

I didn't want the AI grading its own homework.

TECHNICAL DECISION → WORKER COMPLETION AND VERIFICATION ARE DIFFERENT STATES

When a coding worker finishes, Nightshift moves the work to validation. Tests, repository checks, and independent review determine whether it becomes verified.

COST: more steps and more time. BENEFIT: “the agent said it worked” is never the acceptance test.
02

I wanted to switch models without losing the project.

TECHNICAL DECISION → KEEP MISSION STATE OUTSIDE THE PROVIDER SESSION

Claude, Codex, and future workers sit behind adapters. The objective, tasks, attempts, evidence, and history belong to Nightshift, not to whichever model happens to be running.

COST: adapter code and normalization. BENEFIT: the mission can outlive the worker.
03

I didn't want one bad run trashing everything else.

TECHNICAL DECISION → ONE GIT BRANCH / WORKTREE PER CODING TASK

Workers get isolated repository state. Verified commits can move toward an integration branch in order, while unrelated changes stay contained.

COST: more Git bookkeeping. BENEFIT: containment, provenance, and rollback.
04

I wanted to close the laptop and still know what happened.

TECHNICAL DECISION → DURABLE FILE STATE + EVENT HISTORY + PERSISTENT SESSIONS

Mission, task, attempt, and event data are written durably, while tmux keeps worker sessions attachable. Recovery is something the system knows about, not something I have to reconstruct from memory.

COST: state management. BENEFIT: long-running work becomes resumable instead of disposable.
03 / How it works

A run is pretty simple when you strip the jargon away.

There is AI in the system, but I intentionally did not make every decision an AI decision. Once a plan is approved, ordinary deterministic code owns as much of the execution lifecycle as practical.

1. GIVE IT A GOAL
objective

The job is written down independently of any one conversation.

2. BREAK IT INTO WORK
mission + tasks

An AI planner can help propose the task graph, but Nightshift validates the structure before execution.

3. PICK A WORKER
scheduler + worker adapter

Nightshift chooses an allowed worker based on the task and availability instead of handing over the whole mission.

4. GIVE IT A SAFE PLACE TO WORK
Git branch + worktree

The coding task happens in isolated repository state with its own provenance.

5. CHECK THE RESULT
validation

Tests, build, typecheck, targeted checks, and review evidence decide whether the work is actually acceptable.

6. RECOVER OR MOVE FORWARD
retry · rework · integration

Failures stay classified. Good work can move forward. Interrupted work can be resumed. Nothing silently merges the default branch.

04 / Does it actually work?

I made Nightshift use Nightshift.

For Run 10, I gave the system a small real change to its own codebase: add JSON output to nightshift doctor. The feature was intentionally boring. The point was to see whether the whole workflow could operate on itself without cheating.

Dogfood run / PASS

Add --json to the doctor command.

Nightshift accepted the objective through its bounded operator interface, compiled the mission, launched a worker in an isolated worktree, ran the validation path, and produced a verified commit. The result was pushed and deliberately left unmerged.

goal ↓ Nightshift creates the mission ↓ worker gets an isolated worktree ↓ change is implemented ↓ independent validation runs ↓ VERIFIED COMMIT 3beabca
RESULTPASS — all five acceptance gates closed
FINAL TESTS1,747 pass / 0 fail / 4 skip across 145 files
ADAPTER CHECKS131 / 131
TYPECHECK / BUILDpass / pass
FINAL REVIEWzero unresolved severity-1/2 defects
FAILURE TESTSduplicate launch, stage-hash mismatch, and already-launched protections exercised
SECRET SCANtracked diff + artifacts clean except synthetic redaction canaries
DEFAULT BRANCHuntouched
1,747 / 0tests passed / failed
131 / 131adapter checks
5 / 5acceptance gates
0unresolved S1/S2 findings
05 / Where it is now

Some of it is real today. Some of it is still the plan.

I would rather show the line clearly than make the project sound further along than it is.

Working / validated

What exists now

Durable mission, task, attempt, and event state
Deterministic post-plan scheduler
Claude / Codex worker adapter model
Git branch and worktree isolation
Independent validation and rework lifecycle
Persistent tmux-backed worker sessions
Ten-tool bounded MCP operator interface
Terminal Reality UI driven by actual state
Still building / deliberately deferred

What's next

Owner-authentication hardening for remote/operator access
Broader memory and intentions layer
More provider families and independent reviewer paths
Proactive events and richer Personal OS behavior
Voice and broader interface options
Anything resembling autonomous default-branch merges
Cloud platform / giant generic agent framework
06 / One safety choice I like

The remote window is intentionally small.

I wanted Nightshift to be operable from another interface without handing that interface a raw shell or the keys to the machine. So the operator bridge exposes ten named things it can ask Nightshift to do, and leaves arbitrary shell, filesystem, and SQL access out.

status
needs_you
resolve
context
query
work
control
authority
artifact
capabilities
The bridge cannot simply invent approval authority. Mutating requests are bounded and idempotent, responses are redacted/bounded, and the local HTTP surface is loopback-only with host/origin checks. The next hardening step is stronger owner authentication before broader remote use.
The whole idea

Make the AI less fragile, not more magical.

Nightshift started because I was already using AI coding tools constantly and kept running into the same operational problems. I am not trying to prove that an agent can run a company by itself. I am trying to make long-running AI-assisted work easier to trust, resume, inspect, and recover when real life happens.