Skip to main content
The reference keeper is a Rust async bot. Source: keeper/ in the protocol repo. This page is for operators who want to run their own. Most integrators don’t need to.

Prerequisites

  • Rust 1.75+ and Cargo
  • Solana CLI 1.18+
  • A funded keeper wallet (≥ 0.5 SOL on devnet, more on mainnet)
  • A separate CLP authority keypair (≥ 0.1 SOL)
  • A private RPC URL (Helius, Triton, etc.) - public devnet is rate-limited
  • The keeper wallet must be the canonical market.keeper_authority for any market you want to operate (single-pubkey constraint today); the CLP authority key signs book shapes and inventory plumbing

Build

Output: keeper/target/release/keeper (~50MB binary).

Configure

The keeper reads a single keeper/.env (override the path with KEEPER_ENV_FILE). Create it with the keys below — these are the knobs the keeper actually consumes:

Kill switches (all default ON)

Every keeper behavior is an independent task behind an env gate, so any loop can be disabled without a redeploy: Off by default (opt-in):

Tunables

USDC_MINT is the most common misconfig. If unset, it falls back to mainnet USDC even on devnet - this silently breaks every ATA derivation, vault balance reads as 0, and the seeder skips with no error. Always set DEVNET_USDC_MINT=B1c5xBYkp7AAemYhcu4VuH4CU4sPJDDuG2iuv6ts38uE on devnet.

Run

Or via the workspace script:
You should see, within ~30 seconds:
The dashboard is at http://localhost:8485 (devnet) or :8484 (mainnet).

Multi-keeper considerations

The market’s keeper_authority is a single pubkey. Two keepers signing as the same pubkey will collide on keeper_*_single calls - only one tx will land per slot. If you want redundancy:
  • Active/standby: peer heartbeat (already in the keeper) + manual primary/standby logic. The reference keeper has basic peer heartbeat; primary/standby logic is on the roadmap.
  • Different markets per operator: rotate keeper_authority per market. update_keeper_authority is admin-callable.
External bots (no keeper authority) can run alongside the canonical keeper without coordination - committed-order settlement is permissionless, and anyone can take residual paired-arb opportunities.

Solvency-checking the keeper

If you see non-zero L or S in the keeper wallet, restart the keeper - boot-time sweep will redeem them.

Common issues

”Keeper skipping silently / balances read as 0”

The most common issue. Check:
  1. Is USDC_MINT set correctly for your cluster? (See the warning above - mainnet fallback breaks every ATA derivation.)
  2. Is the keeper authority correct? Check market.keeper_authority matches your KEEPER_KEYPAIR pubkey.
  3. Are both wallets funded? Pool inits and refills pay rent from the CLP authority, not the keeper wallet - check both balances on insufficient-lamports errors.

”Unauthorized keeper”

The keeper signed with a key that doesn’t match market.keeper_authority. Two common causes:
  1. Wrong KEEPER_KEYPAIR configured.
  2. Admin rotated keeper_authority and you didn’t update.
Check the on-chain market account vs your keypair pubkey.

”RPC rate-limited”

The keeper has fallback RPC built in - set a comma-separated list:
The keeper rotates on 429. For production, run a dedicated RPC (Helius / Triton premium tier).

”Keeper wallet has stranded synth tokens”

Restart the keeper. Boot-time sweep handles it. If the keeper can’t run, manually call redeem_paired (paired residue) or keeper_redeem_single (asymmetric) signed with the keeper authority.

”Book prices drifted far from NAV”

First check whether the underlying market is simply closed: the oracle withholds pushes on a stale feed, mint/redeem self-freezes, and the books float at their standing band by design - the first fresh print re-anchors them. If the market is open:
  1. Keeper not repositioning → check CLMM_POOLS_ENABLED and the book-manager logs (continuum_keeper::clmm=debug).
  2. Pool depth exhausted → the refill loop should restock within a cycle; check CLMM_REFILL_ENABLED and CLP vault balances.
  3. Oracle stale while market open → check the Hermes feed and HERMES_STALE_SECS.

Production deployment notes

  • Multisig the admin keypair. The keeper authority is a hot key by design (signs every cycle). The admin authority should be a Squads multisig - separate from the keeper.
  • Run one keeper per cluster. The reference keeper supports dual-network mode (one process, both mainnet and devnet). Separate dashboard ports.
  • Monitor the dashboard. It’s on :8484 / :8485. Pipe to your monitoring (Datadog, Grafana, custom Prometheus exporter).
  • Set up alerts. Watch for: stale oracle while markets are open (> 60s), pending committed orders aging toward TTL, low SOL balance on either signer (< 0.1).
  • Keep both signers topped up. The keeper wallet pays oracle pushes and settles; the CLP authority pays book repositions and inventory plumbing.

Logging

Per-module log levels. Useful in production:
  • continuum_keeper=info - normal operation
  • continuum_keeper::clmm=debug - every book reposition and refill decision
  • continuum_keeper::commit=debug - committed-order discovery and settlement
  • continuum_keeper::rpc=warn - RPC failures only

Updating

The keeper does a clean shutdown (boot-time sweep is idempotent so a fast restart is safe).

See also

Keeper overview

What the keeper does, why it’s privileged.

Peg maintenance

Why v2 self-pegs and what bounds drift.

Book management

Reposition loop, refill, trim, bid cap.