A modern process management and scheduling platform — a drop-in replacement for supervisord with a web dashboard, a terminal UI and a scriptable CLI.
Starfleet takes over a box: long-running processes under supervision, cron jobs on a schedule, logs you can actually read, and configuration you can change without a restart. Three interfaces share one engine — a web dashboard, a keyboard-driven TUI, and a CLI that scripts well.
Process supervision
- Full lifecycle: start / stop / restart, per-process user switching
- supervisord-compatible semantics:
startsecs/startretries/autorestart(true/false/unexpected) /exitcodes - Crash-loop protection with exponential backoff (
restart_delay,backoff_limit) - Boot-start toggling (
autostart) from the UI — persisted to the config file - Log rotation exactly like supervisord (
maxbytes+backups) - Health checks over HTTP / TCP with automatic restart
Scheduling
- Standard 5-field cron and
@everysyntax - Enable/disable jobs without deleting them, run them on demand
- Execution history with exit codes, duration and captured output
Interfaces
- Web dashboard (Vue 3, embedded in the binary) — dark UI, auto-refresh,
login gate when
server.authis enabled - TUI (bubbletea) with the same columns and keyboard shortcuts
- CLI for servers and scripts (auth credentials from config, flags or env)
- Real-time log streaming over WebSocket, plus polling fallbacks
Operations
- Hot reload of the whole configuration (file watcher, API, or
SIGHUP) — auth changes apply live, un-reloadable fields warn that a restart is needed - Split configuration: main file +
conf_dir/conf.d/includes - Webhook notifications on process and schedule events
- Optional web UI (
server.web.enabled: false) for headless deployments - Prometheus-style system overview endpoint
Prebuilt binaries for linux/amd64, linux/arm64, linux/armv7, darwin/amd64,
darwin/arm64 are attached to every release
together with checksums.txt.
VER=v1.2.1
curl -sL -o starfleet.tar.gz \
"https://github.com/snail2sky/starfleet/releases/download/${VER}/starfleet_${VER}_linux_amd64.tar.gz"
echo "<sha256 from checksums.txt>" | sha256sum -c
tar xzf starfleet.tar.gz
sudo install -m 755 starfleet_${VER}_linux_amd64/starfleet /usr/local/bin/
starfleet versionBuild from source instead (Go 1.24+, Node 20+):
git clone https://github.com/snail2sky/starfleet.git
cd starfleet
make # builds the frontend, then the binary into bin/sudo mkdir -p /etc/starfleet/conf.d
sudo cp configs/starfleet.yml /etc/starfleet/starfleet.yml
# put one process per file in conf.d/, see docs/configuration.md
sudo vim /etc/starfleet/starfleet.yml
starfleet validate # check config before the first run# systemd (recommended)
sudo cp deploy/systemd/starfleet.service /etc/systemd/system/
sudo systemctl enable --now starfleet
sudo systemctl status starfleet
# or in the foreground
starfleet serve -c /etc/starfleet/starfleet.ymlOpen http://server:8080 for the dashboard, or starfleet tui on the box.
Every release tarball also ships a runnable demo under examples/demo/
(main config + a managed process + a cron schedule) — see its README.
deploy/stf is a wrapper that bakes in the binary and config paths so you
can skip them:
sudo install -m 755 deploy/stf /usr/local/bin/stf
stf status # instead of: starfleet -c /etc/starfleet/starfleet.yml status
stf tui
stf logs -fEdit the two paths at the top of /usr/local/bin/stf to match your install.
starfleet serve # run the API server + managed processes
starfleet tui # terminal UI (connects to a running server)
starfleet validate # validate configuration and exit
starfleet status # process states of the running server
starfleet start|stop|restart NAME # process lifecycle
starfleet logs [NAME] [-n N] [-f] # starfleet's own logs, or one process's
starfleet schedules # list scheduled jobs
starfleet run NAME # trigger a schedule now
starfleet reload # ask the server to hot-reload
starfleet version
Global flags: -c/--config (config path), --server (control commands
against a remote server). Full reference: --help on any subcommand.
📖 Full reference: docs/configuration.md — every supported field, file layout (
conf_dir/conf.d/includes), reload behaviour, and a supervisord field mapping.
# /etc/starfleet/starfleet.yml
conf_dir: conf.d # managed process/schedule fragments live here
server:
host: "0.0.0.0"
port: 8080
auth:
enabled: true
username: admin
password: "your-password" # plain text; WebUI shows a login page
secret: "at-least-32-chars-random-string"
web:
enabled: true # false = headless (API + TUI only)
processes: {} # or keep them inline — both work
schedules:
backup:
cron: "0 3 * * *"
command: "/opt/backup.sh"
timeout: 300s
enabled: trueA typical managed config, one file per service in conf.d/:
# /etc/starfleet/conf.d/nginx.yml
processes:
nginx:
command: "nginx -g 'daemon off;'"
directory: /etc/nginx
autostart: true
autorestart: "true"
startsecs: 3
stdout:
path: /var/log/nginx/out.log
maxbytes: "100M"
backups: 5
healthcheck:
type: http
url: "http://127.0.0.1/health"
interval: 30sstarfleet validate prints where every process came from, so you always
know which file to edit:
✓ configuration is valid: /etc/starfleet/starfleet.yml
conf dir: /etc/starfleet/conf.d (conf_dir)
loaded 4 config file(s):
- /etc/starfleet/starfleet.yml
- /etc/starfleet/conf.d/nginx.yml
processes: 2
All endpoints live under /api/v1. Optional auth via server.auth: the
API accepts HTTP Basic or a Bearer JWT issued by
POST /api/v1/auth/login (what the WebUI login page uses). CLI commands
read the same credentials from the config file.
| Method | Endpoint | Description |
|---|---|---|
| GET | /processes |
List all processes |
| GET | /processes/:name |
Runtime info and full config |
| POST | /processes/:name/start | /stop | /restart |
Lifecycle |
| POST | /processes/:name/enable | /disable |
Boot start, persisted to config |
| GET | /processes/:name/logs?lines=200&stream=stderr |
Captured output |
| Method | Endpoint | Description |
|---|---|---|
| GET | /schedules |
List jobs (includes next fire time) |
| GET | /schedules/:name |
One job |
| POST | /schedules/:name/run |
Trigger now |
| GET | /schedules/:name/history?limit=50 |
Execution history |
| POST | /schedules/:name/enable | /disable |
Schedule / pause, persisted to config |
| Method | Endpoint | Description |
|---|---|---|
| GET | /system/overview |
CPU / memory / disk / load / host |
| GET | /system/health |
Liveness probe |
| GET | /logs?lines=200 |
Aggregated logs from all processes |
| GET | /server/logs?lines=200 |
Starfleet's own logs |
| GET | /config |
Effective configuration (secrets masked) |
| POST | /config/reload |
Hot reload |
| WS | /ws/logs, /ws/events |
Real-time streams |
Both interfaces render the same columns in the same order, so switching between them costs nothing.
| Web UI | TUI | |
|---|---|---|
| Process columns | Name · State · Boot · PID · Uptime · Retries · Autorestart · Command | same |
| Schedule columns | Job · Schedule · Type · Enabled · Next run · Timeout · Command | same |
| Full process details | click row → dialog | Enter |
| Process logs | Logs tab | l |
| Starfleet's own logs | Logs page (default source) | 0 |
| Start / Stop / Restart | row buttons | s / t / r |
| Toggle boot start | Boot switch | e |
| Change autorestart | Autorestart cell (click to cycle) | R |
| Trigger a schedule | Run now | r (Schedules tab) |
| Enable/disable schedule | Enabled switch | e (Schedules tab) |
| Execution history | History | h (Schedules tab) |
| Today's runs (daily view) | Today panel + column | d (Schedules tab) |
| System overview | Overview page | — |
| Config status | Settings page | — |
Boot = starts automatically with starfleet (autostart);
Autorestart = restart policy when the process exits.
Every release also ships ipwatch, a small LAN presence tracker: it
sweeps a /24 every 15s (parallel pings + kernel neighbor table) and
records online/offline intervals + raw sightings in SQLite for later
analysis.
ipwatch -subnet 192.168.1.0/24 -db ipwatch.db # start recording
ipwatch -db ipwatch.db -summary # devices + today's episodes
sqlite3 ipwatch.db 'SELECT * FROM presence ORDER BY online_at DESC LIMIT 20'It also ships a read-only web dashboard (default :8095, -web to
change/disable): live online counts, a 24-hour presence timeline per
device, the device table and a recent UP/DOWN feed — auto-refreshes
every 5s. Keep it LAN-only (do not port-forward it to the WAN).
Tables: presence (ip, online_at → offline_at, mac), sightings
(ts, ip, mac, source, rtt_ms — 30d retention), devices (inventory).
Run it under starfleet for supervision (see conf.d/ipwatch.yml style).
docker compose -f deploy/docker-compose.yml up -dmake frontend # build the web UI into internal/api/dist
make test # go test ./... -race
make lint # golangci-lint
make build # embed + compile into bin/starfleet
make run # build then run with configs/starfleet.ymlCI runs on every push: lint, unit tests (race detector) and a matrix build
for linux/amd64 + linux/arm64. Tags build release binaries for five
platforms plus checksums.txt.
┌──────────────────────────────────────────────────────────┐
│ Interfaces │
│ Vue 3 web UI (embedded) · bubbletea TUI · CLI │
├──────────────────────────────────────────────────────────┤
│ Gin REST + WebSocket │
├───────────┬───────────┬─────────────┬────────────────────┤
│ Process │ Scheduler │Health check │ Event bus + │
│ engine │ (robfig) │ HTTP/TCP │ self log ring │
├───────────┴───────────┴─────────────┴────────────────────┤
│ config loader (conf_dir/conf.d/includes) + watcher │
└──────────────────────────────────────────────────────────┘
Field-by-field mapping is in docs/configuration.md. The differences worth knowing:
environmentis a YAML map, not a comma-separated stringstdout_logfile*become the nestedstdout:/stderr:objects- Starfleet writes the configured log files itself and rotates them
user:actually switches uid/gid (starfleet must run as root for that)autorestartis an explicit string; restart backoff is configurable- Hot reload replaces restart-to-apply-config
MIT License — see LICENSE.