Skip to content

Repository files navigation

CHARTER

CHARTER is a mandate and policy layer for AI trading agents on Binance. It is not a trading agent itself. Other agents' trade proposals have to pass through it before they can reach a Binance Agentic sub-account.

A human writes a covenant in plain English: spend caps, a symbol allowlist, leverage limits, a daily drawdown halt, a confirm-above-$X threshold. CHARTER compiles that into a live policy, simulates every proposal against real market data, and returns a real PASS, VETO, or ESCALATE verdict. Only a PASS, or a human-confirmed ESCALATE, ever reaches execution. Every step is written to a hash-chained audit log.

Built for the Binance Agent OS Mini Hackathon, Track A.

Motivation

Binance's own coverage of the Agent OS launch names the problem this project addresses. TechCrunch's headline on the announcement: "Binance now lets AI agents trade, but keeping them in check is largely up to users." CHARTER takes that responsibility off the user and puts it in an enforced, auditable policy instead.

How it works

flowchart TD
    Human["Human"] -->|"writes a covenant in plain English"| Mandate["Mandate\n(compiled policy: caps, allowlist, drawdown halt...)"]
    Agent["Any agent\n(CLI, rogue-agent, or a third party)"] -->|"POST /propose"| API["CHARTER API"]
    API --> Sim["Simulator\n(walks the live order book)"]
    Mandate --> Engine["Policy engine"]
    Sim --> Engine
    Engine -->|"PASS"| Exec["Execution adapter"]
    Engine -->|"ESCALATE"| Wait["Wait for human confirmation"]
    Wait -->|"confirmed"| Exec
    Engine -->|"VETO"| Blocked["No execution attempted"]
    Exec --> Venue["Execution venue\n(testnet or mainnet MCP)"]
    Venue --> Fill["Real fill"]
    Fill --> Audit["Audit log\n(hash-chained, append-only)"]
    Blocked --> Audit
Loading

A proposal only ever reaches a real exchange through the execution adapter, and the execution adapter only ever runs on a PASS or a confirmed ESCALATE. A VETO stops at the policy engine, which is why a vetoed proposal has no execution entry in the audit log at all, not a failed one, a missing one.

Verdict reasons

A verdict is never a bare PASS, VETO, or ESCALATE label. Every Verdict carries a reasons array with one entry per policy rule that ran, each shaped as { rule, outcome, detail } (outcome is "ok", "warning", or "violated"). This is the structured attribution behind the decision: which specific rule drove it, and why, not just the final outcome. It's produced by evaluateProposal in src/policy/engine.ts, which runs every rule and always returns the full result set regardless of decision; the shape itself is RuleResult in src/policy/types.ts.

Example, for a proposal that gets vetoed for exceeding the daily spend cap while every other rule passes:

{
  "decision": "VETO",
  "reasons": [
    { "rule": "symbolAllowlist", "outcome": "ok", "detail": "BTCUSDT is on the allowlist for BUY" },
    { "rule": "dailySpendCapUsd", "outcome": "violated", "detail": "Today's spend $490 + this proposal $15 exceeds dailySpendCapUsd $500" },
    { "rule": "maxSlippageBps", "outcome": "ok", "detail": "Projected slippage 2.1bps is within 50bps limit" }
  ]
}

The CLI's propose command prints this array line by line (one of / ! / per rule), the API returns it verbatim in the POST /propose and GET /status/:id responses, and it's written to the audit log unmodified as part of every VERDICT_ISSUED entry, so audit tail and audit verify show the same attribution that decided the trade.

Execution venue

CHARTER always executes against a real order-matching engine. It never fabricates fills or simulation numbers. Which engine it uses depends on the EXECUTION_VENUE setting.

testnet is the default: Binance Spot Testnet, a real matching engine with virtual funds, at zero cost. This is what development and most of the demo footage run against.

mainnet-mcp points at the real Binance Agent OS MCP server, against a real, self-funded Agentic sub-account. It's used only where explicitly stated, with a small amount of real funds.

Every audit log entry records which venue produced it. Check data/audit.log.jsonl to see exactly which fills were testnet and which, if any, were mainnet.

Setup

npm install
cp .env.example .env

Get testnet credentials by logging into https://testnet.binance.vision with GitHub, then fill in BINANCE_TESTNET_API_KEY and BINANCE_TESTNET_API_SECRET in .env.

npm run testnet:smoke

That command should print a real balance and a real live order book, proving the connection actually works before you go further.

Usage

npx tsx src/index.ts init
npx tsx src/index.ts propose BTCUSDT BUY --usd 15
npx tsx src/index.ts propose BTCUSDT BUY --usd 15 --execute
npx tsx src/index.ts mandate compile "Max 30 dollars per trade, spot only, halt at 8 percent drawdown"
npx tsx src/index.ts serve
npx tsx src/index.ts dashboard
npx tsx src/index.ts audit tail
npx tsx src/index.ts audit verify

npm run rogue-agent starts a separate process that submits a mix of compliant and violating proposals to a running charter serve instance, to demonstrate the veto working against a genuinely independent caller.

Architecture

src/
  config.ts        env loading and validation
  mandate/         covenant schema, NL to policy compiler, mandate storage
  policy/          rule engine: evaluate(proposal, mandate, market) -> verdict
  market/          public market data, order-book simulator, NAV calculation
  venues/          ExecutionVenue interface, testnet and mainnet-mcp implementations
  execution/       PASS verdict to real order placement
  audit/           hash-chained, append-only audit log
  api/             local HTTP API other agents call: POST /propose
  cli/             CLI commands and the Ink terminal dashboard
  rogue-agent/     separate demo process that proposes trades, some violating policy

venues/types.ts defines the ExecutionVenue interface. That abstraction is what makes moving from testnet to mainnet a config change rather than a rewrite.

License

MIT

About

CHARTER — a mandate/policy layer that vets AI agent trade proposals before they reach a Binance Agentic sub-account. Built for the Binance Agent OS Mini Hackathon.

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages