pm2, rewritten in Rust

shep keeps
your flock
alive.

One binary runs a daemon called the shepherd. It restarts your processes when they die, captures what they print, and says plainly when something is wrong.

Get started →
scroll — the sun comes up ↓
the flock, listed
~/apps
$ shep ls
ID NAME STATUS PID RESTARTS CPU MEM UPTIME FOLD
1 web online 1001 1 12.5% 48.1M 1m backend
2 worker online 1002 2 12.5% 48.1M 2m backend
3 cron online 1003 3 - 48.1M 30s backend

The CPU column prints - rather than 0.0% when a reading is unavailable. A confident zero is worse than an obvious blank.

two fields is a whole Flockfile

A typo fails at load, not at 3am.

[[app]]
name = "web"
script = "./server"

Unknown fields are a parse error rather than a shrug, and sizes are strict on purpose: 512M and 30s parse;512MB and 1.5G do not.

two ship inside the binary

Dogs work for the shepherd.

A dog is a plugin the shepherd supervises for its own sake: it watches the flock rather than being part of it.

$ shep enable metrics
prometheus on 127.0.0.1:9615
$ shep enable bark
alerts to discord, slack, or your own json
pre-releaseand honest about it

Not on crates.io. No tagged release. No install script. You build it from source, and it runs on macOS and Linux. On Windows every command prints shep does not yet support Windows and exits 1 — a real answer, but not a useful one.

See exactly what's missing

Fifteen words carry the whole product.

The sheep are a mnemonic, not a costume. Where the joke would cost clarity it gets dropped — and every themed verb has a straight alias that works forever.

the flock
Every managed process, as a set. Always the plural term.
shep flock · list · ls
a sheep
One managed process. Singular only, so nothing is ambiguous.
shep describe web
the shepherd
The daemon — and only ever the daemon.
log messages, docs
bleats
Logs. shep logs is the same command and always will be.
shep bleats --follow
a fold
A namespace or group of sheep.
shep fold backend
muster
Bring a saved flock back after a reboot.
shep save · shep muster

Why you'd switch

Same feature list as pm2. Different opinions about what a supervisor owes you at 3am.

1

There is no shepd

Daemonizing means the shep binary re-execs itself with a hidden subcommand, detaches, and reports readiness back over a pipe once its socket is bound.

2

A crash loop isn't a healthy start

Exponential backoff, a restart budget, and min_uptime so a process that dies immediately is never mistaken for one that came up fine.

3

Everything renders as JSON

Every command answers under a versioned envelope with a schema_version, so you can pipe it somewhere instead of scraping columns out of a table.

4

reload's own --help says it isn't zero-downtime

shep binds no sockets, so an overlap only works if your app sets SO_REUSEPORT itself. Measured on Linux: an app that drains its listener loses nothing.

5

pm2's source was read exactly once

By a dedicated tracing phase whose only output was behavior specs. Implementation never opens that source — a rule written into the repo's contributor instructions.

6

shep import brings your dump.pm2 over

It starts nothing, names every clustered app on stderr, and refuses to silently swallow env keys it cannot place.

today on the board

What's not built yet

Windows is last, and it is genuinely zero rather than partial. The workspace cross-compiles for it and that check runs on every change, but no test has ever executed there, only a compile.

lookout's bleats feed, sheep pane, host stripthe whistle MCP servershep serveshep devshep runtime.js Flockfilesa schemars config JSON schemaa CLI-flag config layeropenrc and BSD rc.d unitsOTLP exportWindows, entirely

Build it and tell me
what breaks.

Rust 1.88 or newer, edition 2024. Over a thousand tests, and every task ends with a mutation pass: break a line on purpose, confirm a test goes red, put it back.

MIT OR Apache-2.0, at your option.