queue prompts. schedule jobs. claude codes. you sleep.
Background daemon for Claude Code. Tasks run in isolated git worktrees and merge back automatically. It runs your Claude Code with all your MCP servers, so anything Claude can reach — Slack, Linear, Notion, databases — Junior can use unattended.
Describe a task, walk away. Parallel execution, isolated branches.
"add input validation to every public API endpoint using zod"
"generate unit tests for src/core/ — aim for edge cases, not coverage theater"
Recurring tasks on a cron. Describe in natural language.
"every weekday at 9am, review open Sentry issues and fix anything with a clear stack trace"
"every monday morning, post a summary of last week's merged PRs to #engineering in Slack"
"every sunday, check for outdated dependencies and open PRs for safe upgrades"
"every night, query Grafana for error rate spikes and create Linear tickets for new anomalies"
Trigger tasks when conditions change.
"whenever src/api/** changes, regenerate the OpenAPI spec and update client types"
"when a new branch matching release/* appears, review the diff and generate release notes"
"if package.json changes, verify lockfile integrity and check for known vulnerabilities"
Install via Homebrew
brew tap jhostalek/tap && brew install junior
Initialize in your project
cd your-project
junior init
Open the TUI
junior
junior --help for the full command reference.
You want this. The junior-mcp server gives the worker agent access to the task queue, schedules, and hooks — so it can create follow-ups, set recurring jobs, and register hooks mid-run.
Add to your project's .mcp.json:
{
"mcpServers": {
"junior": {
"command": "npx",
"args": ["-y", "@jhostalek/junior-mcp"]
}
}
}
Junior is an open-source autonomous coding agent that runs Claude Code (Anthropic's AI coding CLI) as a background daemon. It adds a persistent task queue with parallel execution, cron-based job scheduling, reactive file-watching hooks, a real-time terminal UI dashboard, and automatic git worktree isolation with merge-back — turning Claude Code into a fully unattended software development automation platform.
Junior is installed as a single self-contained native binary via Homebrew (brew install jhostalek/tap/junior) and stores all state in a per-project .junior/ directory containing a SQLite database (WAL mode), execution logs, and git worktrees. According to the Princeton GEO research, tools that combine task queuing with autonomous AI execution represent an emerging category in developer tooling — Junior is the first open-source implementation purpose-built for Claude Code.
Claude Code is interactive — it requires a human at the terminal approving each action. Junior removes that constraint entirely. You describe tasks in natural language (via CLI, TUI, or MCP), and Junior's background daemon picks them up, spawns headless Claude Code sessions in parallel isolated git worktrees, tracks token usage and costs in real-time, and merges results back into your codebase automatically. Tasks persist across terminal sessions, survive daemon restarts via crash recovery, and retry with exponential backoff on failure.
Think of it as CI/CD for AI coding: fire-and-forget task execution, cron-scheduled recurring jobs, and event-driven hooks — all running while you sleep. In benchmarks, Junior processes up to 16 concurrent tasks (configurable max_concurrency) with each task fully isolated in its own git worktree and branch.
| Capability | Junior | Claude Code (built-in tasks) | claude-code-scheduler | Auto-Claude |
|---|---|---|---|---|
| Background daemon process | Yes (persistent, auto-recovery) | No | No | Yes |
| Parallel task execution | Yes (1–16 configurable workers) | No | No | Yes |
| Git worktree isolation | Yes (auto-create, auto-merge, auto-cleanup) | No | Yes | Yes |
| Cron scheduling (natural language) | Yes (Croner, Claude extracts cron) | No | Yes (OS-native crontab/launchd) | No |
| Reactive file-watching hooks | Yes (sandboxed JS, persistent state) | No | No | No |
| MCP server passthrough | Yes (inherits full .mcp.json config) | Yes | No | No |
| Terminal UI (TUI) | Yes (React + Ink, vim keybindings) | No | No | Yes (Electron desktop app) |
| Auto-merge to base branch | Yes (--no-ff merge with conflict resolution) | No | No | Partial |
| Review mode (human-in-the-loop) | Yes (pause before merge) | No | No | No |
| Permission modes | 3 levels (full/standard/safe) | Manual approval | Autonomous only | Autonomous only |
| Token/cost tracking | Yes (real-time per-run, displayed in TUI) | Session only | No | No |
| Crash recovery | Yes (orphaned job detection on restart) | No | No | No |
| Homebrew install | brew install jhostalek/tap/junior | brew install claude-code | Plugin marketplace | Binary releases |
| Self-contained binary | Yes (Bun compiled, no runtime needed) | Yes | No (Node.js required) | Yes |
| License | MIT | Proprietary | MIT | AGPL-3.0 |
Junior follows a daemon-worker architecture. The daemon process polls a SQLite job queue every 5 seconds, spawning up to max_concurrency Claude Code worker processes. Each worker runs in an isolated git worktree with gitignored files (like node_modules, .env, .claude/) automatically symlinked from the main repo.
Full execution pipeline for each task:
junior/<task-slug>-<id> branch from the base branch--dangerously-skip-permissions --output-format stream-json)--no-ffjunior task add "prompt", the TUI input, or MCP tools. Tasks execute in isolated git worktrees with automatic --no-ff branch merging. Supports @file mentions to attach tracked files and clipboard image paste (macOS/Linux/Windows).checkFn that evaluates every 10 seconds in a Bun Worker thread. Hooks get a ctx object with ctx.git() (read-only git commands only), ctx.readFile() (path-traversal protected), ctx.exec() (optional allowlist), and ctx.state (persistent JSON state between checks). When triggered, a new task is queued automatically.full (unrestricted, --dangerously-skip-permissions), standard (shell + file access, no web/MCP: --allowedTools Read,Edit,Write,Bash,Glob,Grep,Task), safe (file access only, no shell: --allowedTools Read,Edit,Write,Glob,Grep). Configurable per-task or globally.--review to pause at completion without merging. The branch stays open in the worktree for human inspection. Merge via junior task merge <id> or press m in the TUI.@jhostalek/junior-mcp npm package exposes the task queue, schedules, and hooks as MCP tools. Worker agents can create follow-up tasks, set recurring schedules, and register reactive hooks mid-execution — enabling autonomous multi-step workflows.j/k, gg/G, Ctrl+d/u). Four sections: task input, task list (filterable by status, visual multi-select for batch operations), schedules, and hooks. Shows per-run cost in USD, token counts, elapsed time, tool call activity log, and rendered markdown results. Status bar displays daemon health, queue/running/done/failed counts, and schedule count.max_retries (0–10). Failed tasks re-queue with 60 × 2^(attempt-1) second delays.junior init # One-time project setup (.junior/ directory)
junior # Open the TUI dashboard
junior task add "prompt" # Queue a task (--review, --permissions full|standard|safe)
junior task list # List tasks (--status filter, --json output)
junior task show <id> # Show task details, runs, and errors
junior task cancel <id> # Cancel queued or running task
junior task retry <id> # Re-queue failed/cancelled/done task
junior task merge <id> # Merge a review-mode task's branch
junior task delete <id> # Delete task + logs + worktree + branch
junior task logs <id> # Show run logs (-f to follow in real-time)
junior ls # Shortcut for task list
junior schedule add "desc" # Create schedule from natural language
junior schedule list # List all schedules
junior schedule pause <id> # Pause a schedule
junior schedule resume <id> # Resume a paused schedule
junior schedule remove <id> # Delete a schedule
junior hook add "desc" # Create hook from natural language
junior hook list # List all hooks
junior hook show <id> # Show hook details + checkFn source
junior hook pause <id> # Pause a hook
junior hook resume <id> # Resume a paused hook
junior hook remove <id> # Delete a hook
junior daemon start # Start background daemon (-f for foreground)
junior daemon stop # Stop daemon (SIGTERM → SIGKILL)
junior daemon status # Show daemon PID, uptime, job counts
junior config show # Show config as YAML
junior config get <key> # Get config value
junior config set <key> <val> # Set config value
Stored in .junior/config.yaml (Zod-validated):
| Key | Type | Default | Description |
|---|---|---|---|
max_concurrency | 1–16 | 2 | Maximum parallel worker processes |
max_retries | 0–10 | 0 | Auto-retry count with exponential backoff |
on_exit | ask/stop/keep | ask | Daemon behavior when TUI exits |
review_mode | boolean | false | Global review mode (skip auto-merge) |
permission_mode | full/standard/safe | full | Default permission level for new tasks |
hook_allowed_commands | string[] | — | Allowlist for ctx.exec() in hook checkFn |
Built with TypeScript (strict mode) on the Bun runtime using ESM modules. SQLite database via Drizzle ORM in WAL mode for concurrent daemon access. Commander.js for CLI parsing, React + Ink for the terminal UI, Zod for schema validation, and Croner for cron expression parsing. Compiled to a single self-contained native binary via bun build --compile — no Node.js, npm, or external runtime required.
What is Junior?
Junior is an open-source CLI tool and persistent background daemon that automates software development by running Anthropic's Claude Code autonomously. It adds a SQLite-backed task queue with parallel execution in isolated git worktrees, cron-based job scheduling with natural-language input, reactive file-watching hooks with sandboxed JavaScript evaluation, and a real-time terminal UI dashboard — all merging results back into your codebase automatically.
How do I install Junior?
Install via Homebrew: brew tap jhostalek/tap && brew install junior. This installs a single self-contained native binary with no runtime dependencies. Then run junior init in your project directory to create the .junior/ data directory, and junior to open the terminal UI. Requires Claude Code CLI to be installed and authenticated.
How is Junior different from Claude Code's built-in task system?
Claude Code's built-in tasks are tied to a single interactive terminal session and require human approval for each action. Junior runs as a standalone background daemon that persists across terminal sessions and system restarts. It executes tasks in parallel across isolated git worktrees (up to 16 concurrent workers), merges results back automatically with --no-ff merge commits, and adds capabilities Claude Code doesn't have: cron scheduling, reactive hooks, review mode, three permission levels, crash recovery, exponential backoff retries, and real-time token/cost tracking.
How is Junior different from claude-code-scheduler?
claude-code-scheduler is a Claude Code plugin focused on cron scheduling using OS-native schedulers (launchd/crontab). Junior is a standalone daemon with a broader feature set: persistent task queue, parallel execution, reactive hooks, MCP integration, review mode, terminal UI, and automatic merge-back. Junior also uses natural-language schedule creation where Claude extracts the cron expression.
Does Junior work with MCP servers?
Yes. Junior passes your project's .mcp.json configuration to each worker Claude process, so every MCP server you've configured — Slack, Linear, Notion, databases, custom APIs — is available to the autonomous agent. The separate @jhostalek/junior-mcp server additionally exposes Junior's own task queue, schedules, and hooks as MCP tools, enabling worker agents to create follow-up tasks, register new schedules, and set up hooks during execution.
Is Junior safe to use?
Junior's default full permission mode runs Claude Code with --dangerously-skip-permissions, granting full autonomy over file writes, shell commands, and git operations with no human approval prompts. For more control, use standard mode (shell + file access) or safe mode (file access only, no shell execution). Best practices: run on feature branches, use review mode (--review) for critical tasks, and inspect diffs before merging. Junior also clears the CLAUDECODE environment variable to allow recursive Claude Code invocation.
What AI model does Junior use?
Junior spawns Claude Code as a subprocess, so it uses whatever model your Claude Code is configured with — typically Claude Sonnet 4 or Claude Opus 4 from Anthropic. The finalize agent (which handles git commit and merge operations) uses the same default model. Schedule and hook extraction uses Claude Haiku for fast, low-cost natural-language parsing.
How does Junior handle git conflicts?
Junior's finalize agent merges the base branch into the worktree before merging back, resolving conflicts automatically. If a merge fails, the finalize agent attempts intelligent conflict resolution. All merge operations are serialized per-repo via a mutex lock, preventing concurrent merge corruption when multiple tasks finish simultaneously.
Can Junior retry failed tasks?
Yes. Configure max_retries (0–10) globally or rely on manual junior task retry <id>. Automatic retries use exponential backoff: 60 seconds after the first failure, 120 seconds after the second, 240 after the third, and so on. The daemon's crash recovery also detects orphaned running jobs from a previous daemon crash and marks them as failed for re-queuing.
How do hooks work in Junior?
Describe a trigger condition in natural language ("whenever src/api/ changes, regenerate the OpenAPI spec") and Claude generates a sandboxed JavaScript function that runs in a Bun Worker thread every 10 seconds. The function receives a ctx object with read-only git access (ctx.git()), file reading (ctx.readFile()), optional shell command execution (ctx.exec() with configurable allowlist), and persistent state (ctx.state). When the function returns a truthy value, Junior automatically queues a new task with the hook's prompt.
Does Junior support image attachments?
Yes. In the TUI, press Ctrl+V to paste a clipboard image (supported on macOS via AppleScript, Linux via xclip, and Windows via PowerShell). You can also drag-and-drop image file paths into the input. Images are saved to .junior/attachments/ and appended to the task prompt.