Autonomous task runner for OpenCode repositories.
opencode-slave creates structured task folders under each project, executes tasks sequentially or in parallel, supports worktrees and per-task branches, and handles recovery/cleanup for long runs.
This README is an operations guide focused on real usage.
- Task registry in
.opencode-slave/tasks.json - Per-task workspace at
.opencode-slave/tasks/{taskName} - Auto executor mode (
__auto__) that attachesTASK.md+ allcontext/*files - Optional reviewer gate per task with feedback loop back into
context/ - Sequential mode (same repo) and worktree mode (separate branch per task)
- Background execution and recovery (
slave-resume) - Human-in-the-loop state (
waiting_input) when clarification is needed - Cleanup commands for completed/error tasks
Prerequisites:
- Node.js + npm
- OpenCode CLI
- Git (required for no-clone installer path)
macOS / Linux:
./install.sh --localWindows (PowerShell):
powershell -ExecutionPolicy Bypass -File .\install.ps1 -LocalReplace <owner>/<repo> with your repository path once.
macOS / Linux:
curl -fsSL "https://raw.githubusercontent.com/<owner>/<repo>/main/install.sh" | OPENCODE_SLAVE_REPO_URL="https://github.com/<owner>/<repo>.git" bashWindows (PowerShell):
$env:OPENCODE_SLAVE_REPO_URL = "https://github.com/<owner>/<repo>.git"
irm "https://raw.githubusercontent.com/<owner>/<repo>/main/install.ps1" | iexnpm install
npm run install:opencodenpm run install:opencode (or either installer script) installs /slave-* slash commands in your OpenCode profile:
- Commands:
~/.config/opencode/commands - Wrapper script:
~/.config/opencode/scripts/opencode-slave.js
All commands run in the current working directory.
- If you want tasks in project A, run
/slave-*inside project A. - If you want tasks in project B, run
/slave-*inside project B. - There is no
--workspace /pathflag today.
You have 3 equivalent ways to run commands:
- OpenCode slash commands (recommended after
npm run install:opencode):
/slave-task my-task
/slave-start --parallel- Local CLI from this repository:
node src/cli.js slave-task my-task
node src/cli.js slave-start --parallel- Bin command (if installed as executable):
slave slave-task my-task
slave slave-start --parallel# 1) In your target repo
/slave-task task-a
/slave-task task-b
# 2) Fill instructions/context
# .opencode-slave/tasks/task-a/TASK.md
# .opencode-slave/tasks/task-a/context/*
# 3) Run
/slave-start
# 4) Inspect
/slave-status
/slave-logs task-a/slave-task {name}
/slave-start [--dry-run] [--parallel] [--background] [--worktree {name}]
/slave-status
/slave-logs {name}
/slave-questions [name]
/slave-answer {name} "your answer"
/slave-reset {name}
/slave-cancel {name}
/slave-validate
/slave-resume
/slave-prune-worktrees
/slave-clean-finished [--include-errors]
/slave-config [--model provider/model] [--provider provider --model model] [--clear-model]When you run slave-task {name}, the runner creates:
.opencode-slave/
config.json
tasks.json
tasks/
{name}/
TASK.md
task.json
context/
logs/execution.log
output/result.json
Key files:
TASK.md: plain-language objective, constraints, success criteriacontext/*: source-of-truth artifacts for that tasktask.json: per-task runtime config (priority, retries, timeout, worktree mode, executor)
Per-task branch/worktree toggle (inside each task.json):
{
"runInWorktree": true,
"branchName": null,
"baseBranch": null,
"useCurrentBranchAsBase": false,
"review": {
"mode": "none",
"commandTemplate": "__auto__"
}
}true: run that task in a separate worktree/branchfalse: run that task in the current branch/workspacebranchName: optional explicit branch name for that task (null= autobranchPrefix + taskName)baseBranch: optional base branch for that task (null= globalconfig.baseBranch)useCurrentBranchAsBase: iftrue, use the currently checked out branch as the base when the worktree is createdreview.mode:noneoragentreview.commandTemplate: reviewer command (__auto__= OpenCode reviewer agent)
Possible task states:
pendingstartedwaiting_inputfinishederrorcancelled
Use slave-status to see status, retries, lease info, and last error.
Runs pending tasks in priority order in the current repo working tree.
If a task has runInWorktree: true, that individual task runs in its own worktree/branch even in sequential mode.
node src/cli.js /slave-startRuns one task in its own worktree/branch.
node src/cli.js /slave-start --worktree task-aRuns multiple tasks concurrently, each task in its own worktree/branch.
node src/cli.js /slave-start --parallelRuns detached (long-running).
node src/cli.js /slave-start --background
node src/cli.js /slave-status
node src/cli.js /slave-resumeslave-resume can recover stale started tasks when:
- lease expired, or
- process PID is dead, or
- heartbeat is stale.
This is the most important setup for branch isolation.
- Edit
.opencode-slave/config.jsonin your target repo. - Set these keys:
{
"baseBranch": "develop",
"branchPrefix": "slave/",
"worktreeBasePath": "../worktrees",
"maxParallel": 3,
"opencodeInactivityTimeoutSec": 300
}- Create tasks (
/slave-task ...). - Run with worktrees (
/slave-start --parallelor/slave-start --worktree <task>).
Per-task control option:
- Set
runInWorktree: trueonly on tasks that must run in separate branches. - Leave others with
runInWorktree: falseto run on current branch when using normal/slave-start. - Optionally set
branchNameandbaseBranchin each task:
{
"runInWorktree": true,
"branchName": "feature/navbar-redesign",
"baseBranch": "dev",
"useCurrentBranchAsBase": false
}If either value is null, global defaults are used.
To force a task to branch from whatever branch you are on when it starts:
{
"runInWorktree": true,
"useCurrentBranchAsBase": true
}Branch/worktree behavior:
- Branch name per task:
{branchPrefix}{taskName} - Worktree path:
{worktreeBasePath}/{repoName}-slave-{taskName} - Base for new branch: tries
origin/{baseBranch}first, then local{baseBranch}fallback - If
useCurrentBranchAsBaseistrue, the task worktree uses the branch currently checked out at launch time - Ignored local files like
.envare copied into the task worktree after creation, except internal.gitand.opencode-slave
opencodeInactivityTimeoutSec interrupts __auto__ executions when no stdout/stderr is produced for too long, so tasks do not stay stuck in started forever.
Set "opencodeInactivityTimeoutSec": 0 to disable inactivity timeout completely (recommended for very long tasks that may run for hours/days without output).
Useful git checks:
git worktree list
git branch --list "slave/*"Set model override per project:
node src/cli.js /slave-config --model opencode/gpt-5.3-codexOr split provider/model:
node src/cli.js /slave-config --provider opencode --model gpt-5.3-codexShow current config:
node src/cli.js /slave-configClear override (use OpenCode default):
node src/cli.js /slave-config --clear-modelNotes:
- Default for new projects is
opencode/gpt-5.3-codex. openai/gpt-5.3-codexis normalized toopencode/gpt-5.3-codexfor CLI compatibility.
Default mode in each task:
{
"executor": {
"commandTemplate": "__auto__"
}
}In this mode the runner:
- Always attaches
TASK.md - Always attaches all files under
context/ - Builds and runs an
opencode runcommand
You can enable a reviewer per task in .opencode-slave/tasks/{name}/task.json:
{
"review": {
"mode": "agent",
"commandTemplate": "__auto__"
}
}Behavior:
- Reviewer runs only after the implementation command succeeds
- Reviewer is instructed to stay read-only and verify the task against
TASK.md+context/* - On reviewer failure, feedback is written to
context/review-feedback.md - Next retry automatically receives that feedback because all
context/*files are attached again - Latest reviewer report is stored in
output/review.json
You can also use a deterministic custom reviewer command:
{
"review": {
"mode": "agent",
"commandTemplate": "npm test"
}
}You can set a custom command in .opencode-slave/tasks/{name}/task.json:
{
"executor": {
"commandTemplate": "node \"{taskDir}/context/run.cjs\""
}
}Supported placeholders:
{taskName}{taskDir}{taskFile}{workspace}{providerModel}
If a task needs clarification, it moves to waiting_input instead of hard failing.
node src/cli.js /slave-questions
node src/cli.js /slave-questions task-a
node src/cli.js /slave-answer task-a "Use option B and keep mobile layout"
node src/cli.js /slave-start --backgroundArtifacts:
- Questions file:
.opencode-slave/tasks/{name}/questions.md - Answers log:
.opencode-slave/tasks/{name}/context/answers.md
Remove finished/cancelled tasks:
node src/cli.js /slave-clean-finishedAlso remove error tasks:
node src/cli.js /slave-clean-finished --include-errorsPrune stale git worktree metadata:
node src/cli.js /slave-prune-worktreesPer-task hooks are supported if securityMode allows execution.
Place scripts in task folder:
pre-run.sh/pre-run.ps1/pre-run.cmdpost-run.sh/post-run.ps1/post-run.cmd
Default securityMode is untrusted (hooks are skipped).
- Check logs:
node src/cli.js /slave-logs {task} - Recover stale state:
node src/cli.js /slave-resume - If needed, reset task:
node src/cli.js /slave-reset {task}
execution.log now streams stdout/stderr line by line while the command is running.
If the command is silent, heartbeat lines are appended periodically so you can still see progress while a task runs.
- Run
node src/cli.js /slave-prune-worktrees - Or manually remove with
git worktree remove --force <path>then prune
- Verify provider/model with
/slave-config - If environment/session is broken, use a custom executor for deterministic tasks
From this repository:
npm testFull orchestration spec is in opencode-slave-plugin.md.