budom is a per-user background daemon manager for Linux/Unix user processes.
Example terminal log:
$ budom run --kind service --name demo --tag project.example --tag purpose.demo -- /bin/sh -lc 'while true; do echo hello; sleep 1; done'
3mZ7aK2pQ9xT
$ budom ps
ID NAME DESIRED STATE PID RESTARTS TAGS
3mZ7aK2pQ9xT demo Running Running 482311 0 project.example,purpose.demo,kind.service
$ budom logs demo --tail 3
hello
hello
hello
$ budom stop demo
$ budom ps --all
ID NAME DESIRED STATE PID RESTARTS TAGS
3mZ7aK2pQ9xT demo Stopped Exited - 0 project.example,purpose.demo,kind.service
It provides:
- run/list/inspect/start/stop/restart/remove lifecycle management
- a per-user supervisor process (no systemd dependency)
- reboot recovery with explicit
budom recovercommand - restart policies with exponential backoff
- raw stdout/stderr log capture and size-based rotation
- stable job names and short/partial ID references
- tag-based targeting for bulk stop/remove operations
- explicit service and one-shot job kinds
cargo build --releaseInstall locally:
install -m 755 target/release/budom ~/.local/bin/budomRun a long-lived process that Budom may start again after a reboot:
budom run --kind service --name demo --tag project.example --tag purpose.demo -- /bin/sh -lc 'while true; do echo hello; sleep 1; done'Run a task once. A completed or interrupted one-shot stays stopped across
supervisor restarts and budom recover calls:
budom run --kind one-shot --name rebuild-index --tag project.example --tag purpose.index-rebuild -- /path/to/rebuild-indexbudom start rebuild-index explicitly arms one more attempt. One-shots reject
--restart always and --restart on-failure because those rules conflict with
run-once behavior.
Every run command requires --kind service or --kind one-shot. Budom adds
the reserved kind.service or kind.one-shot tag. Add concrete project and
purpose tags so operators can find related jobs without relying on names.
Load environment variables from a file and override specific keys inline:
budom run --kind service --name demo --env-file .env --env PORT=8080 -- /path/to/serverDelay a service's manual/recovery start without needing extra flags later:
budom run --kind service --name api --start-delay 10s -- /path/to/apiList running jobs:
budom psInspect details:
budom inspect demo --jsonRead logs:
budom logs demo --tail 50Recover desired-running services after reboot:
budom recoverRecover quietly while still returning failure via exit status:
budom recover --quietOnly recover when supervisor is down:
budom recover --if-supervisor-downInterleave logs from all daemons matching tags (colorized per daemon):
budom logs --tag api --tag blue --tail 100 -fStop one or many jobs:
budom stop demo other-job 01abcdeStart one or many stopped jobs:
budom start demo other-job
budom start --tag api --tag blueRestart one or many jobs:
budom restart demo other-job
budom restart --tag api --timeout 5sRemove job state:
budom rm demo --forceRun with tags:
budom run --kind service --name api-a --tag project.example --tag purpose.api --tag blue -- /bin/sh -lc 'sleep 9999'Filter by tags:
budom ps --tag api --tag blueStop/remove by tags:
budom stop --tag api --tag blue
budom rm tag:api --forceReplace an existing named daemon:
# Graceful replace: TERM, wait (default 10s), then KILL if needed
budom run --kind service --name api-a --replace --replace-timeout 15s -- /path/to/new-binary
# Force replace: immediate forced removal of old daemon
budom run --kind service --name api-a --replace --force -- /path/to/new-binary
# Keep the replaced job's metadata and logs under its old ID
budom run --kind service --name api-a --replace --retain-replaced -- /path/to/new-binary
budom inspect OLD_JOB_ID --retained --json
budom logs OLD_JOB_ID --retained --tail 100--retain-replaced keeps a hard-linked snapshot under
$XDG_DATA_HOME/budom/retained/OLD_JOB_ID. Budom prints the retained ID to
standard error. The retained status describes the process at snapshot time; it
is not a live process state. Use the old job ID or a unique ID prefix with
inspect --retained and logs --retained.
Commands that take a <ref> accept:
- exact name
- exact full ID (case-sensitive)
- unique ID prefix (including 1 character if unique)
tag:<tag>selectors (for commands supporting multi-target refs, likestop/restart/rm)
If a prefix is ambiguous, the command fails with an ambiguity error.
Checks used for CI/public quality:
cargo fmt --check
cargo clippy --all-targets --all-features -- -D warnings
cargo testMIT (see LICENSE).
The CLI publishes meta.json after the remaining job files and keeps a separate
registration lock through the supervisor's first Run request. Named creators
also serialize replacement and creation for that name. Incomplete unpublished
records do not appear in job lists.
If a creating CLI dies before the supervisor receives Run, a later targeted command can recover that CLI's complete record. It checks the creation marker, account, schemas, and absence of any PID or execution history, then marks the abandoned job stopped before registering it. Inspect, stop, remove, and replacement never execute that abandoned command. An explicit start remains an instruction to execute it. Recovery refuses legacy or malformed abandoned records instead of guessing whether they have run.
This CLI works with the existing one-shot-aware supervisor. Installing it does not require restarting that supervisor or disturbing other jobs and log pipes. A newly started supervisor also leaves an abandoned creation stopped. Do not kill a running supervisor to upgrade it: the current supervisor owns child log pipes and cannot transfer them to a replacement.
Run the normal test suite with cargo test --workspace. To repeat registration
and real CLI interruption tests against an older supervisor binary:
BUDOM_TEST_OLD_BINARY=/absolute/path/to/prior/budom cargo test registration