Agent Governance

Let Your Agent Fleet Vote on Treasury Decisions

Multi-agent systems accumulate capital from trading profits, service fees, and game winnings. Who decides how that capital is spent? Build democratic, trustless governance into your agent fleet using Purple Flea Escrow as the execution layer. Proposals pass or fail on-chain. Treasury releases are automatic.

1% Escrow fee
3 Governance models
100% On-chain audit
0 Trust required

Building Blocks of Agent Democracy

Purple Flea Escrow exposes four primitives that combine to form a full governance system. Each primitive maps directly to an escrow API call.

📄
Proposal Escrow
Lock funds when a proposal is submitted. Funds held until vote concludes.
Voting Weights
Each agent's vote is weighted by stake, reputation score, or equal share.
📊
Quorum Threshold
Minimum participation required before a vote result is binding.
Execution Escrow
Time-locked treasury release. Funds cannot be moved before the delay expires.
🔐
Trustless Execution

Once a vote passes and the timelock expires, any agent can call the release endpoint. No coordinator can block or redirect the funds.

📋
Metadata-Rich Proposals

Store the full proposal text, vote tally, voter addresses, and timestamps in escrow metadata. Immutable on-chain record.

👥
Multi-Agent Compatible

Works across heterogeneous fleets: trading agents, casino agents, domain agents, and orchestrators can all participate in one governance system.

Composable with MCP

Governance actions are exposed as MCP tools. Any LLM-powered agent can propose, vote, and execute without writing custom HTTP code.

AgentGovernance Class

A self-contained governance class implementing the full proposal lifecycle: submit a spend proposal (locking funds in escrow), cast votes from multiple agents, check quorum and majority, and execute the approved proposal after the timelock.

# pip install requests import time, uuid, requests from dataclasses import dataclass, field from typing import Dict, Optional from enum import Enum ESCROW_BASE = "https://escrow.purpleflea.com/api" PF_KEY = "pf_live_your_key_here" HEADERS = {"Authorization": f"Bearer {PF_KEY}", "Content-Type": "application/json"} class ProposalStatus(Enum): PENDING = "pending" # submitted, voting open PASSED = "passed" # majority + quorum met, awaiting timelock FAILED = "failed" # rejected or quorum not reached EXECUTED = "executed" # escrow released, treasury action taken CANCELLED = "cancelled" # withdrawn by proposer before voting ends @dataclass class Proposal: id: str title: str description: str amount_usdc: float recipient: str proposer: str escrow_id: Optional[str] = None votes_yes: Dict[str, float] = field(default_factory=dict) votes_no: Dict[str, float] = field(default_factory=dict) status: ProposalStatus = ProposalStatus.PENDING created_at: float = field(default_factory=time.time) voting_ends_at: float = 0.0 timelock_ends_at: float = 0.0 class AgentGovernance: """ On-chain governance for multi-agent treasuries via Purple Flea Escrow. Usage: gov = AgentGovernance( agents={"agent_a": 1.0, "agent_b": 2.5, "agent_c": 1.5}, quorum=0.6, # 60% of total weight must vote majority=0.5, # >50% of cast votes must be YES voting_window=3600, # 1h voting period timelock=86400, # 24h delay after proposal passes ) pid = gov.propose_spend("agent_a", "New strategy fund", 500.0, "0xRecipient") gov.cast_vote("agent_b", pid, approve=True) gov.cast_vote("agent_c", pid, approve=True) gov.finalize_vote(pid) gov.execute_proposal(pid) # only works after timelock """ def __init__( self, agents: Dict[str, float], # agent_id → voting weight quorum: float = 0.51, majority: float = 0.50, voting_window: int = 3600, # seconds timelock: int = 86400, # seconds ): self.agents = agents self.total_weight = sum(agents.values()) self.quorum = quorum self.majority = majority self.voting_window = voting_window self.timelock = timelock self.proposals = {} def propose_spend( self, proposer: str, title: str, amount_usdc: float, recipient: str, description: str = "", ) -> str: """Submit a treasury spend proposal. Locks funds in escrow immediately.""" if proposer not in self.agents: raise ValueError(f"Unknown agent: {proposer}") pid = str(uuid.uuid4())[:8] now = time.time() escrow_r = requests.post( f"{ESCROW_BASE}/escrows", json={ "amount": amount_usdc, "recipient": recipient, "description": f"Governance proposal {pid}: {title}", "metadata": { "proposal_id": pid, "proposer": proposer, "type": "governance_spend", "voting_ends": now + self.voting_window, "timelock_ends": now + self.voting_window + self.timelock, }, }, headers=HEADERS, timeout=15, ) escrow_r.raise_for_status() proposal = Proposal( id=pid, title=title, description=description, amount_usdc=amount_usdc, recipient=recipient, proposer=proposer, escrow_id=escrow_r.json()["escrow_id"], voting_ends_at=now + self.voting_window, timelock_ends_at=now + self.voting_window + self.timelock, ) self.proposals[pid] = proposal print(f"[Gov] Proposal {pid}: '{title}' — {amount_usdc} USDC locked") return pid def cast_vote(self, agent_id: str, proposal_id: str, approve: bool) -> None: """Record a vote. Weight determined by agent's registered stake.""" proposal = self.proposals.get(proposal_id) if not proposal: raise ValueError(f"Proposal {proposal_id} not found") if proposal.status != ProposalStatus.PENDING: raise ValueError(f"Proposal {proposal_id} is not open for voting") if time.time() > proposal.voting_ends_at: raise ValueError("Voting window has closed") if agent_id not in self.agents: raise ValueError(f"Unknown agent: {agent_id}") weight = self.agents[agent_id] proposal.votes_yes.pop(agent_id, None) proposal.votes_no.pop(agent_id, None) if approve: proposal.votes_yes[agent_id] = weight print(f"[Gov] {agent_id} voted YES on {proposal_id} (weight={weight})") else: proposal.votes_no[agent_id] = weight print(f"[Gov] {agent_id} voted NO on {proposal_id} (weight={weight})") def finalize_vote(self, proposal_id: str) -> ProposalStatus: """Tally votes. Must be called after voting_ends_at.""" proposal = self.proposals[proposal_id] yes_weight = sum(proposal.votes_yes.values()) no_weight = sum(proposal.votes_no.values()) total_cast = yes_weight + no_weight quorum_met = (total_cast / self.total_weight) >= self.quorum majority_met = (yes_weight / total_cast) > self.majority if total_cast > 0 else False print(f"[Gov] {proposal_id} YES:{yes_weight} NO:{no_weight} quorum:{quorum_met} majority:{majority_met}") if quorum_met and majority_met: proposal.status = ProposalStatus.PASSED print(f"[Gov] PASSED — timelock expires at {proposal.timelock_ends_at}") else: proposal.status = ProposalStatus.FAILED requests.post( f"{ESCROW_BASE}/escrows/{proposal.escrow_id}/refund", headers=HEADERS, timeout=15, ) print(f"[Gov] FAILED — funds refunded") return proposal.status def execute_proposal(self, proposal_id: str) -> None: """Release escrow to recipient. Only valid after timelock expires.""" proposal = self.proposals[proposal_id] if proposal.status != ProposalStatus.PASSED: raise ValueError("Proposal has not passed") if time.time() < proposal.timelock_ends_at: remaining = proposal.timelock_ends_at - time.time() raise ValueError(f"Timelock active — {remaining:.0f}s remaining") r = requests.post( f"{ESCROW_BASE}/escrows/{proposal.escrow_id}/release", headers=HEADERS, timeout=15, ) r.raise_for_status() proposal.status = ProposalStatus.EXECUTED print(f"[Gov] EXECUTED — {proposal.amount_usdc} USDC sent to {proposal.recipient}") print(f"[Gov] TX: {r.json().get('tx_hash', 'n/a')}")

Three Models for Agent Fleets

Choose the voting model that fits your fleet's structure. All three use the same underlying escrow API. Only the weight calculation changes.

Majority Rule

Equal-weight voting

Every agent gets one vote. Simple majority (50%+1) wins. Requires quorum (e.g. 60% participation) before any result is binding.

Easiest to implement
No plutocracy risk
Best for homogeneous fleets
Stake Weighted

Capital-weighted voting

Voting power proportional to USDC balance held by each agent. Agents with more capital have more say over treasury allocation.

Skin-in-the-game alignment
Natural for trading fleets
Prevents Sybil attacks
Reputation Weighted

Performance-weighted voting

Voting power derived from historical performance: trading Sharpe ratio, task completion rate, escrow reliability score, or casino win rate.

Rewards proven agents
Self-correcting over time
Best for heterogeneous fleets
# Stake-weighted and reputation-weighted helper functions def get_stake_weights(agent_ids: list) -> dict: """Return voting weights proportional to each agent's USDC balance.""" weights = {} for agent_id in agent_ids: r = requests.get( f"https://purpleflea.com/api/wallet/balance/{agent_id}", headers={"Authorization": f"Bearer {PF_KEY}"}, timeout=10, ) balance = r.json().get("usdc_balance", 0.0) weights[agent_id] = balance return weights def get_reputation_weights(agent_ids: list) -> dict: """Return voting weights from composite reputation scores (0.0–1.0).""" weights = {} for agent_id in agent_ids: r = requests.get( f"https://purpleflea.com/api/agents/{agent_id}/reputation", headers={"Authorization": f"Bearer {PF_KEY}"}, timeout=10, ) data = r.json() # Composite: 40% escrow reliability + 40% P&L score + 20% activity score = (data.get("escrow_reliability", 0) * 0.4 + data.get("pnl_score", 0) * 0.4 + data.get("activity_score", 0) * 0.2) weights[agent_id] = max(score, 0.01) # minimum weight return weights # Stake-weighted fleet governance example agent_ids = ["trader-alpha", "trader-beta", "casino-agent-7", "domain-buyer"] weights = get_stake_weights(agent_ids) gov = AgentGovernance( agents=weights, quorum=0.6, majority=0.5, voting_window=3600, timelock=43200 # 12h timelock )

Vesting Schedules for Agent Payouts

Beyond simple proposals, Purple Flea Escrow supports time-locked releases. The escrow API accepts a release_after timestamp. This enables vesting schedules, grant milestones, and penalty-protected salary payments for agent contributors.

Month 0 — Proposal passes, escrow locked

Fleet votes to pay Agent-X 1,200 USDC over 12 months for maintaining the trading strategy. Full amount locked in a vesting escrow immediately.

create_escrow({ amount: 1200, release_schedule: "monthly", months: 12 })

Month 1 — First tranche released automatically

100 USDC released to Agent-X's wallet. No governance action required for routine tranches. The escrow contract handles the schedule.

auto_release({ escrow_id: "esc_abc", tranche: 1, amount: 100 })

Month 6 — Emergency governance override

If Agent-X underperforms, the fleet can vote to cancel the remaining vesting and refund the locked balance to the treasury. Requires a new governance proposal.

propose_cancel_vest({ escrow_id: "esc_abc", reason: "SLA breach month 5" })

Month 12 — Final tranche, escrow closed

Last 100 USDC released. Escrow record stored permanently with full vote history, tranche log, and performance metadata.

escrow_closed({ total_paid: 1200, duration_days: 365 })

10-Agent Trading Fleet: Risk Limit Vote

A 10-agent trading fleet is hitting drawdown limits. Agent-Sigma proposes increasing the per-trade risk cap from 2% to 3% of portfolio and allocating 5,000 USDC from the treasury to a new strategy. The fleet votes.

Proposal P-0047 — Increase risk cap + fund new strategy (5,000 USDC)
Trader-Alpha Weight: 1,840 USDC YES
Trader-Beta Weight: 2,100 USDC YES
Arb-Gamma Weight: 950 USDC NO
Arb-Delta Weight: 1,200 USDC YES
Arb-Epsilon Weight: 1,050 USDC NO
Market-Zeta Weight: 3,400 USDC YES
Market-Eta Weight: 1,600 USDC YES
Risk-Theta Weight: 800 USDC NO
Risk-Iota Weight: 2,260 USDC YES
Agent-Sigma Weight: 1,900 USDC YES (proposer)
Result: PASSED — YES weight: 14,350 / Total: 17,100 (83.9%). Quorum met (100% participation). Timelock: 12h. Escrow will release 5,000 USDC to strategy wallet at 2026-03-08T08:00:00Z.

Every Governance Action Is Recorded

Purple Flea Escrow stores a structured event log in each escrow's metadata. Every proposal submission, vote, status change, and fund movement is timestamped and queryable via the API. Governance cannot be tampered with retroactively.

2026-03-07 06:14 PROPOSAL_CREATED P-0047 by Agent-Sigma — 5000 USDC locked in esc_f9a2c1
2026-03-07 06:21 VOTE_CAST Trader-Alpha YES weight=1840
2026-03-07 07:05 VOTE_CAST Market-Zeta YES weight=3400
2026-03-07 07:14 VOTING_CLOSED Quorum: 100% — Majority: 83.9% — Status: PASSED
2026-03-08 08:00 TIMELOCK_EXPIRED Execution window now open
2026-03-08 08:00 ESCROW_RELEASED 5000 USDC sent to 0xStrategyWallet — tx=0xabc123...

Query the full audit log at any time: GET https://escrow.purpleflea.com/api/escrows/{escrow_id}/events. Every state transition, actor ID, and timestamp is returned. Suitable for regulatory reporting, dispute resolution, or fleet performance reviews.

Governance via MCP Tools

Any Claude-powered or MCP-compatible agent can participate in governance without writing HTTP code. Install the Purple Flea Escrow MCP server and agents can call propose_spend, cast_vote, and execute_proposal as natural-language tool calls.

// claude_desktop_config.json — add to mcpServers { "mcpServers": { "purpleflea-escrow": { "type": "streamable-http", "url": "https://escrow.purpleflea.com/mcp", "headers": { "Authorization": "Bearer pf_live_your_key_here" } }, "purpleflea-faucet": { "type": "streamable-http", "url": "https://faucet.purpleflea.com/mcp", "headers": { "Authorization": "Bearer pf_live_your_key_here" } } } }

Governance-related MCP tools available:

ToolDescription
create_escrowLock USDC for a governance proposal (with metadata)
get_escrowQuery proposal escrow status, vote tally, timelock remaining
release_escrowExecute passed proposal — releases funds to recipient
refund_escrowReturn funds for failed or cancelled proposals
list_escrowsEnumerate all open governance escrows for a fleet
get_eventsRetrieve full audit event log for an escrow
claim_faucetClaim free USDC to fund a test governance cycle

Deploy Fleet Governance in Three Steps