name: background-bash
description:
'WHAT: Decide when to run a shell command off-turn with the bg_bash tool instead of blocking the turn on the
built-in bash tool, and how to poll / steer / collect it across turns. WHEN: A command is long-running (dev server,
build, watch, test suite, training run, log tail) or you want the turn free while it runs. DO-NOT: Background a quick
command whose output you need immediately, spawn a job you never poll, or use it for pure computation - that is
compute.'
Background bash
The built-in bash tool blocks the assistant turn until the command exits. bg_bash spawns the command off-turn,
returns a job id immediately, and exposes one multi-action tool (start, list, status, logs, wait, signal,
stdin, remove) you drive across later turns to poll, steer, and collect output. Reach for it when a command outlives
the moment you launch it - or when you would rather keep working than sit on a blocking call.
When to use this skill
Use bg_bash start when at least one of these is true:
- The command does not terminate on its own. Dev servers, file watchers,
tail -f,npm run dev, queue workers. These would hang a blockingbashcall forever. - The command is slow and you have other work. A full build, a long test suite, a training run, a large download.
Background it, make progress inline, then
waitfor it. - You want to watch progress over several turns.
logswith asinceCursorlets you resume the stream without re-reading from the top. - The command may need steering. A REPL or installer that reads stdin - pass
interactiveStdin: trueand feed it with thestdinaction.
Stay on the built-in bash tool when:
- The command is quick (a
git status, a one-shot test file, anls) and you need its output to decide the next step. Backgrounding it just adds a poll round-trip. - You cannot proceed without the result. If the very next thing you do consumes the output, block on
bash. - The work is pure calculation or data shaping. That is the
computetool, not a shell at all - seecompute-over-bash.
Workflow
- Start the job.
bg_bashstartwithcommand(andcwd/label/envif needed). It returns a job id and the job begins running detached. Record the id - you need it for every later action. - Do inline work. The turn is yours again. Draft code, read files, start other jobs.
- Check cheaply when you want a pulse.
bg_bashstatuswith the id is a single-line snapshot (running / exited, duration, bytes). Do not tight-poll - onestatusbetween substantial inline work, not one per line of reasoning. - Read output incrementally.
bg_bashlogswith the id. Usetail: Nfor the last N lines,grepto filter, andsinceCursor(the opaque cursor from a priorlogscall) to resume without re-reading. If the response setsdroppedBefore: true, the ring buffer evicted that range - fall back to the on-disklogFileit names. - Block when you actually need the result.
bg_bashwaitwith a generoustimeoutMs(default 15000). It returns when the job exits, ortimedOut: trueif still running - then loop or keep working. - Stop or clean up.
bg_bashsignal(defaultSIGTERM) kills a live job and its process group.bg_bashremovedrops a terminal job from the registry - it refuses live jobs, so signal first.
Steering interactive jobs
A job started with interactiveStdin: true gets a writable stdin. Feed it with bg_bash stdin (text, optional
eof to close the stream after writing). Without interactiveStdin, stdin is /dev/null and any stdin action
errors - this is the default so non-interactive commands that incidentally read stdin see EOF instead of hanging.
Do not orphan jobs
Every job id you start is a commitment. Jobs live for the pi session and survive turn boundaries; a forgotten dev server
keeps running and burning resources. Before ending a turn, for each live job: wait on it (if you need it), note in
scratchpad that you will check it next turn, or signal it (if obsolete). On session_shutdown pi sends every live
job SIGTERM, waits PI_BG_BASH_KILL_GRACE_MS (default 3000), then SIGKILL - but that is a backstop, not your exit
plan.
Common pitfalls
- Backgrounding a quick command, then immediately
waiting. That is a blockingbashcall with extra steps. If you will wait right away, usebash. - Tight
statuspolling. Each call burns a tool slot. Prefer onewaitwith a realtimeoutMsover a stream ofstatuschecks. - Forgetting the job id across a compaction. Stash
id -> what it runsinscratchpadso you can re-attach. - Expecting state to persist across pi restarts. Jobs are session-scoped. A restart leaves only
exited/errorhistory; live jobs from a dead runtime are pruned. - Reaching for
bg_bashto compute. No filesystem-free sandbox here - it is a real shell. Pure math / JSON reshape belongs incompute.
Related docs
bg-bash.md- full tool reference: every action, log buffering, signals, env vars.compute-over-bash- route pure computation tocomputeinstead of any shell.subagent-background- the analogous lifecycle for background subagents.