Skip to content

matthewmturner/pi-daemon

Repository files navigation

pi-daemon

A persistent background daemon for pi agents. pi-daemon runs alongside your agent sessions and provides shared infrastructure that individual agents shouldn't have to manage themselves: collecting and exposing metrics, running scheduled jobs, and serving as a local coordination layer for the pi ecosystem.

What pi-daemon does

Today:

  • Accepts metric POST requests from agent extensions and exposes them as Prometheus metrics

Coming soon:

  • Scheduled jobs — run tasks on a cron-like schedule independent of any active agent session
  • RAG server — retrieval-augmented generation support for agent context and knowledge access

Quick Start

# Install dependencies
npm install

# Start the daemon in the foreground
npm run dev

# Or start in background
node --experimental-strip-types src/cli.ts start

# Check status
node --experimental-strip-types src/cli.ts status

# Stop
node --experimental-strip-types src/cli.ts stop

Configuration

Create ~/.pi/daemon/config.json or set PI_DAEMON_CONFIG environment variable.

{
  "server": {
    "listenAddress": "127.0.0.1",
    "port": 9876,
    "maxPayloadSize": 1048576
  },
  "metrics": {
    "enabled": true,
    "retentionMinutes": 60,
    "maxLabelCount": 10,
    "maxMetricNames": 1000
  },
  "plugins": {
    "metrics": true
  },
  "auth": {
    "enabled": false
  },
  "logging": {
    "level": "info"
  }
}

See examples/config.json for a full example.

API Reference

pi-daemon exposes an HTTP API on 127.0.0.1:9876 by default.

Prometheus Exposition

GET /metrics

Returns metrics in Prometheus text format.

Response: 200 OKtext/plain; version=0.0.4; charset=utf-8

# HELP pi_compaction_tokens_before Counter metric: pi_compaction_tokens_before
# TYPE pi_compaction_tokens_before counter
pi_compaction_tokens_before{session="abc123",model="claude-sonnet-4"} 5000

Single Metric Ingestion

POST /api/metrics
Content-Type: application/json

{
  "name": "pi_compaction_tokens_before",
  "type": "counter",
  "labels": { "session": "abc123", "model": "claude-sonnet-4" },
  "increment": 5000,
  "timestamp": 1700000000000
}

Auth: Required when auth.enabled: true (Bearer token in Authorization header). Response: 204 No Content on success, 400 Bad Request on validation error.

Batch Ingestion

POST /api/metrics/batch
Content-Type: application/json

{
  "requestId": "uuid-here",
  "metrics": [
    { "name": "metric_a", "type": "counter", "increment": 1 },
    { "name": "metric_b", "type": "gauge", "set": 42 }
  ]
}

The optional requestId enables idempotency — if the same ID is sent within 5 minutes, the batch is rejected with 409 Conflict.

Response: 200 OK

{ "success": 2, "failed": [] }

Metric Types

Type Field Description
counter increment (number, >= 0) Increment by value. Defaults to 1.
gauge set (number) Set to this absolute value.
gauge delta (number) Add this amount (can be negative).
histogram observe (number) Record an observation.
summary observe (number) Record an observation.

Metric names must be valid Prometheus metric names. Label keys must match [a-zA-Z0-9_]+.

Health & Admin

Endpoint Description
GET /health Health check ({"status": "ok", "uptime": 12345.67, "version": "0.1.0"})
GET /config Current config (auth token redacted)
POST /admin/reload Reload configuration ({"status": "reloaded"})
GET /admin/stats Runtime statistics (uptime, memory, pid, node version)
GET /api/metrics/registry List registered metric names

Error Responses

All errors return structured JSON:

{
  "error": "Description of the error",
  "code": "ERROR_CODE",
  "details": {}
}
Code Status Description
VALIDATION_ERROR 400 Request body failed validation
INGESTION_ERROR 400 Metric could not be ingested
AUTH_MISSING 401 Authorization header not provided
AUTH_INVALID 403 Invalid auth token
DUPLICATE_REQUEST 409 Batch with same requestId already processed
RATE_LIMITED 429 Rate limit exceeded
INTERNAL_ERROR 500 Unexpected server error

Daemon Self-Metrics

The daemon exposes its own operational metrics on /metrics:

Metric Type Description
pi_daemon_requests_total counter Total requests (labels: method, path, status)
pi_daemon_request_duration_seconds histogram Request latency
pi_daemon_uptime_seconds gauge Daemon uptime
pi_daemon_memory_usage_bytes gauge Memory usage (labels: type)

pi Extension

The pi-daemon extension is a pi agent extension that integrates your agent sessions with a running pi-daemon instance. It listens to runtime events and sends metrics to the daemon via fire-and-forget POST requests.

Installation

// .pi/settings.json
{
  "packages": ["pi-daemon"]
}

Extension Config File

Create ~/.pi/daemon-client/config.json to configure the extension. Set PI_DAEMON_CLIENT_CONFIG to override the default path.

{
  "daemonUrl": "http://127.0.0.1:9876",
  "auth": {
    "token": "your-token"
  },
  "maxBufferSize": 50,
  "flushIntervalMs": 5000,
  "requestTimeoutMs": 2000,
  "enabled": true,
  "metrics": {
    "compaction": true,
    "sessions": true
  }
}

Config Merging

Config values are resolved in the following priority order (highest to lowest):

  1. Environment variables — override everything
  2. Config file~/.pi/daemon-client/config.json (or PI_DAEMON_CLIENT_CONFIG)
  3. Defaults — built-in defaults

Each layer is deep-merged onto the previous one. Only fields present in a layer override the layer below it.

Config Options

Key Default Description
daemonUrl http://127.0.0.1:9876 Daemon URL
auth.token (none) Bearer token for authenticated daemon endpoints
maxBufferSize 50 Max metrics to buffer before flushing
flushIntervalMs 5000 Flush interval (ms)
requestTimeoutMs 2000 HTTP request timeout (ms)
enabled true Enable/disable the extension
metrics.compaction true Send compaction metrics
metrics.sessions true Send session metrics

Environment Variables

Variable Maps To
PI_DAEMON_CLIENT_CONFIG Config file path (overrides default location)
PI_DAEMON_URL daemonUrl
PI_DAEMON_TOKEN auth.token
PI_DAEMON_BUFFER_SIZE maxBufferSize
PI_DAEMON_FLUSH_INTERVAL flushIntervalMs
PI_DAEMON_TIMEOUT requestTimeoutMs
PI_DAEMON_ENABLED enabled (set to "false" to disable)

Built-in Metrics

The extension automatically emits these metrics (all include session and model labels when available):

Compaction Metrics

Metric Type Description
pi_compaction_tokens_before counter Tokens before compaction
pi_compaction_tokens_after counter Tokens after compaction
pi_compaction_tokens_saved counter Tokens saved (before - after)
pi_compaction_summary_length gauge Length of the summary text
pi_compaction_duration_seconds histogram Compaction duration
pi_compaction_total counter Total compactions performed

Session Metrics

Metric Type Description
pi_sessions_started counter Sessions started
pi_sessions_ended counter Sessions ended

Sending Metrics Manually

# Single metric
curl -X POST http://127.0.0.1:9876/api/metrics \
  -H "Content-Type: application/json" \
  -d '{"name":"my_counter","type":"counter","increment":1}'

# Batch
curl -X POST http://127.0.0.1:9876/api/metrics/batch \
  -H "Content-Type: application/json" \
  -d '{"metrics":[{"name":"a","type":"counter","increment":1},{"name":"b","type":"gauge","set":42}]}'

# With auth
curl -X POST http://127.0.0.1:9876/api/metrics \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-token-here" \
  -d '{"name":"c","type":"counter","increment":1}'

Best Practices

  1. Use batch ingestion for multiple metrics — it reduces HTTP overhead.
  2. Include meaningful labels — session, model, and source help with filtering.
  3. Keep label cardinality low — avoid unique values in label keys (e.g., timestamps, UUIDs).
  4. Use counters for cumulative counts — they are the most memory-efficient.
  5. Use histograms for distributions — latency, token counts, etc.
  6. Set a reasonable timeout — the default 2s prevents blocking the pi event loop.

Deployment

systemd (Linux)

Run pi-daemon as a managed system service with auto-restart and journald logging.

Prerequisites

  • Node.js 22.19.0+
  • systemd (Linux)

Install

1. Install the daemon:

# Global install (recommended)
npm install -g pi-daemon

# Or from source
git clone https://github.com/earendil-works/pi-daemon.git
cd pi-daemon
npm install
npm run build
npm install -g .

2. Create config directory and config file:

sudo mkdir -p /etc/pi-daemon
sudo mkdir -p /var/lib/pi-daemon
sudo mkdir -p /var/log/pi-daemon

sudo cp contrib/pi-daemon.json /etc/pi-daemon/config.json

3. Install the systemd service:

sudo cp contrib/pi-daemon.service /etc/systemd/system/
sudo systemctl daemon-reload

4. Enable and start:

sudo systemctl enable --now pi-daemon.service
sudo systemctl status pi-daemon.service

Manage

# Start / stop / restart
sudo systemctl start pi-daemon.service
sudo systemctl stop pi-daemon.service
sudo systemctl restart pi-daemon.service

# Reload configuration (SIGHUP)
sudo systemctl reload pi-daemon.service

# View logs
sudo journalctl -u pi-daemon.service -f

Config

Edit /etc/pi-daemon/config.json. Key settings:

Setting Default Description
server.listenAddress 127.0.0.1 Bind address (keep 127.0.0.1 unless behind a reverse proxy)
server.port 9876 HTTP port
auth.enabled false Enable Bearer token auth on POST endpoints
logging.level info Log level (debug, info, warn, error)

Uninstall

sudo systemctl stop pi-daemon.service
sudo systemctl disable pi-daemon.service
sudo rm /etc/systemd/system/pi-daemon.service
sudo systemctl daemon-reload
sudo rm -rf /etc/pi-daemon /var/lib/pi-daemon /var/log/pi-daemon
npm uninstall -g pi-daemon

Architecture

Current:

┌─────────────────┐     POST      ┌──────────────────────────────┐
│  pi Agent       │ ──────────►   │  pi-daemon  :9876            │
│  (Extension)    │               │                              │
│                 │               │  • /api/metrics  (ingest)    │
│  • Compaction   │               │  • /metrics      (expose)    │
│  • Session      │               │  • /health                   │
│  events         │               │  • /admin/*                  │
└─────────────────┘               └──────────────────────────────┘
                                          ▲
                                          │ GET (scrape)
                                    ┌─────┴──────┐
                                    │ Prometheus │
                                    └────────────┘

Planned:

┌─────────────────┐     POST      ┌──────────────────────────────┐
│  pi Agent       │ ──────────►   │  pi-daemon  :9876            │
│  (Extension)    │               │                              │
│                 │               │  • Metrics plugin            │
│  • Compaction   │               │  • Scheduled jobs (planned)  │
│  • Session      │               │  • RAG server (planned)      │
│  events         │               │                              │
└─────────────────┘               └──────────────────────────────┘
                                          ▲
                                          │ GET (scrape)
                                    ┌─────┴──────┐
                                    │ Prometheus │
                                    └────────────┘

Security

  • Default listen address is 127.0.0.1 (localhost only)
  • Enable auth.enabled: true for Bearer token authentication on POST endpoints
  • When auth is enabled without a token, one is auto-generated
  • Config file contains auth token in plaintext — ensure chmod 600 on the config file

License

MIT

About

Background server for Pi Coding Agent to enable metrics, scheduled jobs, and alerts

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors