| name | bg-dispatch |
| description | Fire-and-forget background dispatch for heavy coding agents (Claude Code, Aider, Codex CLI, etc.) with pluggable notification system. Agent runs in background, main session stays free. Resumable across container resets. |
bg-dispatch — OpenClaw Skill
Fire-and-forget background dispatch for heavy coding agents. Launch Claude Code, Aider, Codex CLI — or any long-running coding tool — in the background. Your OpenClaw session stays free with zero token burn. On completion, pluggable notifiers wake your agent and/or notify your team.
When to Use
Use bg-dispatch for:
- Any coding task expected to take more than a few minutes
- Building features, fixing bugs, refactoring, writing tests
- Heavy "vibe coding" sessions that would block your main session
- Tasks where you want your agent available for other conversations
Handle directly (no dispatch):
- Pure documentation edits (README, config files)
- Quick one-liner shell commands
- Tasks where you need the result immediately
Quick Reference
Dispatch a New Task
bg-dispatch \
--adapter claude-code \
--prompt "Build a REST API with user authentication and rate limiting" \
--name "user-auth-api" \
--workdir /path/to/project \
--source-session "$CURRENT_SESSION_KEY"
Resume After Interruption
bg-dispatch --adapter claude-code --workdir /path/to/project --resume --force
Check Task Status (Heartbeat)
node task-check.mjs --data-dir ./data --projects-dir /path/to/projects
Available Adapters
claude-code (Claude Code)
The primary adapter. Supports Superpowers plugin, Agent Teams, and Bedrock.
bg-dispatch -a claude-code \
-p "Implement the payment module with Stripe integration" \
-n "payment-stripe" \
-w /path/to/project \
--model "claude-opus-4-1-20250805" \
--agent-teams \
--allowed-tools "Bash(*),Read,Write,Edit,MultiEdit,Glob,Grep,Skill,Agent"
Adapter-specific options:
--opt permission-mode=none — Claude Code permission mode
Environment variables:
CLAUDE_BIN — Path to claude binary (default: auto-detect)
CLAUDE_CODE_USE_BEDROCK=1 — Use AWS Bedrock
AWS_PROFILE, AWS_REGION — Bedrock auth
aider (Aider)
bg-dispatch -a aider \
-p "Refactor the database layer to use connection pooling" \
-n "db-pool-refactor" \
-w /path/to/project \
--model "claude-sonnet-4-20250514"
Adapter-specific options:
--opt edit-format=diff — Edit format (whole/diff/udiff)
--opt auto-commits=true — Enable Aider's auto-commits
--opt lint-cmd="ruff check" — Lint after edits
--opt test-cmd="pytest" — Test after edits
codex (OpenAI Codex CLI)
bg-dispatch -a codex \
-p "Add comprehensive test coverage for the auth module" \
-n "auth-tests" \
-w /path/to/project
Adapter-specific options:
--opt approval-mode=full-auto — Approval mode (full-auto/suggest/ask)
Notification System
bg-dispatch uses a pluggable notifier system. Configure in bg-dispatch.json:
{
"notifiers": [
{
"type": "openclaw",
"config": { "session": "main" }
},
{
"type": "webhook",
"config": {
"url_env": "SLACK_WEBHOOK_URL",
"template": "slack"
}
},
{
"type": "webhook",
"config": {
"url_env": "FEISHU_WEBHOOK_URL",
"template": "feishu",
"secret_env": "FEISHU_WEBHOOK_SECRET"
}
},
{
"type": "command",
"config": {
"command": "echo Task $BGD_TASK_NAME completed with status $BGD_STATUS"
}
}
]
}
Notifier Types
| Type | Description | Use Case |
|---|
openclaw | Wakes OpenClaw session via direct system event | Primary — agent receives completion event |
webhook | HTTP POST to any webhook URL | Team notifications (Slack, Feishu, Discord) |
command | Execute arbitrary shell command | Custom integrations, scripts, logging |
Webhook Templates
slack — Slack Block Kit message with status, duration, model info
feishu — Feishu rich-text post with emoji status indicators
discord — Discord embed with color-coded status
generic — Simple JSON payload (works with any webhook receiver)
Config File Search Order
<workdir>/bg-dispatch.json — per-project config
<data-dir>/bg-dispatch.json — instance config
<install-dir>/bg-dispatch.json — global config
~/.bg-dispatch.json — user config
If no config file found, defaults to openclaw notifier.
Writing Custom Notifiers
Create a script in notifiers/ implementing:
notifier_validate() {
}
notifier_send() {
local META_FILE="$1"
local CONFIG="$2"
}
The command notifier exposes these env vars in the command context:
BGD_TASK_NAME, BGD_STATUS, BGD_EXIT_CODE
BGD_WORKDIR, BGD_MODEL, BGD_ADAPTER
BGD_STARTED_AT, BGD_COMPLETED_AT
BGD_META_FILE, BGD_PROGRESS_FILE
How It Works
Architecture
Your Agent (OpenClaw session)
│
├─ Receives coding task
├─ Runs: bg-dispatch --adapter <name> --prompt <task> --workdir <dir>
│ ├─ Creates progress.md + meta.json in data/tasks/<task-id>/
│ ├─ Launches coding agent in background (setsid + PTY)
│ ├─ Starts watchdog (stall detection + max runtime)
│ └─ Returns immediately ← your agent is FREE
│
... zero token consumption while agent works ...
│
├─ On completion:
│ ├─ Hook fires → notify.sh → all configured notifiers
│ ├─ Watchdog provides fallback if hook fails
│ └─ OpenClaw notifier wakes your agent session (instant, no cron delay)
│
├─ Your agent reads data/tasks/<task-id>/progress.md
└─ Sends summary to user, creates PR, etc.
Three-Layer Notification Guarantee
- Hook (primary) — Claude Code's Stop hook fires →
on-complete.sh → notify.sh
- Process fallback — Inline completion handler in the background process
- Watchdog (safety net) — Detects process exit, waits 35s for hook, sends if missed
All three paths call notify.sh, which is idempotent: each notifier checks meta.json's notified.* fields before sending. First writer wins; subsequent calls are safe no-ops. No duplicate notifications even when hook and setsid block race.
Cascading Session Wake (openclaw notifier)
The openclaw notifier uses a three-level cascade to guarantee the agent session is woken, even when the target session is temporarily unavailable:
Level 1: Targeted session wake (source_session)
│ ✅ → done (notification delivered to exact originating session)
│ ❌ ↓
Level 2: Broadcast system event (main session)
│ ✅ → done (main session picks up the completion)
│ ❌ ↓
Level 3: Heartbeat pending marker
│ → writes pending_session_notify to meta.json
│ → next heartbeat poll (task-check.mjs) surfaces it
└ → agent reads meta.json and delivers the notification
--source-session: Pass the originating session key when dispatching. The completion notification will be routed directly to that session (Level 1), rather than broadcasting to the main session. This is critical for multi-channel setups where the dispatching session (e.g., a Slack channel) is different from the main agent session.
bg-dispatch -a claude-code \
-p "Fix auth bug" \
-n "auth-fix" \
-w /path/to/project \
--source-session "channel:C0ANTPRBBJ4"
Idempotency tracking in meta.json:
{
"notified": {
"openclaw": true,
"webhook_slack": true,
"webhook_feishu": false
},
"pending_session_notify": null
}
When pending_session_notify is non-null, task-check.mjs includes it in the output so the heartbeat can retry delivery.
Watchdog Behavior
- Stall detection — No file changes for 15 min (configurable) → kill + notify
- Max runtime — Hard 2-hour limit (configurable) → kill + notify
- Progress.md check — If
## Status: COMPLETE appears → clean shutdown + notify
- Exit detection — When process exits, waits for hook, sends fallback if needed
Progress Monitoring
bg-dispatch provides intermediate progress reporting between dispatch and completion:
- Periodic polling — With
--progress-interval 300, the watchdog runs git diff --stat every 5 minutes and appends to progress.md
- File activity signals — The watchdog logs file changes to
watchdog.log and updates last_activity in meta.json (always-on)
- Progress notifications — Notifiers can subscribe to
progress events via the events config array
- Live output —
bgd logs -f follows output in real-time while the task is running
Notifier Event Configuration
Each notifier can subscribe to specific events. Default is ["complete"] only:
{
"notifiers": [
{ "type": "openclaw", "config": { "session": "main" } },
{ "type": "webhook", "config": { "url_env": "SLACK_WEBHOOK_URL", "template": "slack" }, "events": ["complete", "progress"] }
]
}
Event types:
complete — Task finished (default, always sent unless filtered)
progress — Lightweight mid-task update (must opt-in via events array)
Resume Protocol
Progress is centralized in data/tasks/<task-id>/ — outside the project workdir to avoid polluting repos:
data/tasks/<task-id>/
├── meta.json # Full task definition (prompt, adapter, config, status)
├── progress.md # What's done, in progress, remaining
├── output.txt # Agent output log
└── watchdog.log # Watchdog monitoring log
On resume, bg-dispatch searches data/tasks/ for a task matching the workdir and rebuilds the prompt from meta.json. The agent reads progress.md + git log and continues from the last checkpoint. Legacy .dev-progress/ in the workdir is auto-migrated if found.
CLI Reference
Usage: bg-dispatch [OPTIONS]
Required:
-a, --adapter NAME Adapter name (claude-code, aider, codex)
-p, --prompt TEXT Task prompt (required unless --resume)
Options:
-n, --name NAME Task name (default: task-<timestamp>)
-w, --workdir DIR Working directory (default: cwd)
--resume Resume from data/tasks/
--force Kill existing task for same workdir
--model MODEL Model override
--allowed-tools TOOLS Allowed tools (adapter-specific)
--agent-teams Enable multi-agent mode
--stall-timeout SECS Stall timeout (default: 900)
--max-runtime SECS Max runtime (default: 7200)
--progress-interval SECS Progress polling interval (default: 0 = disabled)
--callback-session KEY OpenClaw session key
--source-session KEY Originating session key (for targeted notification routing)
--opt KEY=VALUE Adapter-specific option (repeatable)
-h, --help Show help
Integration Guide for Agent Developers
Step 1: Install
git clone https://github.com/PeterHiroshi/bg-dispatch.git
cd bg-dispatch && bash install.sh
export PATH="$(pwd):$PATH"
export BG_DISPATCH_DIR="$(pwd)"
Step 2: Configure Notifications
Create bg-dispatch.json with your preferred notifiers. At minimum, use openclaw to wake your agent:
{
"notifiers": [
{ "type": "openclaw", "config": { "session": "main" } }
]
}
Step 3: Dispatch from Your Agent
Your OpenClaw agent dispatches tasks like this:
bg-dispatch \
-a claude-code \
-p "$(cat <<'EOF'
Build a user authentication system with:
- JWT tokens with refresh
- Rate limiting per IP
- Password hashing with bcrypt
- Integration tests
EOF
)" \
-n "auth-system" \
-w /path/to/project
Step 4: Handle Completion
When the task completes, your agent receives a system event. Read the progress from the centralized task directory (path is included in the system event message):
cat /path/to/bg-dispatch/data/tasks/<task-id>/progress.md
Then take action: create a PR, notify the user, dispatch the next task.
Step 5: Heartbeat Integration
In your agent's heartbeat, check for completed/interrupted tasks:
node bg-dispatch/task-check.mjs \
--data-dir bg-dispatch/data \
--projects-dir /path/to/projects
The output JSON tells you what needs attention:
unnotified — Completed tasks the user hasn't been told about
interrupted — Tasks that need resuming
stalled — Tasks that may be stuck
Monitoring Commands (bgd CLI)
The bgd CLI provides interactive task monitoring. Use it to check on background tasks, view logs, and manage task lifecycle.
List Tasks
bgd tasks
bgd tasks --status running
bgd tasks --status done
bgd tasks --limit 5
Quick Status Overview
bgd status
Show Task Details
bgd show auth-api
bgd show db
View Logs
bgd logs auth-api
bgd logs auth-api -n 100
bgd logs auth-api -f
bgd logs auth-api --watchdog
View Progress
bgd progress auth-api
Cancel a Task
bgd cancel auth-api
Resume a Task
bgd resume auth-api
Clean Up
bgd clean
bgd clean --all
bgd clean --dry-run
File Layout
bg-dispatch/
├── bg-dispatch # Main dispatcher
├── watchdog.sh # Stall detection + max runtime
├── notify.sh # Notification dispatcher
├── task-check.mjs # Heartbeat integration
├── install.sh # Setup script
├── bg-dispatch.example.json # Example config
├── SKILL.md # This file (OpenClaw Skill)
├── adapters/
│ ├── claude-code.sh # Claude Code adapter
│ ├── aider.sh # Aider adapter
│ └── codex.sh # Codex CLI adapter
├── notifiers/
│ ├── openclaw.sh # OpenClaw system event notifier
│ ├── webhook.sh # Generic webhook (Slack/Feishu/Discord)
│ └── command.sh # Custom command notifier
├── hooks/
│ ├── on-complete.sh # Claude Code Stop hook
│ └── settings.json # Hook config
├── docs/
│ └── writing-adapters.md # Adapter development guide
└── data/tasks/ # Runtime data (gitignored)