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.
Resources
17Install
npx skillscat add peterhiroshi/bg-dispatch Install via the SkillsCat registry.
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 --forceCheck Task Status (Heartbeat)
node task-check.mjs --data-dir ./data --projects-dir /path/to/projectsAvailable 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 BedrockAWS_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/projectAdapter-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 infofeishu— Feishu rich-text post with emoji status indicatorsdiscord— Discord embed with color-coded statusgeneric— 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() {
# Check prerequisites, return 1 on failure
}
notifier_send() {
local META_FILE="$1" # Path to task meta.json
local CONFIG="$2" # JSON string with notifier config
# Send notification, return 0 on success
}The command notifier exposes these env vars in the command context:
BGD_TASK_NAME,BGD_STATUS,BGD_EXIT_CODEBGD_WORKDIR,BGD_MODEL,BGD_ADAPTERBGD_STARTED_AT,BGD_COMPLETED_ATBGD_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: COMPLETEappears → 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 runsgit diff --statevery 5 minutes and appends toprogress.md - File activity signals — The watchdog logs file changes to
watchdog.logand updateslast_activityinmeta.json(always-on) - Progress notifications — Notifiers can subscribe to
progressevents via theeventsconfig array - Live output —
bgd logs -ffollows 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 viaeventsarray)
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 logOn 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 helpIntegration 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/projectStep 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.mdThen 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/projectsThe output JSON tells you what needs attention:
unnotified— Completed tasks the user hasn't been told aboutinterrupted— Tasks that need resumingstalled— 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 # All tasks
bgd tasks --status running # Only running tasks
bgd tasks --status done # Only completed tasks
bgd tasks --limit 5 # Limit outputQuick Status Overview
bgd status # Summary counts + active task detailsShow Task Details
bgd show auth-api # Full metadata + progress + git log
bgd show db # Partial name match OKView Logs
bgd logs auth-api # Last 50 lines of output (ANSI stripped)
bgd logs auth-api -n 100 # Last 100 lines
bgd logs auth-api -f # Follow in real-time
bgd logs auth-api --watchdog # Watchdog log insteadView Progress
bgd progress auth-api # Show progress.md from task dataCancel a Task
bgd cancel auth-api # Kill process tree, update meta, notifyResume a Task
bgd resume auth-api # Resume interrupted/killed taskClean Up
bgd clean # Remove done/killed tasks older than 24h
bgd clean --all # Remove all done/killed tasks
bgd clean --dry-run # Preview what would be removedFile 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)