# 3pm — full documentation > 3pm is a fast, robust process manager written in Rust, with the pm2 workflow (same commands, ecosystem.config.js works): one binary that is both CLI and daemon, zero-downtime self-update, process trees, host metrics. Application metrics, events and remote actions come from SDKs for Node.js, Python, C++ and Rust. `3pm link` joins a host to 3pm-backend, a fleet backend (buckets of hosts, live dashboard, JSON HTTP API, SSE feed). Generated 2026-10-13T15:51:31Z from https://3pm.edgecr4ft.net/llms.txt. Each document starts with a `` line naming its URL. # 3pm concepts The model behind every command, SDK call and API route, in one page. Each section ends with the document that goes deeper. ## The process manager - **One binary.** `3pm` is both the CLI and the daemon. The first command spawns the daemon (detached, its own session); a lock guarantees exactly one daemon per home. - **Home.** `~/.3pm`, or `$THREEPM_HOME`. It holds the sockets, `3pm.log` (the daemon's own log), `logs/-out.log` / `-error.log`, `pids/`, `dump.json` (`3pm save`), the optional `config.toml`, the installed `modules/`, the files actions leave in `actions/`, and the fleet link state in `agent/`. - **Sockets.** The CLI and the daemon talk NDJSON over Unix sockets: `rpc.sock` (request/response), `pub.sock` (event bus: lifecycle, log lines), `ctl.sock` (apps talking back: readiness, graceful stop, application metrics, actions), `host.sock` (the host-metrics agent). Wire catalogue: [protocol.md](protocol.md). - **App and instance.** An app is a name owning N instances (`-i N`). Each instance is a process row with its own `id`, pid, status and restart counter, and gets `THREEPM_INSTANCE` = 0…N-1. Commands target a name, an id, a glob (`'api-*'`), `all`, or every app of an ecosystem file. - **Status.** `launching` → `online`; `stopping` → `stopped`; `waiting restart` (backoff); `errored` (crash loop: 16 exits under `min_uptime`, re-armed by `3pm restart`). - **Supervision.** Restart policy `always` (default) / `on_failure` / `never`; instant restart or exponential backoff; stop = `kill_signal` (SIGINT) to the process group, then SIGKILL after `kill_timeout`; memory/CPU guards on the whole process tree; cron restarts; watch mode. - **Ecosystem file.** The declarative form of `3pm start`: TOML, JSON, YAML, or pm2's `ecosystem.config.js`. `validate` checks it, `apply` reconciles the daemon with it (create / restart changed / leave the rest), profiles with `--env`. [ECOSYSTEM.md](ECOSYSTEM.md). - **Readiness and graceful stop.** An app connects to `$THREEPM_CTL_SOCK`, says `hello`, then `ready` (`--wait-ready`) or receives `shutdown` (`--shutdown-with-message`). Any language, a few lines. - **Logs.** Captured per instance, rotated by the daemon (20 MB × 5, 14 days by default), streamed live by `3pm logs` from the event bus. [logs.md](logs.md). - **Persistence.** `3pm save` writes `dump.json`, `3pm resurrect` restores it, `3pm startup` installs a boot service (systemd, launchd…) that does. - **Zero-downtime update.** `3pm update` hands the daemon off to the new binary in place: same pids, same pipes, apps keep running. `install.sh` run again does it. - **Containers.** `3pm runtime` is a PID 1 entrypoint: foreground, output streamed, exits when nothing is left to supervise. [RUNTIME.md](RUNTIME.md). - **Hosted users.** A root daemon can host other accounts: one socket set per account, each seeing only its apps. [logs.md](logs.md) (`[users]`). - **Resources.** Soft guards (`max_memory_restart`, `max_cpu_percent`), hard cgroup v2 limits (`cgroup_enforce`, Linux), `deny_gpu`. [resources.md](resources.md). - **Modules.** Optional features shipped next to the binary and run as apps: `serve` (static file server, [SERVE.md](SERVE.md)) and `agent` (the fleet link). [modules.md](modules.md). ## Metrics | Layer | Where it comes from | Read with | |---|---|---| | Process | CPU and memory of each instance's whole process tree, every second | `3pm ls`, `3pm ls --tree`, `3pm show` | | Host | A separate host-agent process, cached, in three tiers (1 s / 10 s / 5 min): CPU, PSI, memory, disks, RAID, network, TCP, sensors, GPUs, NTP | `3pm hostmetrics` | | Daemon | 3pm's own memory, fds, supervision counters | `3pm internals` | | Application | What the app reports through an SDK: gauges, counters, meters, histograms, events, errors | `3pm show `, `3pm events -f app` | References: [metrics.md](metrics.md), [hostmetrics.md](hostmetrics.md), [app-metrics.md](app-metrics.md). ## SDKs Three SDKs with the same surface, talking to `$THREEPM_CTL_SOCK`; outside 3pm every call is a no-op, and none of them blocks or throws. | SDK | Language | Install | Reference | |---|---|---|---| | `@3pm/api` | Node.js ≥ 18, Electron | `npm i https://3pm.edgecr4ft.net/sdk/node/3pm-api-.tgz` | [sdk/node.md](sdk/node.md) | | `threepm-io` | Python ≥ 3.9 | `pip install --index-url https://3pm.edgecr4ft.net/simple/ threepm-io` | [sdk/python.md](sdk/python.md) | | `threepm_io.hpp` | C++17, header-only | CMake `FetchContent` from `https://3pm.edgecr4ft.net/sdk/cpp/` | [sdk/cpp.md](sdk/cpp.md) | Versions and sha256 of every archive: `https://3pm.edgecr4ft.net/sdk/sdk.json`. - **Metrics**: `gauge`, `counter` (cumulative), `meter`, `histogram` (base-2 exponential), `metric(name, fn)` (a gauge read at every flush); labels, at most 50 label sets per metric. - **Events**: `event(name, {level, attrs})`, `notifyError(err)`. - **Actions**: `io.action(name, handler)` exposes a function to `3pm trigger ` and to the fleet backend; `3pm:profile` (CPU or heap profile, Node) is built in and driven by `3pm profile `. - **Node only**: the programmatic client `ThreePM` (pm2's API: `start`, `list`, `stop`, `restart`, `delete`, `launchBus`), and fleet calls `io.call` / `io.open` / `io.stream` to other nodes. ## The fleet: `3pm link` and `3pm-backend` `3pm-backend` is the server side: one binary (axum + SQLite), optional VictoriaMetrics (metrics) and VictoriaLogs (events) behind it, a dashboard and a JSON API. A host running 3pm joins it with `3pm link`. | Thing | Identifier | What it is | |---|---|---| | Account | token `3pmu_…` | Owns buckets. The API takes it as `Authorization: Bearer 3pmu_…`; the dashboard trades it for a session cookie. The first account registered adopts existing buckets. | | Bucket | cluster id `3pmc_…` | A group of hosts and its certificate authority. The pasted cluster key is `3pmc_` or `3pmc_.`. | | Enrollment token | `3pmk_.` | Minted per bucket, pasted once: `3pm link 3pmc_… 3pmk_… wss://backend`. | | Node | `3pmn_…` | One enrolled host, with a key and a certificate. `pending` until approved (unless the token pre-approves), revocable. Presence: `online`, `stale` (3 s without a frame), `offline` (30 s). | | Session | `3pms_…` | One live WebSocket link (`/api/v1/link`, sub-protocol `3pm.link.v1`). | | Node bearer | `3pma_…` | Minted for the node in every `welcome`: lets the node call the backend's HTTP routes itself, within the scopes its owner grants (`fleet:list`, `fleet:read`, `fleet:invoke`). | | Capabilities | `metrics:read`, `proc:restart`, `proc:stop`, `proc:action` | What an agent offers the backend (`3pm link --cap`). | - **Telemetry**: the agent sends the redacted process table and host gauges about once a second, a full host frame every 60 s, application metrics and process trees when they change. The backend keeps a live window in memory, persists to VictoriaMetrics/VictoriaLogs when configured. - **Live feed**: `GET /api/buckets/{clusterId}/events` (SSE): `init`, then `node`, `telemetry`, `emit`, `call`, `artifact`. - **Calls**: `nodeCall` (`restart`, `stop`, `ping`) and `nodeAction` (an `io.action`) place a command on a node; its state goes `sent` → `acked` → `replied` (or `unacked`, `refused`, `lost`); read with `getCall`. Files it leaves (profiles, dumps) are artifacts, kept 30 days. - **Node to node**: `3pm fleet nodes|apps|inspect|top|call` and `io.call` use the node's own bearer. References: the HTTP API [backend/api.md](backend/api.md) (every route, its body, answer and auth), the backend's features [backend/features.md](backend/features.md), the agent [fleet/agent.md](fleet/agent.md), the wire protocol [fleet/link-protocol.md](fleet/link-protocol.md). ## Distribution - `curl -fsSL https://3pm.edgecr4ft.net/install.sh | sh`: macOS and Linux (glibc ≥ 2.28), x86_64 and arm64, into `~/.3pm/bin`; rerun to update in place. - `https://3pm.edgecr4ft.net/latest/version.json`: the current release, its assets and sha256. # 3pm A fast, robust process manager, written in Rust. `3pm` keeps your apps alive: it daemonizes them, restarts them when they crash, aggregates their logs, and tracks the CPU/memory of their whole process tree — with the pm2 workflow you already know. ```console $ 3pm start app.js [3PM] Spawning 3pm daemon with home=/Users/you/.3pm [3PM] App [app] launched ┌────┬──────┬───────┬────────┬───┬────────┬──────┬────────┐ │ id ┆ name ┆ pid ┆ uptime ┆ ↺ ┆ status ┆ cpu ┆ mem │ ╞════╪══════╪═══════╪════════╪═══╪════════╪══════╪════════╡ │ 0 ┆ app ┆ 4021 ┆ 0s ┆ 0 ┆ online ┆ 0.0% ┆ 12.3mb │ └────┴──────┴───────┴────────┴───┴────────┴──────┴────────┘ ``` ## Install ```console curl -fsSL https://3pm.edgecr4ft.net/install.sh | sh # any platform; rerun to update curl -fsSL https://releases.3pm.dev/setup-apt.sh | sudo sh # Debian/Ubuntu curl -fsSL https://releases.3pm.dev/setup-yum.sh | sudo sh # RHEL/Fedora ``` Or grab a tarball / `.deb` / `.rpm` from the [releases page](https://github.com/Unitech/3pm/releases), or build from source: `cargo install --path crates/threepm-cli`. ## Commands | Command | What it does | |---|---| | `3pm start