I shipped NightCrew — an overnight task runner for Claude Code.
The pitch is simple: write your tasks in tasks.yaml, run ./nightcrew.sh run before bed, wake up to draft PRs with plans, decision logs, and review reports attached.
What it does per task:
- Plan (Opus) — scope challenge, architecture review, test coverage plan, failure mode analysis. Saves
PLAN-{task-id}.md. - Implement (Sonnet) — follows the plan, writes code, runs tests, logs judgment calls to
DECISIONS-{task-id}.md. - Review (Sonnet) — pre-landing review, auto-fixes mechanical issues, logs concerns to
REVIEW-{task-id}.md.
Then it commits, pushes, opens a draft PR, and moves to the next task. Each task runs in its own git worktree, so they can't stomp on each other.
A real tasks.yaml entry:
tasks:
- id: per-project-protected-branches
title: "Per-project protected_branches override on tasks"
branch: feat/per-project-protected-branches
type: implementation
complexity: medium
files_in_scope:
- schemas/task.schema.json
- lib/00-common.sh
- tests/protected-branches.bats
test_command: "bats tests/"
files_in_scope is a hard fence — anything Claude writes outside it gets reverted before commit. Seven guardrails total: tool whitelists per task type, blocked ops (rm, sudo, force-push), branch protection, file scope, per-task timeouts, cost cap, secret scanning.
Output of a recent run, straight from state/progress.json:
{
"session_id": "2026-04-17T143100Z",
"total_cost_cents": 287,
"total_input_tokens": 78400,
"total_output_tokens": 21900,
"tasks": {
"per-project-protected-branches": {
"status": "complete",
"pr_url": "https://github.com/oluoyefeso/nightcrew/pull/12"
},
"broaden-tool-whitelist": {
"status": "complete",
"pr_url": "https://github.com/oluoyefeso/nightcrew/pull/13"
}
}
}
$2.87, two PRs, one night.
The clearest proof it works: NightCrew shipped its own v0.4.0.0 release. Two overnight runs queued four feature tasks against the NightCrew repo itself — run lockfile, preflight gitignore validation, per-project protected branches, broadened tool whitelists. Four draft PRs (#10–#13) waiting in the morning. Reviewed, merged, ran the next batch the following night.
Single bash script. No daemon, no database. The whole runtime is bash + jq + yq + gh + claude.
Source on GitHub. Next post is about cutting the token bill on overnight runs by ~21% — caveman prompts.