Command Reference
bgrun has 18 subcommands. All commands return JSON to stdout when piped, or human-readable output when connected to a terminal.
The daemon auto-starts on the first CLI invocation. You don’t need to manually start it.
run
Start a background process.
bgrun run [OPTIONS] <cmd> [args...]
Flags
| Flag | Description |
|---|---|
--name <NAME> | Named job (enables idempotent re-run; second run --name X returns the existing job if alive) |
--workspace <WS> | Group jobs for batch operations |
--ready-when <PATTERN> | Mark job Ready when a log line matches this substring |
--ready-when-regex <REGEX> | Mark job Ready when a log line matches this regex |
--ready-when-port <PORT> | Mark job Ready when TCP port localhost:PORT accepts connections |
--ready-when-url <URL> | Mark job Ready when GET returns HTTP 2xx |
--ready-when-file <PATH> | Mark job Ready when file exists |
--after <NAME> | Wait for named job to reach Ready (or Exited/Crashed) before spawning |
--pty | Allocate a pseudo-terminal (useful for processes that buffer output differently with pipes). The PTY is allocated by bgrun’s portable-pty library. Known limitation: programs that open their own PTY (e.g. podman exec -it, ssh, docker attach) may not work with --pty because the child’s PTY is consumed by the inner command rather than bgrun’s PTY master. |
--restart <POLICY> | Restart policy: never, on-crash (non-zero exit / signal death), on-failure (also clean exits that never became Ready), always (any exit except an explicit kill). An explicit kill always wins. |
--backoff <DURATION> | Base delay between restart attempts, e.g. 2s, 5m, 500ms (default: 2s, only with --restart). Doubles per consecutive failure, capped at 5 min. |
--max-retries <N> | Give up after N consecutive restart attempts (docker-style max-retries; 0 = never restart). Counter resets after a healthy run (>10s). Unset = retry forever. |
--log-max-size <SIZE> | Rotate stdout.log past this size (e.g. 10M, 1G, default 50M) |
--log-keep <N> | Retain N rotated files (stdout.log.1…; default 1, minimum 1) |
--max-rss <MB> | Kill the job if resident memory exceeds this threshold (checked every 1s) |
--max-runtime <D> | Kill the job after this duration (e.g. 30s, 5m) |
--cols <N> | PTY width in columns (default: 80, only with --pty) |
--rows <N> | PTY height in rows (default: 24, only with --pty) |
--allocate-port <NAME> | Allocate a free TCP port and set it as the environment variable <NAME> |
--health-check-url <URL> | Poll an HTTP URL periodically for liveness after ready |
--health-check-port <PORT> | Probe a TCP port periodically for liveness after ready |
--health-interval <SECS> | Seconds between health checks (default: 10) |
--health-threshold <N> | Consecutive health check failures before killing (default: 3) |
-e, --env <KEY=VAL> | Environment variable for the job (repeatable) |
-C, --cwd <DIR> | Working directory for the job (default: current directory) |
--replace | Kill any existing alive job with the same --name before starting (requires --name) |
--wait | Block until the job is Ready after starting (single-shot run+wait) |
--wait-timeout <D> | Timeout for --wait (e.g. 30s, 2m, default: 60s) |
Short flags: -n (--name), -w (--workspace), -r (--ready-when), -e (--env), -C (--cwd).
Agent shortcut — start and wait in one call instead of separate run + wait:
bgrun run -n server -r "listening on" --wait --wait-timeout 30s "npm run dev"
bgrun run -n worker -e QUEUE=jobs -e RUST_LOG=debug -C ./worker --replace "python worker.py"
Examples
# Simple background process
bgrun run "npm run dev"
# Named + readiness
bgrun run --name server --ready-when "listening on" "cargo run"
# With restart (3 attempts max, then stays crashed)
bgrun run --name worker --restart on-failure --max-retries 3 --backoff 5s "python worker.py"
# Depends on another job
bgrun run --name tests --after server "cargo test"
# PTY allocation
bgrun run --pty "npm run dev"
Output (JSON)
{"id":"abc123","name":"server","workspace":null,"cmd":["cargo","run"],"pid":12345,"state":"running","started_at":"2026-05-31T00:00:00Z"}
If a named job is already running, the existing record is returned instead of spawning a duplicate.
run-group
Start multiple named jobs in parallel. Each name is resolved from bgrun.toml (see bgrun.toml Reference). Jobs respect their after dependencies — the group waits for each job’s dependencies before spawning it.
bgrun run-group <NAME> [NAME...]
Examples
# Start all jobs defined in bgrun.toml
bgrun run-group db server worker
# Start specific group
bgrun run-group server worker
Output (JSON)
[
{"id":"aaa","name":"server","state":"running",...},
{"id":"bbb","name":"worker","state":"running",...}
]
list
List all known jobs, or filter by workspace.
bgrun list [--workspace <WS>]
Examples
# All jobs
bgrun list
# Jobs in a specific workspace
bgrun list --workspace myapp
Output (JSON) — one JSON object per line (NDJSON):
{"id":"abc","name":"server","workspace":"myapp","cmd":["cargo","run"],"pid":12345,"state":"running","started_at":"..."}
{"id":"def","name":"worker","workspace":"myapp","cmd":["python","worker.py"],"pid":12346,"state":"exited","started_at":"..."}
status
Get the current state of a job.
bgrun status [<ID>] [--name <NAME>]
Flags
| Flag | Description |
|---|---|
--name / -n <NAME> | Job name (alternative to positional ID) |
Examples
bgrun status abc123
bgrun status server # works with names too
bgrun status --name server
Output (JSON)
{"state":"running","exit_code":null,"ready_at":null,"restart_count":0,"last_diff_cursor":0}
| Field | Meaning |
|---|---|
state | Starting, Running, Ready, Exited, Crashed, or Killed |
exit_code | Process exit code (null while running) |
ready_at | RFC 3339 timestamp when readiness check passed |
restart_count | How many times the process has been restarted |
last_diff_cursor | Byte offset for incremental log tailing |
tail
Show the last N lines of a job’s stdout/stderr log.
bgrun tail <ID> [--lines <N>] [--digest] [--level <LEVEL>] [--stream <S>] [--strip-ansi] [--follow] [--filter-regex <R>]
Flags
| Flag | Description |
|---|---|
--lines <N> | Number of lines to show (default: 20) |
--digest | Show summary instead of raw lines (error/warn count, last error) |
--level <LEVEL> | Filter lines containing error or warn (case-insensitive) |
--stream <S> | Filter by stream source (stdout, stderr, pty) |
--strip-ansi | Strip ANSI escape codes from output |
--follow | Follow new log lines in real time |
--filter-regex <R> | Filter log lines matching a regex pattern |
Examples
# Last 10 lines
bgrun tail server --lines 10
# Digest summary
bgrun tail server --digest
# Show only lines containing "error"
bgrun tail server --level error
Output (JSON)
{
"lines": [
{"line_number": 42, "content": "listening on :8080", "timestamp": null},
{"line_number": 43, "content": "GET / 200 OK", "timestamp": null}
]
}
Human output colorizes errors in red and warnings in yellow.
diff
Show log lines added since the last diff call (tracked via cursor).
bgrun diff <ID> [--lines <N>] [--stream <S>] [--strip-ansi] [--filter-regex <R>]
Flags
| Flag | Description |
|---|---|
--lines <N> | Number of lines to show (unlimited if not set) |
--stream <S> | Filter by stream source (stdout, stderr, pty) |
--strip-ansi | Strip ANSI escape codes from output |
--filter-regex <R> | Filter log lines matching a regex pattern |
Examples
# First call: all log content
bgrun diff server
# Later: only new lines since last call
bgrun diff server
Output (JSON)
{
"cursor": 2048,
"lines": [
{"line_number": 100, "content": "some new output", "timestamp": null}
]
}
wait
Block until a job reaches Ready state, or a timeout elapses. If the job exits or crashes before becoming ready, returns immediately with the terminal state and exit code.
bgrun wait <ID> [--timeout <DURATION>]
Examples
# Wait up to 60s
bgrun wait server
# Wait up to 5 minutes
bgrun wait db --timeout 5m
Output (JSON)
{"ready":true,"elapsed_ms":1234,"exit_code":null,"state":null}
If the job exits with code 0 before becoming Ready (pattern not matched):
{"ready":false,"elapsed_ms":350,"exit_code":0,"state":"exited"}
If the job crashes before becoming Ready:
{"ready":false,"elapsed_ms":150,"exit_code":1,"state":"crashed"}
If the timeout elapses while the job is still Running:
{"ready":false,"elapsed_ms":60000,"exit_code":null,"state":null}
kill
Terminate a job by ID, name, or entire workspace.
bgrun kill [<ID>] [--name <NAME>] [--workspace <WS>]
Flags
| Flag | Description |
|---|---|
--name / -n <NAME> | Job name (alternative to positional ID) |
--workspace <WS> | Kill all jobs in a workspace |
Sends SIGTERM first, then SIGKILL after 5 seconds if the process hasn’t exited. Sends to the entire process group, so child processes are cleaned up.
Examples
# Kill by ID
bgrun kill abc123
# Kill by name
bgrun kill server
bgrun kill --name server
# Kill all jobs in a workspace
bgrun kill --workspace myapp
Output (JSON) — single kill:
{"killed":["abc123"]}
Workspace kill:
{"killed":["abc123","def456"]}
stop
Gracefully stop a job: SIGTERM (escalating to SIGKILL after the grace period), then mark it Killed.
bgrun stop <ID> [--timeout <DURATION>]
| Flag | Description |
|---|---|
--timeout <D> | Grace period before SIGKILL escalation (e.g. 5s, default: 10s) |
Unlike kill, stop also works on terminal-state jobs (Exited/Crashed): marking them Killed suppresses any pending policy restarts, so stop can break an --restart always loop that kill refuses to touch.
bgrun stop server
bgrun stop server --timeout 5s
Output (JSON): {"stopped":["abc123"]}
restart
Stop the live process (if any) and re-spawn the job from its stored definition — command, env, cwd, readiness, restart policy — returning the new record. No backoff is applied; the failure streak resets but the lifetime restart count is preserved.
bgrun restart <ID> [--timeout <DURATION>]
| Flag | Description |
|---|---|
--timeout <D> | Grace period for stopping the old process (e.g. 5s, default: 10s) |
bgrun restart server
bgrun restart abc123 --timeout 5s
export
Write a job’s log history to a file — spanning rotated generations oldest-first (unlike tail/diff, which read only the live log).
bgrun export [<ID>] [--name <NAME>] [--file <PATH>] [--lines N] [--level L] [--stream S] [--strip-ansi] [--filter-regex <RE>] [--since <D>]
| Flag | Description |
|---|---|
--file <PATH> | Destination (default: ./bgrun-<id>.log). Relative paths resolve against your cwd |
--lines <N> | Export only the last N matching lines (default: all) |
--level <L> | Keep lines containing this substring (case-insensitive, e.g. error) |
--stream <S> | Keep one stream: stdout, stderr, or pty |
--strip-ansi | Strip ANSI escape codes |
--filter-regex <RE> | Keep lines matching this regex (invalid patterns are an error) |
--since <D> | Only entries from the recent past (e.g. 30m, 2h). Lines without a parseable timestamp are kept |
bgrun export server --file ./server.log --level error --since 1h
bgrun export abc123 --lines 200 --strip-ansi
Output (JSON): {"path":"/abs/path/server.log","lines":142}
send
Write data to a job’s stdin.
bgrun send <ID> [<DATA>] [--newline] [--enter]
Flags
| Flag | Description |
|---|---|
--newline | Append a newline to the data (deprecated: use --enter instead) |
--enter | Send just an Enter (newline), optionally with data |
Examples
# Send text
bgrun send server "/reload"
# Append newline
bgrun send server "/reload" --newline
# Send just Enter (press Return)
bgrun send server --enter
# Send text followed by Enter
bgrun send server "yes" --enter
# Using shell escape
bgrun send server $'yes\n'
Output (JSON)
{"ok":true}
Works with both piped and --pty jobs.
stats
Show CPU and memory usage of a running process.
bgrun stats <ID>
Examples
bgrun stats server
Output (JSON)
{"cpu_pct":2.4,"rss_mb":48,"uptime_secs":3600}
| Field | Meaning |
|---|---|
cpu_pct | CPU usage percentage (across all cores) |
rss_mb | Resident memory in MB |
uptime_secs | Process uptime in seconds |
skill
Install the embedded skill bundle to a target directory.
bgrun skill install <DIR>
Examples
bgrun skill install ~/.config/opencode/skills/bgrun
Output
Installed skill to /home/user/.config/opencode/skills/bgrun/SKILL.md
attach
Attach to a PTY job’s interactive terminal. Enables raw bidirectional communication with a process running in a pseudo-terminal.
bgrun attach <ID>
Examples
bgrun attach server
Once attached, the terminal enters raw mode:
- Keystrokes are forwarded to the PTY job’s stdin.
- The job’s PTY output is displayed live.
- Ctrl+C detaches without killing the job (unlike a normal terminal).
- *Ctrl+* (SIGQUIT) is also forwarded but may terminate the job.
- Terminal resize events are forwarded to the PTY master.
The connection is closed automatically when the job exits.
screen
Show last N lines from a job’s in-memory ring buffer (non-blocking). Unlike bgrun tail, this reads from a live memory buffer rather than disk, making it suitable for rapid polling without I/O overhead.
bgrun screen <ID> [--lines <N>]
Flags
| Flag | Description |
|---|---|
--lines <N> | Number of lines to show (default: 20) |
Examples
# Last 20 lines
bgrun screen server
# Last 5 lines
bgrun screen server --lines 5
Output (JSON)
["line 1", "line 2", "line 3"]
Human output prints each line directly.
clean
Remove all terminated (crashed/exited/killed) jobs.
bgrun clean [--workspace <WS>] [--force]
Flags
| Flag | Description |
|---|---|
--workspace <WS> | Only clean jobs in this workspace |
-f / --force | Skip confirmation prompt |
Examples
# Remove all terminated jobs
bgrun clean
# Remove only terminated jobs in a workspace
bgrun clean --workspace myapp
# Skip confirmation
bgrun clean --force
Output (JSON)
{"removed":["abc123","def456"]}
expect
Wait for a pattern to appear in a job’s log output. Returns when the pattern is found or the timeout expires.
bgrun expect <ID> <PATTERN> [--regex] [--timeout <DURATION>]
Flags
| Flag | Description |
|---|---|
--regex | Treat pattern as a regular expression |
--timeout <D> | Max wait time, e.g. 30s, 5m (default: 60s) |
Examples
# Wait for substring
bgrun expect server "listening on"
# Wait for regex
bgrun expect server "http://localhost:\d+" --regex
# With custom timeout
bgrun expect server "ready" --timeout 10s
Output (JSON) — on match:
{"matched":true,"line_number":42,"content":"listening on :8080"}
On timeout:
{"matched":false,"line_number":null,"content":null}
schema
Print JSON Schema (draft-07) for a command’s argument struct. Designed for AI agents to discover the expected input shape at runtime.
bgrun schema <COMMAND>
Supported commands: run, kill, tail.
Examples
bgrun schema run
bgrun schema kill
bgrun schema tail
Output (JSON) — a standard JSON Schema document with title, type, properties, and required fields.
completions (hidden)
Hidden subcommand for shell autocomplete scripts. Prints tab-separated job information for shell tab-completion, or generates full completion scripts.
bgrun completions --active-ids
bgrun completions --workspaces
bgrun completions --shell fish
bgrun completions --shell bash
bgrun completions --shell zsh
Flags
| Flag | Description |
|---|---|
--active-ids | Print active short IDs with state descriptions |
--workspaces | Print unique active workspaces |
--shell <fish|bash|zsh> | Generate a complete completion script for the given shell |
Installation
# Fish
bgrun completions --shell fish > ~/.config/fish/completions/bgrun.fish
# Bash
bgrun completions --shell bash | sudo tee /etc/bash_completion.d/bgrun
# Zsh
bgrun completions --shell zsh > /usr/local/share/zsh/site-functions/_bgrun
Dynamic completion integration
The --active-ids and --workspaces flags produce live data from the daemon, used by shell functions:
# In ~/.config/fish/completions/bgrun.fish:
complete -c bgrun -n "__fish_seen_subcommand_from status kill wait tail diff send stats attach expect" -a "(bgrun completions --active-ids)"
complete -c bgrun -n "__fish_seen_subcommand_from list kill; and __fish_prev_arg_in --workspace" -a "(bgrun completions --workspaces)"
Interactive menu
Running bgrun -i (or bgrun with no subcommand) opens an interactive menu:
- Workspace filter — optionally scope the whole session to one workspace
- Dashboard — live counts on every loop (
N job(s) · M alive · K terminated) - Browse jobs — filterable picker (
short-id | name [state] | command), then a per-job submenu: status + stats, tail (with lines/digest/level prompts), screen buffer, diff, send stdin, wait until ready, expect pattern, PTY attach, graceful stop, restart from stored definition, kill (with confirm) - Start a new job — prompts for command, name, ready pattern, env vars, and optional wait-until-ready
- Clean terminated jobs — remove exited/crashed/killed jobs in scope
- Change workspace filter / Exit
ESC goes back a level; Ctrl+C exits. The job list is populated live from the daemon.
ID resolution
All commands that accept a job ID also accept:
- Full UUID — the canonical job identifier
- Job name — as set with
--name - Unique prefix — at least 4 characters of the UUID that match exactly one job
bgrun status abc1 # prefix match
bgrun status my-server # name match
bgrun status abc12345... # full UUID
Job States
Jobs transition through these states:
Starting ──► Running ──► Ready
│ │
▼ ▼
Exited Crashed (non-zero exit / SIGKILL)
Killed (explicit kill)
A job in any of Starting, Running, or Ready is considered “alive.” Exited, Crashed, and Killed are terminal states.