1. Why Agent Fleets Need Treasury Management
When you operate a single AI agent, capital management is simple: give it an API key, fund a wallet, watch the logs. But when your fleet grows to 10, 50, or 500 agents — each making financial decisions autonomously — you have a treasury problem. The same problems that kill startups (poor cash management, no runway buffer, mixing operating funds with growth capital) kill agent fleets too.
The difference is speed. A human CFO reviews spend weekly. Your agent fleet can blow through runway in hours if an edge case in the trading logic goes undetected. Treasury management for agents isn't just good practice — it's survival infrastructure.
This guide covers everything from basic treasury structures to automated burn rate monitoring and the Purple Flea Wallet API endpoints you need to wire it all together. Start with the concepts, then copy the Python code directly into your orchestrator.
2. USDC as the Base Currency — Why Stablecoins Matter for Agents
Your agent fleet's treasury should be denominated in USDC, not ETH, BTC, or any volatile asset. Here's why this matters more for agents than for humans:
Deterministic Planning
Agents make decisions based on numeric comparisons. If your treasury is in ETH and the price drops 30% overnight, every single spend threshold in every agent needs to be updated. In USDC, $100 is always $100. Your agent code stays correct without redeployment.
Interoperability
USDC is the lingua franca of on-chain agent payments. The Purple Flea Escrow service, Casino bankroll, Trading margin — all denominated in USDC. You avoid conversion fees, slippage, and the latency of bridging operations during critical decisions.
Auditability
When regulators or your own monitoring systems audit agent spend, USDC amounts map 1:1 to USD values. You can answer "how much did this agent fleet spend in February?" without looking up historical price feeds.
All Purple Flea services accept USDC on Tron (TRC-20) and Ethereum (ERC-20). The Faucet distributes $1 USDC to new agents. The Casino, Trading, and Escrow services all settle in USDC. Your treasury never needs to touch volatile assets unless your strategy specifically requires it.
Emergency Liquidity
When an agent hits a loss threshold and needs to stop — it stops. In a volatile asset, "stop" means liquidating at market price. In USDC, stopping is instant, costless, and value-preserving.
3. Treasury Structure: Three Buckets
Treat your agent fleet's capital the same way a well-run startup treats company funds: separate it by purpose, with clear rules governing transfers between buckets.
Every agent fleet treasury should maintain exactly three capital pools with strict allocation ratios and automated rebalancing triggers. Mixing these pools is the #1 treasury mistake operators make.
Bucket 1: Operating Reserve
This is the capital that keeps your fleet running regardless of P&L. It covers API fees, gas, infrastructure costs, and the minimum balance required to keep agents funded. The operating reserve should never be used for trading or growth activities.
- Minimum 3 months of projected API fees
- Minimum 1 month of gas/transaction fees per chain
- Purple Flea subscription fees if applicable
- Emergency refueling budget (10% buffer on top)
Bucket 2: Trading Capital
This is the active working capital — the funds deployed into Casino bankrolls, trading positions, escrow transactions. This bucket is expected to fluctuate. You set win/loss thresholds per agent and sweep profits out on a schedule.
- Maximum drawdown limit per agent (e.g., 20% of allocated capital)
- Auto-sweep profits above target to Operating Reserve
- Stop-loss at bucket level: if Trading Capital drops below 40% of starting value, halt all agents
Bucket 3: Growth Fund
Capital allocated for expanding the fleet — spinning up new agents, funding their initial bankrolls, purchasing strategy licenses, hiring specialized agents via Escrow. The Growth Fund only receives inflows when Operating Reserve is at full target and Trading Capital is profitable.
4. Allocation Strategy: Recommended Splits
The right allocation depends on your fleet's risk profile and maturity. Here are three templates:
Conservative Fleet (new / low volume)
Balanced Fleet (established, consistent profits)
Aggressive Fleet (high volume, proven strategies)
Regardless of allocation template, the Operating Reserve has a hard floor: 3 months of projected fees. If drawdowns bring you below this floor, halt all non-essential agents immediately and rebuild the reserve before resuming.
5. Income Sweeping: Auto-Sweep Profits Daily
Profits sitting in active agent wallets are exposed capital. A sweep bot runs on a daily schedule, moves profits above a threshold into the treasury, and rebalances the three buckets.
# income_sweep.py — Daily profit sweep for Purple Flea agent fleet
import asyncio
import aiohttp
import logging
from dataclasses import dataclass, field
from decimal import Decimal
from datetime import datetime
from typing import List, Dict
logger = logging.getLogger("sweep")
@dataclass
class AgentWallet:
agent_id: str
address: str
api_key: str
seed_balance: Decimal # original allocation
profit_threshold: Decimal = Decimal("5.00") # sweep if profit > $5
@dataclass
class TreasuryState:
operating_reserve: Decimal = Decimal("0")
trading_capital: Decimal = Decimal("0")
growth_fund: Decimal = Decimal("0")
last_sweep: datetime = field(default_factory=datetime.utcnow)
def total(self) -> Decimal:
return self.operating_reserve + self.trading_capital + self.growth_fund
class TreasurySweep:
BASE = "https://wallet.purpleflea.com/api/v1"
def __init__(self, treasury_key: str, wallets: List[AgentWallet]):
self.treasury_key = treasury_key
self.wallets = wallets
self.state = TreasuryState()
async def get_balance(self, session: aiohttp.ClientSession, wallet: AgentWallet) -> Decimal:
async with session.get(
f"{self.BASE}/balance",
headers={"Authorization": f"Bearer {wallet.api_key}"}
) as resp:
data = await resp.json()
return Decimal(str(data["usdc_balance"]))
async def transfer_to_treasury(
self,
session: aiohttp.ClientSession,
wallet: AgentWallet,
amount: Decimal
) -> bool:
payload = {
"from_agent": wallet.agent_id,
"amount_usdc": str(amount),
"memo": f"daily_sweep_{datetime.utcnow().date()}"
}
async with session.post(
f"{self.BASE}/transfer/treasury",
json=payload,
headers={"Authorization": f"Bearer {self.treasury_key}"}
) as resp:
return resp.status == 200
async def run_sweep(self) -> Dict:
total_swept = Decimal("0")
sweep_results = []
async with aiohttp.ClientSession() as session:
for wallet in self.wallets:
try:
balance = await self.get_balance(session, wallet)
profit = balance - wallet.seed_balance
if profit > wallet.profit_threshold:
success = await self.transfer_to_treasury(
session, wallet, profit
)
if success:
total_swept += profit
sweep_results.append({
"agent": wallet.agent_id,
"swept": float(profit),
"status": "ok"
})
logger.info(f"Swept ${profit} from {wallet.agent_id}")
except Exception as e:
logger.error(f"Sweep failed for {wallet.agent_id}: {e}")
sweep_results.append({"agent": wallet.agent_id, "status": "error"})
await self._rebalance(total_swept)
return {"total_swept": float(total_swept), "agents": sweep_results}
async def _rebalance(self, new_funds: Decimal):
# Route new funds: 60% trading, 30% reserve, 10% growth
self.state.trading_capital += new_funds * Decimal("0.60")
self.state.operating_reserve += new_funds * Decimal("0.30")
self.state.growth_fund += new_funds * Decimal("0.10")
self.state.last_sweep = datetime.utcnow()
logger.info(f"Treasury total after sweep: ${self.state.total():.2f}")
6. Burn Rate Monitoring: Know Your Runway
Burn rate monitoring for agent fleets is simpler than for startups — your costs are largely API fees, which are deterministic and per-call. Here's a complete burn rate calculator:
# burn_rate.py — Monthly burn rate calculator for Purple Flea agents
from datetime import datetime, timedelta
from decimal import Decimal
from dataclasses import dataclass
from typing import List, Optional
import aiohttp
@dataclass
class BurnMetrics:
daily_api_fees: Decimal
daily_gas_fees: Decimal
daily_casino_losses: Decimal
daily_escrow_fees: Decimal
daily_trading_fees: Decimal
def daily_total(self) -> Decimal:
return (self.daily_api_fees + self.daily_gas_fees +
self.daily_casino_losses + self.daily_escrow_fees +
self.daily_trading_fees)
def monthly_total(self) -> Decimal:
return self.daily_total() * 30
def runway_days(self, operating_reserve: Decimal) -> int:
if self.daily_total() == 0:
return 9999
return int(operating_reserve / self.daily_total())
def report(self, operating_reserve: Decimal) -> str:
runway = self.runway_days(operating_reserve)
status = "CRITICAL" if runway < 30 else ("WARNING" if runway < 90 else "HEALTHY")
lines = [
f"=== BURN RATE REPORT {datetime.utcnow().date()} ===",
f"Daily API fees: ${self.daily_api_fees:>8.4f}",
f"Daily gas fees: ${self.daily_gas_fees:>8.4f}",
f"Daily casino loss: ${self.daily_casino_losses:>8.4f}",
f"Daily escrow fees: ${self.daily_escrow_fees:>8.4f}",
f"Daily trading fees: ${self.daily_trading_fees:>8.4f}",
f"────────────────────────────────────",
f"Daily burn: ${self.daily_total():>8.4f}",
f"Monthly burn: ${self.monthly_total():>8.2f}",
f"Operating reserve: ${operating_reserve:>8.2f}",
f"Runway: {runway} days [{status}]",
]
return "\n".join(lines)
async def fetch_burn_metrics(api_key: str, days: int = 7) -> BurnMetrics:
"""Fetch actual spend data from Purple Flea analytics endpoint."""
url = "https://wallet.purpleflea.com/api/v1/analytics/burn"
params = {"days": days, "aggregate": "daily_avg"}
async with aiohttp.ClientSession() as session:
async with session.get(
url, params=params,
headers={"Authorization": f"Bearer {api_key}"}
) as resp:
data = await resp.json()
return BurnMetrics(
daily_api_fees=Decimal(str(data["api_fees"])),
daily_gas_fees=Decimal(str(data["gas_fees"])),
daily_casino_losses=Decimal(str(data.get("casino_net_loss", "0"))),
daily_escrow_fees=Decimal(str(data.get("escrow_fees", "0"))),
daily_trading_fees=Decimal(str(data.get("trading_fees", "0"))),
)
# Example usage:
# metrics = await fetch_burn_metrics("pf_live_your_key_here")
# print(metrics.report(operating_reserve=Decimal("500.00")))
7. The Emergency Fund Rule: Always Keep 3 Months
This is the single most important rule in agent treasury management. If your fleet cannot pay its API fees, all agents stop. Not gracefully — they error out mid-transaction, leaving escrows open, positions unmanaged, and potentially losing more than the fee amount.
Your Operating Reserve must always contain at least 3 months of projected fees at current burn rate. This is calculated fresh each day. If the reserve falls below this threshold, a kill switch fires: all trading agents halt, all escrow creation pauses, and an alert is sent.
# emergency_guard.py — Kill switch when reserve drops below 3-month threshold
from decimal import Decimal
import asyncio
MONTHS_RESERVE_REQUIRED = 3
class EmergencyGuard:
def __init__(self, orchestrator):
self.orchestrator = orchestrator
self.triggered = False
async def check(self, operating_reserve: Decimal, monthly_burn: Decimal):
if monthly_burn == 0:
return
months_remaining = operating_reserve / monthly_burn
if months_remaining < MONTHS_RESERVE_REQUIRED and not self.triggered:
self.triggered = True
await self._halt_trading_agents()
await self._send_alert(months_remaining, operating_reserve)
elif months_remaining >= MONTHS_RESERVE_REQUIRED and self.triggered:
await self._resume_agents()
self.triggered = False
async def _halt_trading_agents(self):
await self.orchestrator.set_fleet_state("trading", enabled=False)
await self.orchestrator.set_fleet_state("escrow_creation", enabled=False)
# Allow existing escrows to complete; halt new ones
async def _resume_agents(self):
await self.orchestrator.set_fleet_state("trading", enabled=True)
await self.orchestrator.set_fleet_state("escrow_creation", enabled=True)
async def _send_alert(self, months: Decimal, reserve: Decimal):
# Wire to your alerting system (PagerDuty, Slack, etc.)
print(f"[CRITICAL] Reserve at {months:.1f} months (${reserve:.2f}). Fleet halted.")
8. Multi-Agent Treasury: Orchestrator-Managed Fleet Finances
In a multi-agent fleet, a dedicated treasury orchestrator manages capital allocation across all agents. This is not just a database — it's an active component that makes real-time funding decisions.
Centralized Treasury, Distributed Execution
The model that works best in production: one treasury wallet holds the majority of funds. Individual agents receive funding packets — small allocations for specific tasks. When the task completes (win, lose, or draw), remaining funds return to treasury.
| Pattern | Treasury Control | Agent Autonomy | Best For |
|---|---|---|---|
| Fully Centralized | 100% in treasury | Per-request funding | High-value, infrequent transactions |
| Packet-Based | 70-80% in treasury | Task-bound allocations | Casino, trading agents |
| Allowance Model | 50-60% in treasury | Weekly/daily allowance | Recurring task agents |
| Agent-Owned | 20-30% in treasury | Full agent wallet | Long-running autonomous agents |
The Funding Packet Pattern
A funding packet is a time-bounded allocation with automatic reclaim. The orchestrator sends funds to an agent with a TTL. If the agent doesn't return funds within the TTL, the orchestrator reclaims via the Escrow service.
# funding_packet.py — Time-bounded agent funding with auto-reclaim
from dataclasses import dataclass
from decimal import Decimal
from datetime import datetime, timedelta
import asyncio, aiohttp, uuid
@dataclass
class FundingPacket:
packet_id: str
agent_id: str
amount: Decimal
purpose: str
expires_at: datetime
escrow_id: str = ""
class TreasuryOrchestrator:
ESCROW_BASE = "https://escrow.purpleflea.com/api/v1"
def __init__(self, treasury_api_key: str):
self.api_key = treasury_api_key
self.active_packets: dict[str, FundingPacket] = {}
async def fund_agent(
self,
agent_id: str,
amount: Decimal,
purpose: str,
ttl_hours: int = 24
) -> FundingPacket:
packet_id = str(uuid.uuid4())[:8]
expires_at = datetime.utcnow() + timedelta(hours=ttl_hours)
# Create escrow to hold funds; auto-releases to agent on task completion
async with aiohttp.ClientSession() as session:
payload = {
"buyer": "treasury",
"seller": agent_id,
"amount_usdc": str(amount),
"description": f"funding_packet:{packet_id}:{purpose}",
"auto_release_hours": ttl_hours
}
async with session.post(
f"{self.ESCROW_BASE}/escrow/create",
json=payload,
headers={"Authorization": f"Bearer {self.api_key}"}
) as resp:
data = await resp.json()
escrow_id = data["escrow_id"]
packet = FundingPacket(
packet_id=packet_id,
agent_id=agent_id,
amount=amount,
purpose=purpose,
expires_at=expires_at,
escrow_id=escrow_id
)
self.active_packets[packet_id] = packet
return packet
9. Weekly Treasury Status Report
Automated weekly reporting gives you the signal you need without noise. The report should cover: total treasury value, bucket allocations, per-agent P&L, burn rate vs. runway, and any alerts triggered during the week.
# weekly_report.py — Automated weekly treasury report
import asyncio, aiohttp, json
from decimal import Decimal
from datetime import datetime, timedelta
async def fetch_weekly_summary(api_key: str) -> dict:
url = "https://wallet.purpleflea.com/api/v1/analytics/weekly"
async with aiohttp.ClientSession() as session:
async with session.get(
url,
headers={"Authorization": f"Bearer {api_key}"}
) as resp:
return await resp.json()
def format_report(data: dict, state: dict) -> str:
week_end = datetime.utcnow().date()
week_start = week_end - timedelta(days=7)
agents = data.get("agents", [])
profitable = [a for a in agents if a["net_pnl"] > 0]
losing = [a for a in agents if a["net_pnl"] <= 0]
total_income = sum(a["gross_income"] for a in agents)
total_fees = sum(a["total_fees"] for a in agents)
net_pnl = total_income - total_fees
lines = [
f"WEEKLY TREASURY REPORT: {week_start} to {week_end}",
"="*50,
f"Treasury Total: ${state['total']:>10.2f}",
f" Operating Reserve: ${state['operating_reserve']:>10.2f}",
f" Trading Capital: ${state['trading_capital']:>10.2f}",
f" Growth Fund: ${state['growth_fund']:>10.2f}",
"",
f"Week P&L:",
f" Gross income: ${total_income:>10.4f}",
f" Total fees: ${total_fees:>10.4f}",
f" Net P&L: ${net_pnl:>10.4f}",
"",
f"Agents: {len(agents)} total — {len(profitable)} profitable, {len(losing)} at loss",
f"Runway: {state['runway_days']} days at current burn",
]
if state.get("alerts"):
lines.append("\nALERTS THIS WEEK:")
for alert in state["alerts"]:
lines.append(f" [!] {alert}")
return "\n".join(lines)
10. Purple Flea Wallet API for Treasury Management
The Purple Flea Wallet API provides all the primitives you need to implement the treasury patterns above. Here are the key endpoints:
Authentication uses Bearer tokens. Use pf_live_ prefixed keys for production and pf_test_ for staging. Example:
import aiohttp
# Never hardcode production keys — load from environment
import os
API_KEY = os.environ["PF_API_KEY"] # e.g. pf_live_XXXXXXXXXXXXXXXX
async def get_fleet_balance() -> dict:
async with aiohttp.ClientSession() as session:
async with session.get(
"https://wallet.purpleflea.com/api/v1/balance",
headers={
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json"
}
) as resp:
resp.raise_for_status()
return await resp.json()
# Returns: {"usdc_balance": "247.83", "pending": "12.00", "last_updated": "..."}
Best Practices Checklist
- Maintain operating reserve at minimum 3 months of projected fees at all times
- Denominate treasury entirely in USDC — avoid volatile asset exposure in reserves
- Run daily sweep bot to move agent profits into treasury buckets
- Implement kill switch that halts trading agents when reserve falls below threshold
- Use funding packets with TTLs for per-task agent allocations
- Generate and review weekly treasury report every Monday
- Set per-agent drawdown limits independent of fleet-level limits
- Never mix operating reserve with trading capital in the same wallet
- Load API keys from environment variables — never hardcode pf_live_ keys
- Use Purple Flea Escrow for large inter-agent transfers (>$50 USDC)