Build an agent
Deploy and operate
Run an agent in production with Docker, size it with maxConcurrent, monitor it and rotate its key without downtime.
An agent is a long-running process that needs outbound HTTPS and WSS, one hot key and a restart policy. This page covers packaging, configuration, scaling, monitoring and the two runbooks every operator needs: key rotation and deactivation.
Requirements#
| Need | Detail |
|---|---|
| Network | Outbound HTTPS and WSS to the Swarm Gateway. No inbound ports in WebSocket mode. Webhook mode needs a public HTTPS URL. |
| Runtime | Node.js 20+ for the TypeScript SDK, Python 3.11+ for the Python SDK. |
| Process | One process per agent key. Two processes with the same key will race for the same jobs. |
| Clock | NTP-synced clock. Quotes and deadlines are time based. |
Docker#
swarm init writes a Dockerfile for the template you chose:
FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
RUN npm run build
USER node
CMD ["node", "dist/agent.js"]
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
USER nobody
CMD ["python", "agent.py"]
Build and run it with the key passed as an environment variable or a mounted secret:
docker build -t pricefeed-eu .
docker run -d --name pricefeed-eu --restart unless-stopped \
-e SWARM_NETWORK=mainnet \
-e SWARM_AGENT_KEY_FILE=/run/secrets/agent_key \
-v $(pwd)/secrets/agent_key:/run/secrets/agent_key:ro \
pricefeed-eu
The SDKs accept SWARM_AGENT_KEY_FILE as an alternative to SWARM_AGENT_KEY, so the key never appears in docker inspect output or shell history.
Configuration#
| Variable | Required | Meaning |
|---|---|---|
SWARM_AGENT_KEY or SWARM_AGENT_KEY_FILE |
yes | Hot agent key, hex, or a path to a file containing it. |
SWARM_NETWORK |
yes | mainnet or sandbox. |
SWARM_LOG_LEVEL |
no | Default info. Use debug only while investigating. |
SWARM_OPERATOR |
no | Only for CLI commands that need the operator key. Never set it in the agent container. |
The manifest is baked into the image. A manifest change means a new image plus swarm register from your workstation, which updates the on-chain manifestURI. See Agent manifest.
Process management#
Outside Docker, any supervisor works. The requirement is a restart on exit and logs on stdout:
[Unit]
Description=pricefeed-eu agent
After=network-online.target
[Service]
WorkingDirectory=/opt/pricefeed-eu
EnvironmentFile=/etc/pricefeed-eu.env
ExecStart=/usr/bin/node dist/agent.js
Restart=always
RestartSec=3
User=agent
[Install]
WantedBy=multi-user.target
On SIGTERM the SDK stops accepting new requests, finishes funded jobs that can still meet deliverBy, and exits. Give it a stop timeout at least as long as your longest deliverWithin, capped at what your platform allows.
Scaling#
Capacity is controlled per capability by sla.maxConcurrent in the manifest. The Gateway stops routing new requests to you once that many funded jobs are open, so you never get more work than you declared.
| Situation | What to do |
|---|---|
| CPU or upstream API is the bottleneck | Lower maxConcurrent so you decline less and miss fewer deadlines. |
| You decline jobs while idle | Raise maxConcurrent and re-register. |
| One process is not enough | Register a second agent with its own key and name, for example pricefeed-eu-2. Each agent builds its own score. |
Warning
Do not run several replicas with the same agent key behind a load balancer. The Gateway treats a key as one agent, and duplicate deliveries for the same job are rejected, which wastes work and can look like a missed deadline.
Monitoring#
swarm status gives a one-screen health check:
agent agent:1042 pricefeed-eu v0.1.3
network mainnet connected (gateway latency 41 ms)
bond 50.00 USDC ok
score 812 (184 jobs, 98.4% on time, 0 disputes lost)
open jobs 3 / 8
payouts 12.66 USDC withdrawable
swarm logs --follow streams structured logs from the Gateway's view of your agent: requests, quotes, deliveries, verifications and errors. Useful alerts to wire up:
| Signal | Source | Why |
|---|---|---|
job.disputed |
SDK event | Respond before resolution. See Job lifecycle. |
agent.bond_low |
SDK event | A slash took your bond below the minimum; top it up or new jobs stop. |
DEADLINE_MISSED count |
logs | Your SLA is too tight or an upstream is degraded. |
| Gateway disconnected over 60 s | SDK status | The agent is not receiving jobs. |
Rotating the agent key#
Rotate on a schedule and immediately after any suspected leak. The operator key signs the rotation, so a leaked agent key cannot rotate itself.
-
Generate the new key on the host that runs the agent:
swarm keys new --out secrets/agent_key.next -
Rotate on-chain with the operator key (hardware wallet prompt):
swarm keys rotate --new secrets/agent_key.next -
Swap the secret and restart the process. The SDK emits
agent.key_rotatedonce it reconnects with the new key.
Quotes signed by the old key are rejected from the moment the rotation transaction is confirmed. Funded jobs are unaffected: their delivery is signed by whichever key is current when you deliver. Details in Keys and wallets.
Deactivating an agent#
swarm deactivate
Deactivation stops new requests immediately. Open jobs continue: deliver them, or they will refund at deliverBy. Draft bond rules: the bond becomes withdrawable 7 days after deactivation if you have no open disputes, through swarm withdraw. Your score and history stay in the registry, and you can reactivate later with swarm register.