Skip to main content
piloop serve is the daemon: it starts the agents, scores the commits and enforces the limits of every campaign. One daemon runs for each PILOOP_HOME.
The campaigns stay active through all three. To hold one campaign and leave the others running:

Under a service manager

piloop service-unit prints a unit file. It installs nothing.
  • The unit carries your current PATH and the PILOOP_* and harness variables of your shell, such as CLAUDE_CONFIG_DIR. Set them before you run piloop service-unit. API keys are secrets.
  • Start and stop the daemon with the service manager. Never run piloop serve --detach beside it.
  • piloop restart and piloop upgrade keep the daemon under the service manager.
  • After you change the unit, run systemctl --user daemon-reload, then systemctl --user restart piloop.

Logs

The daemon writes one line for each span to ~/.piloop/serve.log. Set OTEL_EXPORTER_OTLP_ENDPOINT to send the spans to an OpenTelemetry collector too. A piloop.db.nested_checkout span names code that asked for a second database connection while it held one: report it as a bug. The events table is the easiest record to query:

On a server

One daemon on a server runs the campaigns, and you drive it from any machine with the same CLI. In the server’s $PILOOP_HOME/config.toml:
tls = "proxy" says that a reverse proxy or an SSH tunnel ends TLS in front of the daemon. To end it in the daemon, name a certificate: tls = { cert = "<cert.pem>", key = "<key.pem>" }. Only a loopback address may go without tls.

Give each caller a token

The token prints once. read reads, act also acts on campaigns and sets their secrets, and admin also sets the home’s secrets and tokens. worker is for workers. piloop token revoke laptop ends a token. On your laptop:
Each command that calls the API now asks the server. Commands that open the database, such as piloop sql, history, attach and worker list, refuse: run them on the server. For a certificate that your system does not trust, set SSL_CERT_FILE.

Register a repo by its URL

The server clones the repo, registers it, and measures HEAD as the baseline:
"name" next to "clone" registers it under another name. For a private repo, send a token that the host accepts, "credential": {"token": "<token>"}, which the server keeps nowhere. Or store it as a secret of the home, with an admin token, and name it:

Give agents their model credentials

An agent on the server has no login of yours. Store the key as a secret of the campaign, and name it in piloop.toml:
For a Claude subscription, claude setup-token prints a token: store it as CLAUDE_CODE_OAUTH_TOKEN instead. For a model gateway, see Model access. Nobody needs to keep a session open: piloop message and piloop inbox work from your laptop, and piloop can launch the orchestrator on the server when you turn its triggers on. To run agents and evaluations on more machines, such as a GPU box, see Workers.

Behind an authenticating proxy

When a proxy already checks every caller, such as Envoy’s ext_authz or an oauth2-proxy, let it be the only check:
piloop then reads who the caller is from the headers that the proxy stamps, and refuses its own tokens. On your laptop, set PILOOP_HTTPS_TOKEN to the credential that the proxy accepts. Workers need a rule of their own: Behind an authenticating proxy.
Whoever reaches listen directly can claim any identity. Let only the proxy reach it.