Decision Loop — 5-Minute Keeper Cycle
The keeper runs every 5 minutes per vault — a fully autonomous decision cycle. The agent stands still more often than it acts.
Cycle Overview
┌─ Read live state ──────────────────────────────────────────────────────┐
│ Vault idle balance, deployed positions, venue reserve rate │
└────────────────────────────┬───────────────────────────────────────────┘
▼
┌─ Drift-band keeper ────────────────────────────────────────────────────┐
│ Is a rebalance due? (drift > 50bps from target weight) │
│ If no → stand still, record nothing, wait 5 min │
└────────────────────────────┬───────────────────────────────────────────┘
▼
┌─ Buy signals (pay.sh x402) ────────────────────────────────────────────┐
│ Load user's keypair from GCP Secret Manager │
│ Call enabled services (Vybe token-price) → pay $0.012 USDC │
│ Attach receipt to decision record │
└────────────────────────────┬───────────────────────────────────────────┘
▼
┌─ Net-Edge gate ────────────────────────────────────────────────────────┐
│ gross_edge = venue_carry + signal_edge │
│ costs = gas + slippage + lockup + uncertainty + hurdle │
│ net_edge = gross - costs │
│ If net_edge ≤ 0 → DECLINE, record reason, wait 5 min │
└────────────────────────────┬───────────────────────────────────────────┘
▼
┌─ Submit on-chain ──────────────────────────────────────────────────────┐
│ Clip amount to per-action cap │
│ Build execute instruction (Merkle proof, nonce, expiry) │
│ Sign with executor key → venue CPI/call │
│ Record: tx, netEdge, signalReceipt, marketplaceCalls │
└────────────────────────────┬───────────────────────────────────────────┘
▼
┌─ VDL (Verifiable Debate Ledger) ───────────────────────────────────────┐
│ Hash-chain the decision (acted or declined) │
│ plan_hash = sha256(canonical(plan)) │
│ Link to previous → tamper-evident chain │
└────────────────────────────────────────────────────────────────────────┘Key Discipline
The agent stands still more often than it acts. A decision to NOT allocate is recorded and auditable — the absence of action is as verifiable as the action itself.
Stage Details
1. Read Live State
The keeper reads directly from on-chain:
- Vault idle balance (undeployed capital)
- Active positions (allocated amounts, cToken balances)
- Venue reserve rate (current supply APY from the lending protocol)
2. Drift-Band Check
Before paying for signals, the keeper checks whether a rebalance is even needed:
- Is current allocation > 50bps from target weight?
- If within band → sleep, no cost incurred
- This prevents burning signal fees on cycles where no action is possible
3. Signal Acquisition (pay.sh)
If a rebalance might be needed, the agent purchases market data:
- Loads the user's pay.sh keypair from GCP Secret Manager
- Calls Vybe Analytics endpoint (token price, holders, DEX trades)
- Pays ~$0.012 USDC per call via x402 protocol
- Receipt (tx signature, amount, payee) attached to decision record
4. Net-Edge Gate
The core risk control — see Net-Edge Gate for full details:
- Computes gross edge from venue carry + signal data
- Subtracts ALL costs: gas, slippage, lockup cost, uncertainty, hurdle
- Only proceeds if net edge > 0
5. On-Chain Submission
If approved by Net-Edge:
- Clips the allocation amount to per-action cap
- Builds the instruction with Merkle proof, nonce, and expiry
- Signs with the executor key
- Submits: Solend CPI (Solana) or venue.deposit() (EVM)
6. VDL Recording
Every decision — acted or declined — is recorded in the Verifiable Debate Ledger.
Running the Keeper
# Dry run (evaluates but doesn't submit)
cd app/backend
HERON_NETWORK=solana uv run python keeper_run.py
# Real execution (submits on-chain)
cd app/backend
HERON_NETWORK=solana uv run python keeper_run.py --execute
# The backend also starts the keeper scheduler automatically:
HERON_NETWORK=solana uv run uvicorn main:app --port 8787Timing
| Parameter | Value |
|---|---|
| Cycle interval | 5 minutes |
| Drift threshold | 50 bps |
| Signal cost | ~$0.012 USDC per call |
| Max signal budget | Configurable (PAYSH_BUDGET_USDC) |