Pistis

Operate

Set limits, watch health, upgrade, rotate keys and read the logs.

What to set, watch and do once Pistis runs for a team.

Limits and capacity

KeyMeaning
sandboxes.cpu, memory, pidsLimits for each sandbox: CPUs, memory such as 4g, and processes (default 1024)
sandboxes.maxThe most sandboxes at once. A new sandbox past it is refused; the session says why, and the log has sandbox.refused. Existing sandboxes stay reachable.
sandboxes.warmSpare sandboxes kept ready per server, so new sessions start at once. Must be below max.

A test with a cap of two: box limits 1 CPU / 512 MiB / 256 pids; a third box refused at sandboxes.max 2 (said and logged).

Health and metrics

Set metricsPort to serve /metrics for Prometheus and /healthz. They listen on 127.0.0.1, or on metricsHost inside a private network. Scrape every Pistis server and watch the p95, not averages.

MetricMeaning
pistis_tool_call_secondsEach command, by tool and outcome: ok, error or unknown (cut off)
pistis_sandbox_lease_secondsTime to get a session's sandbox ready
pistis_turn_secondsA message, from accepted to finished
pistis_tool_unknown_totalCommands cut off by a crash
pistis_sessions_liveSessions not ended
pistis_warm_boxesSpare sandboxes ready

Alert when /healthz returns 503, which names the failing check. Also alert on a rising p95 of pistis_tool_call_seconds, any rise of pistis_tool_unknown_total, and pistis_warm_boxes at zero. See Speed for every timing.

Upgrade

Back up, change the version, and restart the servers one at a time: see Upgrade. A new version updates the database when it starts, in one transaction, and records each change in schema_migrations; upgrades go forward only.

Rotate the secret key

PISTIS_SECRET_KEY encrypts the secrets people enter in the web app.

  1. Stop every Pistis server.
  2. Run pistis rotate-secret with the current and the new key:
$ PISTIS_SECRET_KEY=<current> PISTIS_NEW_SECRET_KEY=<new> pistis rotate-secret --config pistis.json
re-sealed 3 secrets in 2 rows; start every brain with PISTIS_SECRET_KEY set to the new key
  1. Start every server with PISTIS_SECRET_KEY set to the new key.

If one secret doesn't open with the current key, nothing changes and the command names it. API tokens are unaffected. The built-in secret store (people's MCP credentials) and pending OAuth PKCE verifiers are re-encrypted too; a store from a plugin keeps its own keys. If rotation reports legacy MCP credentials, start the server once with the old key to adopt them, then stop every server before rotating.

Docker access

Access to the Docker socket is root on the host, so Pistis servers don't get it. pistis docker-proxy --namespace <ns> holds the socket and lets Pistis create, start, stop, pause and delete its own sandboxes and networks. It refuses privileged containers, host mounts, exec, image pulls and builds, and logs each refusal as docker-proxy.refused. The compose file runs it as the docker-proxy service.

Logs

Every decision off the normal path is one JSON line with its reason: sandbox.refused, sandbox.replaced, checkpoint.skipped, sync.blocked, tool.unknown, token.revoked, docker-proxy.refused and the policy's refusals. A step stopped after repeated crashes is logged as pi.report (task_parked) and waits for its owner or an admin to retry it (Sessions).

Several servers

Pistis servers that share one Postgres share every session. One server handles each session at a time. If a server stops answering, another cuts off its database connection and takes over its sessions. Sessions are split between servers in a fixed number of shards: set it once with fleet.shards and never change it.

On this page