| name | background-monitor |
| description | Run long-running tasks with autonomous completion notifications. Spawns an isolated monitoring sub-agent that watches your process and notifies you immediately when done. Use for installs, builds, downloads, or any task >2 minutes. Zero bloat - sub-agent auto-deletes after notification. |
Background Monitor
Run long tasks with immediate autonomous completion notifications using monitoring sub-agents.
How It Works
- Start your long task in background → get
sessionId
- Spawn a monitoring sub-agent that polls the process every 30 seconds
- When complete, sub-agent parses output and announces results
- Sub-agent auto-deletes (
cleanup="delete") - no bloat!
Key benefit: You get notified in seconds, not 30 minutes (heartbeat cycle).
Usage
Pattern: Monitored Task
result = exec(
command="./install-script.sh",
background=True,
timeout=900
)
sessionId = result['sessionId']
sessions_spawn(
task=f"""
You are monitoring background process '{sessionId}'.
LOOP UNTIL PROCESS EXITS:
1. Check: process(action='poll', sessionId='{sessionId}')
2. If still running: reply EXACTLY "HEARTBEAT_OK" and wait for next wake
3. If exited: break loop and proceed to announcement
WHEN PROCESS EXITS:
1. Get output: process(action='log', sessionId='{sessionId}')
2. Parse for success/failure and key details:
- Exit code (0 = success)
- Important URLs, credentials, errors
- Installation location
- Next steps
3. Clean up: process(action='clear', sessionId='{sessionId}')
4. Announce results as your FINAL message (this gets delivered to user):
✅/❌ status
Key details (URLs, credentials, location)
Next actions if needed
Do NOT say anything after the announcement - it must be your last reply!
CRITICAL: Only reply HEARTBEAT_OK when process is STILL RUNNING. When it exits, announce results instead.
""",
cleanup="delete",
label=f"monitor-{sessionId[:8]}"
)
f"Started installation! Monitoring in background - I'll ping you when complete."
Simplified Helper Function
For repeated use, wrap this pattern:
def monitored_exec(command, name="Task", timeout=900):
"""Start a monitored background task with autonomous notification."""
result = exec(command, background=True, timeout=timeout)
sid = result['sessionId']
sessions_spawn(
task=f"""
Monitor process '{sid}' (task: {name}).
LOOP: Poll process(action='poll', sessionId='{sid}').
- If running: reply "HEARTBEAT_OK" and wait
- If exited: STOP replying HEARTBEAT_OK, proceed to announce
WHEN DONE:
1. Get logs: process(action='log', sessionId='{sid}')
2. Parse: exit code, URLs, credentials, errors, locations, next steps
3. Clear: process(action='clear', sessionId='{sid}')
4. Announce as FINAL message: ✅/❌ {name} complete! [details]
CRITICAL: The announcement must be your LAST reply - nothing after it!
""",
cleanup="delete",
label=f"monitor-{sid[:8]}"
)
return f"Started {name} (session: {sid[:8]}). Monitoring in background!"
Then just:
monitored_exec("./install-romm.sh", name="RomM Installation", timeout=1800)
Examples
Example 1: Installation Script
result = exec(
command="bash /tmp/install.sh",
background=True,
timeout=1800
)
sessions_spawn(
task=f"""
Monitor process '{result['sessionId']}' for installation completion.
Poll every 30s. When done, parse output for URLs/credentials/errors and notify user.
Clean up and exit.
""",
cleanup="delete",
label="install-monitor"
)
"Installation started! I'll notify you when complete."
Expected notification:
✅ Installation complete!
- Access: http://192.168.1.228:8080
- Credentials: /root/app.creds
- Next: Log in and configure settings
Example 2: Build Process
result = exec("npm run build", background=True, timeout=600, workdir="~/project")
sessions_spawn(
task=f"""
Monitor build process '{result['sessionId']}'.
When complete, report exit code, build time, and output location.
""",
cleanup="delete",
label="build-monitor"
)
Expected notification:
✅ Build succeeded! (5m 23s)
- Output: dist/
- Bundle size: 2.3 MB
Example 3: Download + Extract
result = exec(
command="wget https://example.com/file.tar.gz && tar -xzf file.tar.gz",
background=True,
timeout=900
)
sessions_spawn(
task=f"""
Monitor download/extract process '{result['sessionId']}'.
Report file size, extraction location, time taken.
""",
cleanup="delete",
label="download-monitor"
)
Token Efficiency
Sub-agent cost is minimal:
- Heartbeat every 30 seconds = ~2 calls per minute
- For a 10-minute task: ~20 heartbeat calls
- Each heartbeat is tiny (process poll + HEARTBEAT_OK)
- Total: ~1-2K tokens for the entire monitoring session
Compare to: Running the task foreground and blocking your main session.
Configuration
No config needed - works out of the box!
Optional: Adjust sub-agent concurrency if you run many monitors:
{
"agents": {
"defaults": {
"subagents": {
"maxConcurrent": 8
}
}
}
}
Troubleshooting
Sub-agent not spawning?
- Check:
agents_list - is your agent allowed to spawn sub-agents?
- Check concurrency:
agents.defaults.subagents.maxConcurrent
Not getting notifications?
- Verify sub-agent was created:
sessions_list --kinds isolated
- Check sub-agent status:
sessions_history --sessionKey agent:<agentId>:subagent:<uuid>
Process killed before completion?
- Increase
timeout parameter in exec()
- Check system resources (OOM killer?)
Lost output?
- Output is kept in memory until cleared
- For huge output, redirect to file:
./script.sh > output.log 2>&1
Advanced: Custom Parsing Logic
For complex output parsing, be specific in the monitor task:
sessions_spawn(
task=f"""
Monitor process '{sessionId}' for Docker container creation.
When complete:
1. Parse logs for container ID (grep for "Created container")
2. Extract port mapping (look for "0.0.0.0:XXXX->")
3. Check health status
4. Announce: Container ID, access URL, health status
""",
cleanup="delete",
label="docker-monitor"
)
Pattern: Multi-Stage Tasks
For sequential long tasks:
result = exec("./download.sh", background=True)
sessions_spawn(
task=f"""
Monitor '{result['sessionId']}' (download stage).
When done, tell user and START NEXT STAGE:
exec("./process.sh", background=True) + spawn new monitor
""",
cleanup="delete",
label="stage1-monitor"
)
Each stage automatically kicks off the next!
Integration with AGENTS.md
Already integrated! Your AGENTS.md has the pattern documented.
For one-off tasks without the helper function, just use the full pattern inline.
tl;dr: Start task with exec(..., background=True), spawn monitoring sub-agent with sessions_spawn(..., cleanup="delete"). Sub-agent polls, notifies immediately, and auto-deletes. Zero bloat, immediate notifications! 🚀