@johndaskovsky/nightshift
v4.0.1
Published
Deprecation shim for the Nightshift CLI. Nightshift is now distributed as a Claude Code plugin — install via /plugin marketplace add johndaskovsky/nightshift.
Maintainers
Readme
* . . . * . +
_ _ _ _ _ ____ _ _ __ _ *
| \ | (_) __ _| |__ | |_ / ___|| |__ (_)/ _| |_ .
| \| | |/ _` | '_ \| __| \___ \| '_ \| | |_| __| (
| |\ | | (_| | | | | |_ ___) | | | | | _| |_ *
|_| \_|_|\__, |_| |_|\__| |____/|_| |_|_|_| \__|
* |___/ . + . *Long-running unsupervised agent framework
A batch processing framework for AI agents. Define a table of items, write task instructions, and let a manager-plus-dev system work through them autonomously with built-in retries, self-improvement, and self-validation.
Nightshift runs inside Claude Code as a manager subagent that dispatches dev work as fresh top-level claude -p subprocesses. Dev subprocesses inherit your full user-level MCP configuration — any MCP you've installed in Claude Code (Slack, Drive, Playwright, internal company MCPs) is automatically available to every Nightshift task. Nightshift is distributed as a Claude Code plugin via its own marketplace.
How It Works
A shift is a batch job. It contains a CSV table of items to process and one or more task definitions that describe what to do with each item. Two roles collaborate to execute the work:
- Manager (a Claude Code subagent) -- reads shift state, picks the next item, dispatches dev work as a
claude -psubprocess via the bundleddispatch-batch.shhelper, applies step improvements from successful dev runs (unlessdisable-self-improvement: trueis set), and reports progress. Writesmanager.mdand task files; readstable.csvfor status information. - Dev (a fresh top-level Claude session per item) -- executes task steps on a single item, self-validates, retries up to 3 times, reports step improvement recommendations (unless self-improvement is disabled), and writes its own status to
table.csv(doneon success,failedon failure). Because each dev runs as a top-levelclaude -psubprocess, it sees every user-configured MCP without any Nightshift-specific setup.
Each item-task moves through a state machine:
todo --> done
\
-> failedPrerequisites
- Claude Code v2.1.83 or later (for
--permission-mode auto; see the Permission mode section for the fallback path on older versions or non-eligible plans). - qsv CSV toolkit (required) -- install via
brew install qsvor download from GitHub releases for non-Homebrew platforms - flock file locking utility (required) -- install via
brew install flockor use the version bundled withutil-linuxon Linux - jq JSON processor (required by
dispatch-batch.sh) -- install viabrew install jq
Installation
Inside Claude Code, add the marketplace and install the plugin:
/plugin marketplace add johndaskovsky/nightshift
/plugin install nightshift@nightshiftAfter install, restart Claude Code if it's already running (so the new skills are discovered), then verify your system has the required dependencies:
/nightshift:doctorThe doctor skill checks for qsv, flock, and jq on PATH. It prints brew install hints for any that are missing.
You're ready when /nightshift:doctor reports all three present. Move on to Quick Start.
Permissions
Nightshift's skills declare the Bash commands they need (qsv, flock, claude, jq) via allowed-tools frontmatter. Claude Code should honor these declarations automatically. If you see repeated permission prompts during a shift, add the entries to ~/.claude/settings.json once:
{
"permissions": {
"allow": ["Bash(qsv *)", "Bash(flock *)", "Bash(claude *)", "Bash(jq *)"]
}
}Updates
Marketplaces auto-update on Claude Code startup. To pull the latest plugin version manually:
/plugin marketplace updateDeprecated: npm CLI
Earlier Nightshift versions (1.x–3.x) shipped as the npm package @johndaskovsky/nightshift with a nightshift init command. This path is deprecated as of 4.0.0. The npm package still exists but nightshift init only prints these instructions and exits. Migrate to the plugin install path above.
If you have a previous project-local install (<project>/.claude/skills/nightshift-*/), it will shadow the plugin via Claude Code's skill precedence. Delete those directories from your projects to let the plugin take over. Your .nightshift/<shift>/ data is unaffected.
Quick Start
All commands run inside Claude Code.
1. Create a shift
/nightshift:create my-batch-jobThis scaffolds .nightshift/my-batch-job/ with a manager.md and an empty table.csv. Add data to the table. The items should have all of the metadata needed to process the tasks.
2. Add a task
/nightshift:add-task my-batch-jobThe command asks you to describe what the agent should do, what tools it needs, step-by-step instructions, and how to verify success. It creates a task file (e.g., create_page.md) with three sections:
## Configuration
- tools: playwright
## Steps
1. Navigate to {ENV:BASE_URL}{path}
2. Click the "Add Page" button
3. Fill in the title field with {page_title}
4. Click "Publish"
5. Save a screenshot to {SHIFT:FOLDER}screenshots/
## Validation
- Page exists at the expected URL
- Page title matches {page_title}Steps use template variables that get substituted before execution. Three types are supported:
{column_name}-- item data fromtable.csv(e.g.,{url},{page_title}){ENV:VAR_NAME}-- values from the shift's.envfile (e.g.,{ENV:BASE_URL},{ENV:API_KEY}){SHIFT:FOLDER}/{SHIFT:NAME}/{SHIFT:TABLE}-- shift metadata (directory path, shift name, and table file path)
See Template Variables for details.
3. Add items to the table
/nightshift:update-table my-batch-jobAdd rows with the metadata columns your tasks reference. The resulting table.csv looks like:
url,page_title,create_page
https://example.com/site1,Welcome,todo
https://example.com/site2,About Us,todo
https://example.com/site3,Contact,todoEach task gets a status column initialized to todo.
4. Run the shift
/nightshift:start my-batch-jobThe manager agent takes over: it reads the table, picks the next todo item, delegates to the dev agent, updates statuses, and loops until everything is done or failed.
5. Test a single task (optional)
/nightshift:test-task my-batch-jobRuns one task on one item through the dev agent without modifying any state. Useful for debugging task definitions before running a full shift.
6. Archive a completed shift
/nightshift:archive my-batch-jobMoves the shift to .nightshift/archive/YYYY-MM-DD-my-batch-job/.
Commands Reference
| Command | Purpose |
|---------|---------|
| /nightshift:create <name> | Scaffold a new shift directory with manager.md and table.csv |
| /nightshift:add-task <name> | Add a task definition to an existing shift |
| /nightshift:update-table <name> | Add rows, update metadata, or reset failed items |
| /nightshift:start <name> | Begin or resume shift execution |
| /nightshift:test-task <name> | Dry-run a single task on a single item |
| /nightshift:archive <name> | Move a completed shift to the archive |
All commands accept a shift name as an argument, or prompt interactively if omitted.
Shift Structure
.nightshift/
my-batch-job/
manager.md # Shift config: name, task order, progress counters
table.csv # Items and their per-task statuses
.env # Optional: environment variables for this shift (gitignored)
create_page.md # Task definition (Configuration, Steps, Validation)
update_cms.md # Another task definition
archive/
2026-02-08-old-job/ # Archived shift (date-prefixed)manager.md
Tracks task execution order and progress. Updated automatically by the manager agent.
## Shift Configuration
- name: my-batch-job
- created: 2026-02-08
# - parallel: true
# - current-batch-size: 2
# - max-batch-size: 10
# - disable-self-improvement: true
## Task Order
1. create_page
2. update_cmsThe parallel, current-batch-size, max-batch-size, and disable-self-improvement fields are optional. See Parallel Execution and Self-Improvement for details.
table.csv
Each row is an item. Metadata columns hold the data tasks need. Status columns (one per task) track progress.
url,page_title,create_page,update_cms
https://example.com/site1,Welcome,done,done
https://example.com/site2,About Us,todo,todo
https://example.com/site3,Contact,todo,todoStatus values: todo, done, failed.
Task files
Each task has three sections. Only the Steps section is modified during execution (by the dev agent's self-improvement loop).
| Section | Purpose | Mutable by Dev | |---------|---------|----------------| | Configuration | Declares tools and optional model | No | | Steps | Numbered instructions with template variable substitution | Yes | | Validation | Independently verifiable success criteria | No |
Execution Details
Item processing order
The manager iterates items in order, tasks in the order listed in manager.md. Tasks within an item are sequential -- task 2 cannot start until task 1 is done. A failed task blocks all subsequent tasks for that item.
Dev agent retry loop
The dev agent gets up to 3 attempts per item (1 initial + 2 retries). On each attempt it:
- Substitutes all template variables from the current item, environment, and shift metadata
- Executes steps sequentially, stopping on failure
- Identifies step improvement recommendations
- Self-validates against the Validation criteria
- Retries from scratch if self-validation fails and attempts remain
- Writes its own status to
table.csv(doneon success,failedon failure)
Step improvement recommendations are reported back to the manager, which applies them to the task file. Only recommendations from successful dev executions are applied; failed executions' recommendations are discarded.
Self-validation
The dev agent validates its own work against the task's Validation criteria after each attempt. All criteria must pass for the item to be marked done. If validation fails and retry attempts remain, the dev agent retries from scratch. After exhausting all attempts, the item is marked failed.
Resumability
If a shift is interrupted, /nightshift:start picks up where it left off. There are no transient states to recover from -- items are either todo (available for dev processing), done, or failed. On resume, todo items are dispatched to dev and done/failed items are skipped.
Graceful degradation
A single item failure never stops the entire shift. The manager marks the failed item and moves on to the next one.
Parallel execution
By default, the manager processes one item at a time. To enable parallel processing, add parallel: true to the Shift Configuration section of manager.md:
## Shift Configuration
- name: my-batch-job
- created: 2026-02-08
- parallel: trueIn parallel mode, the manager dispatches multiple items concurrently for each task using adaptive batch sizing. Two optional fields control batch behavior:
| Field | Default | Description |
|-------|---------|-------------|
| current-batch-size | 2 | Initial batch size. Updated automatically after each batch. |
| max-batch-size | no cap | Upper bound on batch size growth. |
## Shift Configuration
- name: my-batch-job
- created: 2026-02-08
- parallel: true
- current-batch-size: 4
- max-batch-size: 10Adaptive sizing: The manager doubles the batch size after a fully successful batch and halves it (minimum 1) when any item fails. After each adjustment, the manager writes the new value back to current-batch-size in manager.md, so resumed shifts pick up where they left off.
Both current-batch-size and max-batch-size are ignored when parallel is not true. Invalid values (non-positive or non-numeric) are treated as omitted.
Parallelism applies only across items for a single task. Tasks within an item remain strictly sequential per the task order.
Self-improvement
By default, after each successful dev execution the manager reviews the dev's step improvement recommendations and applies them to the task file. This incremental refinement improves execution reliability over time as the manager learns from each item.
To disable this cycle, add disable-self-improvement: true to the Shift Configuration section of manager.md:
## Shift Configuration
- name: my-batch-job
- created: 2026-02-08
- disable-self-improvement: trueWhen the flag is true:
- The manager skips the Apply Step Improvements step after each dev result
- The dev agent skips the Identify Recommendations step and always returns
Recommendations: None
This is useful for shifts with mature, stable task files where the self-improvement cycle adds token overhead without meaningful benefit. Omitting the flag (or setting it to false) restores the default behavior.
Template Variables
Task steps support three types of placeholders, all resolved in a single pass before execution begins.
Column placeholders: {column_name}
Reference any metadata column from table.csv. The column name must match a header in the table exactly.
1. Navigate to {url}
2. Fill in the title with {page_title}Environment placeholders: {ENV:VAR_NAME}
Reference values from an optional .env file in the shift directory (.nightshift/<shift-name>/.env). Useful for credentials, API keys, and base URLs that should not be committed to version control.
1. Authenticate with API key {ENV:API_KEY}
2. POST to {ENV:BASE_URL}/api/pagesThe .env file uses standard dotenv format:
# Shift environment variables
BASE_URL=https://example.com
API_KEY=sk-1234-abcdShift .env files are gitignored via the .nightshift/**/.env pattern.
Shift placeholders: {SHIFT:FOLDER} / {SHIFT:NAME} / {SHIFT:TABLE}
Reference shift-level metadata. Three variables are available:
{SHIFT:FOLDER}-- the shift directory path (e.g.,.nightshift/my-batch-job/){SHIFT:NAME}-- the shift name (e.g.,my-batch-job){SHIFT:TABLE}-- the full path to the shift'stable.csv(e.g.,.nightshift/my-batch-job/table.csv)
1. Save the output to {SHIFT:FOLDER}output/{SHIFT:NAME}-output.jsonError handling
All placeholders use fail-fast behavior. A missing column value, undefined environment variable, or unrecognized shift variable causes the dev agent to report an error immediately rather than proceeding with an unresolved placeholder.
Agent Permissions
| Agent | Write | Edit | Bash | Delegation | Playwright |
|-------|-------|------|------|------------|------------|
| Manager | yes | yes | qsv, flock | dev only | no |
| Dev | yes | yes | mkdir, qsv, flock | none | optional (see below) |
MCP access (Playwright, Slack, Drive, custom MCPs)
Nightshift dev work runs as a top-level claude -p subprocess, so it automatically inherits every MCP you have configured at the user level in Claude Code. No Nightshift-specific MCP setup is required. If you have a Playwright MCP, a Slack MCP, an internal company MCP, etc. installed globally, your Nightshift tasks can use them — just reference the relevant tools in your task file's ## Configuration tools: line and the dev process will use them on each invocation.
To enable Playwright specifically, install the standard Playwright MCP at the user level per Claude Code's MCP setup docs. Subsequent shifts will pick it up automatically.
Permission mode
The manager probes Claude Code's --permission-mode auto on each shift start and uses it when available. Auto mode reduces permission prompts while keeping classifier-driven safety guardrails (no privilege escalation, no force-push, no mass deletion, etc.). See https://code.claude.com/docs/en/permission-modes for the full contract.
Auto mode requires:
- Claude Code v2.1.83 or later
- A Max, Team, Enterprise, or API plan (not Pro)
- An eligible Sonnet 4.6, Opus 4.6, or Opus 4.7 model
- The Anthropic API provider (not Bedrock, Vertex, or Foundry)
If your environment doesn't qualify, the manager transparently falls back to --permission-mode bypassPermissions and prints a one-line notice in the shift's final summary. The fallback skips the classifier guardrails — tasks run with full tool access — so review your task definitions before kicking off shifts under fallback mode.
Real-time observability
Each dev subprocess streams its work to .nightshift/<shift>/logs/<item-id>-<task>-<timestamp>.jsonl. While a shift is running, you can tail -f any log to watch a single dev process think in real time:
tail -f .nightshift/my-shift/logs/3-create_page-*.jsonl | jq .Logs persist after the shift completes (handy for post-mortem). They are gitignored by default.
Multi-repo shifts
Nightshift can target a different repository per item. Three optional fields in the task ## Configuration section control where and how each dev subprocess runs:
working_dir: <path-or-placeholder>— the directory each dev subprocesscds into before running. Supports the same placeholder syntax as task steps ({column},{ENV:VAR},{SHIFT:FOLDER|NAME|TABLE}), so per-item paths come from atable.csvcolumn.worktree: true— when set, the subprocess runs inside a git worktree ofworking_diron a unique branch (worktree-ns-<shift>-<item>-<task>-<timestamp>). Each item gets its own isolated checkout — parallel items targeting the same repo don't clobber each other.model: <name>— pass a specific Claude Code model (haiku,sonnet,opus, or a full model ID) for this task. Useful for cost control: mechanical tasks can run onhaiku.
Example: refactor across 3 repos in parallel
Task definition (.nightshift/dep-bump/upgrade.md):
## Configuration
- tools: bash
- model: sonnet
- working_dir: {repo_path}
- worktree: true
## Steps
1. Run `pnpm install` to refresh the lockfile
2. Run `pnpm test` to confirm the suite still passes
3. Commit the lockfile change with `git commit -am "chore: refresh lockfile"`
## Validation
- `pnpm test` exit code is 0
- A new commit exists on the current branch with message starting `chore: refresh lockfile`Table (.nightshift/dep-bump/table.csv):
row,repo_path,name,upgrade
1,/Users/you/project-a,Project A,todo
2,/Users/you/project-b,Project B,todo
3,/Users/you/project-c,Project C,todomanager.md enables parallel mode:
## Shift Configuration
- name: dep-bump
- parallel: true
- current-batch-size: 3
- max-batch-size: 3
## Task Order
1. upgradeOne-time workspace-trust setup
Claude Code requires you to accept its workspace-trust dialog in each new directory before --worktree works there. Do this once per target repo before starting a worktree-using shift:
for d in /Users/you/project-a /Users/you/project-b /Users/you/project-c; do
(cd "$d" && claude) # accept the trust dialog, then exit immediately
doneTrust is stored in ~/.claude.json and persists indefinitely. The manager runs a pre-flight check before dispatching and aborts with a clear remediation message if any directory isn't trusted yet — so you'll know exactly which (cd ... && claude) invocations are still needed.
The trust prerequisite only applies when worktree: true. Tasks using working_dir alone (no worktree) skip the trust check.
Shipping .env into worktrees
By default, a fresh git worktree doesn't have your repo's gitignored files (like .env or .env.local). Claude Code reads a .worktreeinclude file at your repo root and copies the listed gitignored files into each new worktree:
# .worktreeinclude in your project root
.env
.env.local
config/secrets.jsonSee the Claude Code worktree docs for the full contract.
Cleanup
Worktrees are cleaned up automatically when the dev subprocess exits successfully and leaves no uncommitted state. If the dev fails or leaves uncommitted changes, the worktree is preserved for inspection and listed in the shift's final summary. Clean up manually with:
(cd <working_dir> && git worktree remove --force .claude/worktrees/<name>)Add .claude/worktrees/ to each target repo's .gitignore so worktree contents don't appear as untracked files in the main checkout.
Project Layout
nightshift/
.claude-plugin/
marketplace.json # marketplace catalog (lists this one plugin)
plugins/
nightshift/
.claude-plugin/
plugin.json # plugin manifest
agents/
manager.md # the manager subagent
skills/
start/SKILL.md # /nightshift:start
create/SKILL.md # /nightshift:create (incl. project bootstrap)
add-task/SKILL.md
update-table/SKILL.md
do-task/SKILL.md
test-task/SKILL.md
archive/SKILL.md
doctor/SKILL.md # /nightshift:doctor (dep check)
src/ # TypeScript source for the deprecated npm CLI stub
bin/ # CLI entry script
dist/ # Compiled output (generated by build)
test/ # Integration tests (drives the plugin via --plugin-dir)
.nightshift/ # Active and archived shifts (created lazily in target projects)License
MIT
