An autonomous developer that runs on your machine and finishes tasks to merged PRs.
mcptask_runner turns Claude Code into a self-driving teammate. It works with Claude, Kimi, DeepSeek, local ollama, or any model you choose — no vendor lock-in. It picks the task, writes code and tests, opens a PR, and merges it after green CI. Assign well-specified work in the evening, find it done in the morning.
A full autonomous harness around Claude Code
mcptask_runner is a Ruby gem that drops rake tasks into a host Rails app so it can pull tasks from mcptask.online and run them through Claude Code end to end. It runs the whole agent loop: pick a task → triage it → choose a model → run Claude Code → watch the run with a watchdog → respect the daily quota → (optionally) merge the PR after CI.
It is not just a 'dumb launcher' for Claude Code. It adds orchestration, supervision, recovery, and quality control that bare Claude Code does not have.
What you actually get
Framed as outcomes for a freelancer or a dev team, not as tech.
Foreign bugs become tracked work
If the runner hits an unrelated bug mid-task, it files its own tracked task, fixes it, and returns to your original work. Chaos becomes an audit trail instead of a side conversation.
Self-recovers and finishes
Context overflow, stall, or interruption does not kill the task. The runner resumes on a stronger model and pushes the work to a PR. The job actually gets done, not just started.
No vendor lock-in on model
Map the genius / smart / primitive tiers to Claude, Kimi, DeepSeek, local ollama, or any model you want in mcptask_runner.yml. Switching provider is one env change. Big agents lock you to their premium model; runner does not.
AI cost under control
Cheap model for reading, strong model only for hard code. QuotaGuard (fail-closed) guards the daily budget so you never overshoot. Predictable spend.
Runs on your machine, against reality
It executes against your real PostgreSQL, your real system tests, and your real browser screenshots. Not a stripped-down cloud sandbox with mocked data.
Backlog to merged PR — even overnight
Stack tasks in mcptask.online. The runner works them while you do something else, or sleep. In the morning, merged PRs are waiting.
Runs unattended, on schedule
Each working morning it starts itself and takes the queue. No babysitting prompts.
Quality gate built in
Nothing merges without green CI. You choose: auto-merge, or PRs for human review. The runner can also process review feedback.
Not a black box — full traceability
Every run is a tracked task with progress percent, a live card, and JSON logs. Auditable, clear for the whole team.
Multiplies team capacity without hiring
An autonomous developer that holds the project's conventions (tests, CI, PR), guided by humans where it makes sense.
On your machine, against reality
Cloud coding agents run in sanitized sandboxes. The runner runs in your actual Rails project.
Real database
It connects to your PostgreSQL, runs your migrations, and tests against real data shapes — not a toy schema.
Real system tests
Capybara/Selenium runs against your real app. Screenshots and browser checks mean the PR is actually verified.
Real commits and PRs
Branches, commits, and pull requests live in your repo, with your CI, under your Git history.
Task → merged PR → timesheet → invoice
The runner is not a standalone coder. Its work flows straight back into mcptask.online.
Loop pulls tasks; goal finishes them
mcptask_runner pairs a work loop (it eats one task after another from the queue) with a goal (it finishes each task to a green PR, not just 'made some edits'). It can run in four modes:
One task
Triage and work a single task. Good for first runs and debugging.
Today's work
Loop through tasks until the daily quota is hit. PRs stay open for human review.
Continuous queue
Process the queue non-stop while tasks keep arriving.
All tasks of a story
Work every available task in a single story, in priority order.
One command does the whole bootstrap
rake mcptask_runner:install does every boring step: copies 11 bundled Claude Code skills into .claude/skills/, checks helper binaries, merges baseline permissions into .claude/settings.local.json, provisions a JWT token for mcptask.online, writes the SSE server entry into .mcp.json, asks which epic should hold auto-found bugs, and on macOS generates a LaunchAgent for weekdays at 08:00. One line, about two minutes to your first task.
$ bundle exec rake mcptask_runner:install
→ Installing 11 skills into ./.claude/skills/
→ Checking required helpers ✓ ok
→ Merging permissions into
.claude/settings.local.json
→ Provisioning MCPTASK_TOKEN
→ Writing .mcp.json ✓
→ macOS LaunchAgent scheduled
(weekdays 08:00) ✓
Ready. Have a nice day.Skill updates without losing your edits
When the gem is bumped, a single rake mcptask_runner:update is enough. The updater holds a manifest with a content-hash for every skill and classifies each as missing (copy it), identical (skip), outdated (update), or locally modified (leave alone / with FORCE=1 back it up to .bak and overwrite). New runner capabilities land automatically, your own skill edits stay intact. Git hooks re-sync skills after pull and checkout. The gem version is auto-incremented by a post-merge hook.
mcptask_runner:prepare:permissions merges the baseline permission set — part of the zero-maintenance flow.
What makes it autonomous
Below is the technical detail behind the claim that the runner is 'more than a launcher'. Each feature exists because a real-world run would fail without it.
Hitting a foreign bug spawns a tracked task and pauses
If the runner hits an URGENT bug that has nothing to do with its current task, it commits and pushes the in-progress work to the feature branch, switches to main (clean tree), files a new urgent bug task, and returns its id and name. The runner pins the bug to disk (UrgentBugPin), so even after a restart it fixes the bug first and only then returns to the original task. Chaos from 'I hit something unrelated' becomes a tracked, owned item.
Resume after context overflow or interruption
If a run ends because of context overflow, a quota hit, or an urgent bug, the task stays in_progress and the unfinished work stays on the feature branch. The next run picks it up: reads git log + branch state, fetches and merges origin/main, skips already-done steps, and escalates the model to 'genius' (Opus) so a stronger model can finish it. The runner also caps context burn: parallel independent tools, no re-reading the same file twice, no polling in loops, screenshots converted and downscaled. Long tasks survive across runs.
Watchdogs and stall detection
HeartbeatMonitoring kills the run after 20 minutes of idle, soft-warns on frozen at 3 minutes, caps on stuck tools, an absolute 30-minute backstop, and refreshes the daily quota every tick. StallDetector reads the Claude Code stream line by line and recognises 'spinning in place' — repeated Edit or Bash errors, same tool signature with no file changes. On a stall the process is killed; the task stays in_progress and resumes on Opus next time. QuotaGuard is the single source of truth for the daily budget — fail-closed on errors. Every tick also rewrites log/runs/run_*.json so you can audit what really happened.
Triage and model selection (three spice levels)
Before any work, Triage rates the task's complexity and recommends a model. Three levels: genius (Opus — heavy code), smart (Sonnet — triage, review), primitive (Haiku — read only). Model ids are versioned so retry strings survive context overflow.
Quality: tests, CI, auto-merge
The honest executor runs the full workflow: branch → code → unit tests → screenshots → system tests → push → PR → local CI. A task is not done until CI is green. In auto-squash modes the runner merges the PR itself once CI goes green; in manual modes the PR stays open for human review. The runner can also process review feedback on an open PR.
Model-agnostic by configuration
Three tiers map to any provider. Swap Claude for ollama, Kimi, DeepSeek, or Alibaba DashScope with one env change.
models:
genius: minimax-m3:cloud
smart: kimi-k2.7-code:cloud
primitive: deepseek-v4-flash:cloud
launcher:
# Local ollama
command: [env, "ANTHROPIC_BASE_URL=http://localhost:11434", "ANTHROPIC_AUTH_TOKEN=ollama", "claude"]
Why this isn't magic
Six threads, one orchestrator, and a state machine that keeps the agent honest.
Work loop
The main orchestration thread. It runs the loop, launches Claude Code via Open3.popen3 as a child process in its own process group (so SIGTERM and SIGKILL cleanly take down the whole tree).
stdout reader
Reads Claude Code's stream-json output line by line as it is produced. Parses events, counts them, hunts for the TASKRUNNER_RESULT marker (the done signal), and feeds the StallDetector. No waiting for the process to end — reacts incrementally.
stderr reader
Captures errors separately, so they do not block the main stream and you can tell a real crash from an expected shutdown.
Watchdog
An independent guard thread that ticks on a schedule: 20-minute idle kill, 3-minute frozen soft-warn, stuck-tool caps, 30-minute absolute backstop, and refreshes the daily quota from REST each tick. It is the only outside supervisor over the child process.
WebSocket to mcptask.online
EventStream holds a persistent WebSocket (ActionCable, RunnerSessionChannel) connection to mcptask.online. It sends a subscribe handshake, throttles snapshots to about 0.5 s but force-flushes every FSM state change, and reconnects asynchronously with a 30-second throttle if the socket drops. The final 'closed' frame gets a 0.5-second grace window so the live card never freezes on a stale state. The MCPTASK_RUNNER_DISABLE env var turns the whole stream off (used in tests so 'ruby test/...' does not file cards in production).
Thread-safe snapshot builder
The state machine (starting → triage → processing → waiting → finished / stalled / frozen / pending / error / closed) is guarded by a Mutex and returns an immutable snapshot hash. The producer/consumer contract uses a versioned schema (docs/runner_snapshot_schema.md) — neither side changes it without a version bump.
What you can ask it to do
Every entry below is run as bundle exec rake <task> from the project root. Optional flags: verbose=true, ignore_quota=true. The story and task variants require an argument — they fail without one.
Manual modes — PRs stay open for human review
mcptask_runner:manual:onceOne task. Triage and execute.
mcptask_runner:manual:once_dryJust show the next task, do not execute.
mcptask_runner:manual:todayLoop through tasks until the daily quota is hit.
mcptask_runner:manual:dailyContinuous daily loop.
mcptask_runner:manual:queueContinuous processing of the queue.
mcptask_runner:manual:reviewAddress review feedback on the current branch's PR.
mcptask_runner:manual:reviewsLoop over all PRs with unresolved reviews.
mcptask_runner:manual:workflowFirst reviews, then today's tasks.
mcptask_runner:manual:story[STORY_ID]Every task in a story.
mcptask_runner:manual:task[TASK_ID]One specific task.
Auto-squash modes — PR merges after CI goes green
mcptask_runner:auto:onceOne task, auto-merge, then stop.
mcptask_runner:auto:squash:todayToday's tasks, auto-merge each one.
mcptask_runner:auto:squash:story[STORY_ID]Whole story, auto-merge.
mcptask_runner:auto:squash:task[TASK_ID]One specific task, auto-merge.
mcptask_runner:auto:squash:queueContinuous queue, auto-merge.
Maintenance
mcptask_runner:installFull bootstrap: skills, permissions, token, .mcp.json, scheduler.
mcptask_runner:updateRefresh bundled skills without losing local edits.
mcptask_runner:prepare:permissionsMerge the baseline permission set.
mcptask_runner:bug_reportFile a high-priority bug with the last run log and (redacted) env config.
Turn the machine on in the morning
mcptask_runner does not replace your team — it multiplies it. One Ruby gem, one line to install, and your backlog moves by itself.
Free 30-day trial. No credit card. Open source. Cancel any time.