Pure-Python client for PM2's daemon RPC socket
Project description
pm2-rpc
Pure-Python client for PM2's daemon RPC socket.
[!CAUTION] Experimental (v0.2.0) — Early-stage personal project. API may change without notice.
Talks directly to ~/.pm2/rpc.sock using PM2's pm2-axon / pm2-axon-rpc
wire stack (AMP framing → amp-message arg packing → axon-rpc body). The
runtime makes zero pm2 CLI subprocess calls — every operation is one
round-trip on the Unix socket. Returned values are plain dicts in PM2's
own shape, no extra abstraction.
Install
pip install pm2-rpc # core (only stdlib)
pip install 'pm2-rpc[yaml]' # add YAML ecosystem-config support
Requires Python ≥ 3.11 and a running PM2 daemon on the same host.
Quick start
import os
import pm2_rpc as pm2
# List
for p in pm2.list():
env = p["pm2_env"]
print(env["pm_id"], env["name"], env["status"])
# Describe (raises pm2.NotFound)
proc = pm2.describe("worker")
print(proc["pm2_env"]["restart_time"])
# Start a fresh process — no ecosystem file required
pm2.start("scripts/worker.py", name="worker", env={"DEBUG": "1"})
# Or from an ecosystem.config.{json,yaml}
pm2.start_ecosystem("ecosystem.config.json", only="worker")
# Flip an env var without re-reading the ecosystem file (avoids the
# `pm2 restart NAME --update-env` foot-gun where passing ecosystem.config.js
# silently overrides --update-env)
pm2.restart("worker", env={**os.environ, "APP_MODE": "suite"})
# Logs (tails the file PM2 writes on disk, no streaming)
print(pm2.logs("worker", lines=50))
print(pm2.error_logs("worker", lines=20))
# Teardown
pm2.stop("worker") # keeps the entry, status='stopped'
pm2.delete("worker") # removes it entirely
API
list() -> list[dict] |
All registered processes |
exists(name) -> bool |
Cheap existence probe |
describe(target) -> dict |
One process; raises NotFound |
start(script, **opts) -> dict |
Launch (fork mode); see kwargs below |
start_ecosystem(config, *, only=, cwd=) -> list[dict] |
.json/.yaml; .js raises UnsupportedConfigError |
restart(target, *, env=None) -> dict |
env merges server-side via Object.assign |
stop(target) -> dict |
Graceful stop, keeps entry |
delete(target) -> None |
Unregister |
env(target) -> dict[str, str] |
The runtime env the process sees |
logs(target, lines=15) -> str |
Last N lines of stdout |
error_logs(target, lines=15) -> str |
Last N lines of stderr |
pm2_rpc.start() kwargs use PM2's vocabulary: name, interpreter, cwd,
args, env, autorestart, out_file, error_file, merge_logs.
Low-level access if you need it:
from pm2_rpc import rpc_call, PM2Error
rpc_call("getMonitorData", {}) # raw axon-rpc round-trip
What's not supported (v0.2.0)
- Cluster mode (
exec_mode: "cluster",instances > 1) — fork-mode only. .js/.cjs/.mjsecosystem configs (require node to evaluatemodule.exports). Convert to.json/.yaml, usepm2_rpc.start()with app fields, or shell out topm2 start ecosystem.config.js --only NAME.- NVM-pinned interpreters (
exec_interpreter: "node@18.0.0"). filter_env, source-map auto-detection, watch mode.$PATHlookup of script names — pass an absolute path (useshutil.which()yourself if you really want a PATH binary).
Development
uv sync --group dev
uv run pytest tests/ # 64 tests, ~6s, requires a live PM2 daemon
uv run ruff check # lint
uv run ruff format # format (omit --check to apply)
uv run mypy # typecheck pm2_rpc/
CI runs lint + format + typecheck + the full 64-test suite + build on every PR — PM2 is installed from npm on the runner.
Fixture processes are named pm2rpc-test-* so they're easy to identify
if a test crashes and leaks one.
License
MIT — see LICENSE.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pm2_rpc-0.2.2.tar.gz.
File metadata
- Download URL: pm2_rpc-0.2.2.tar.gz
- Upload date:
- Size: 10.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
209efe9038686e3c4aaf948fffbf9d76857736f51c098f35cd82bf586b62addf
|
|
| MD5 |
c10ec7c4308c7102e6d9b7136460d07f
|
|
| BLAKE2b-256 |
6eaf1c6a1ce6278bd621241c82bbcf1a52abb95e482ca9e24f5bf2ef74abf8d2
|
File details
Details for the file pm2_rpc-0.2.2-py3-none-any.whl.
File metadata
- Download URL: pm2_rpc-0.2.2-py3-none-any.whl
- Upload date:
- Size: 13.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4e718d91ff263b87cf31b2f7e978ca9ca902b58a602b5360cbf800e6bd59e4f5
|
|
| MD5 |
c6937bb8e3ed1f61befd61d90266d29e
|
|
| BLAKE2b-256 |
9052fbd83732f744f43f2a4ed6b35c9ab5ee151b25019413f6c349123a4d9eb7
|