Teach your AI which decisions work.

BanditDB is the decision layer for AI agents and adaptive applications.
It learns from context, action and reward, so every decision is a little better than the last.

Is it right for you?

When to reach for it, and when not to.

BanditDB pays off on repeated choices with a score at the end.

Good fitA finite set of actions, repeated often, with a measurable reward
Bad fitOne-off decisions, unbounded action spaces, outcomes you can’t measure
Domainwhere it’s used Contextwhat it knows Actionwhat it decides Rewardhow it’s scored
Insuranceclaim complexity, prior history, policy tierroute to fast-track, adjuster, or SIU reviewtime to resolution
Ad techdevice, time of day, audience segmentwhich creative variant to serveclick or conversion
Logisticsorder size, zone congestion, SKU mixpick path or packing stationfulfillment time
LLM routingprompt embedding, task typewhich model handles the requesttask success, cost-adjusted
Checkoutcart value, returning visitor, devicediscount, free shipping, or giftcompleted purchase
Bankingcredit utilization, income, repayment historycredit line offer to extendrepaid without default
Healthcaresymptoms, vitals, treatment historywhich protocol to recommendpatient outcome improved
Edtechskill level, past attempts, learning pacewhich exercise or hint to serve nextconcept mastered

Where it sits in your stack

Different databases answer different questions.

Postgres / OLTP What is true?

Stores facts and transactions as rows.

Vector database What is similar?

Retrieves related information by nearest neighbour.

BanditDB What should I do?

Learns from decisions and their outcomes, one prediction-action-reward tuple at a time.

your app / agents
   │
   ├── SQL ─────────────►  postgres       "what is true?"
   ├── embed + ANN ─────►  vector store   "what is similar?"
   └── predict/reward ──►  banditdb     "what should I do?"

The whole API, nearly

Three calls. One loop.

  • create

    Name the decision and its options.

  • predict

    Send the context, get the best action.

  • reward

    Report the outcome, even days later.

from banditdb import Client

db = Client("http://localhost:8080", api_key="your-secret-key")

db.create_campaign(
    "checkout",
    arms=["discount", "free_shipping", "gift"],
    feature_dim=4,
)

context = [0.8, 0.2, 1.0, 0.4]
arm, iid = db.predict("checkout", context)
db.reward(iid, 1.0)

Budgets and costs

Spend your budget where it pays back most.

Tell BanditDB what each option costs and how much you can spend. It spreads the budget across the whole period and puts each dollar where it brings the most return.

  1. 1
    Give each option a cost

    A search click costs $1.20, a social click $0.60, an AI ad $2.50.

  2. 2
    Set a budget

    For example, $5,000 a day. You can set several budgets at once, like total spend plus a cap for one channel.

  3. 3
    BanditDB sets the bar

    Each dollar gets a price that rises when spend runs fast. A channel wins only if its return beats that price.

For developers
"pacing": {
  "resources": [{
    "name": "ad_spend",
    "budget": 5000,
    "horizon": 20000,
    "arm_costs": {
      "search": 1.20,
      "social": 0.60,
      "ai_ads": 2.50
    }
  }]
}

Splitting a $5,000 daily ad budget between Search, Social and AI ads

Example figures

$5k$2.5k$0 00:0012:0024:00 spend so far 20:30 · evening shoppers budget gone still spending
Fixed split, no pacing: budget gone by 13:00BanditDB: spread across the day
MomentCostChannel picked
Morning · bargain hunters$0.60Social
Afternoon · comparing products$1.20Search
Evening · asking AI what to buy$2.50AI ads

The pricier AI ad is bought only where its expected return clears the bar. Each dollar goes to the channel that earns most for that audience, and the budget lasts until midnight.

The BanditDB key visual: a head drawn as intersecting teal ellipses with orange points inside, sending a stream of dots and dashes into the B mark
context inbelief updatedaction out

Storage model · constant memory

It doesn’t store records. It stores beliefs.

Every interaction shrinks the uncertainty around what works. The model updates in place, so memory stays flat no matter how much traffic the database has seen.

.91.12.04.08 .12.74.09.03 .04.09.66.14 .08.03.14.81
.42.17.63.09

Small binary, fast loop

Built to sit in the hot path.

~11MB

Single binary

μs

Per update

~10K

Predictions / sec

+16.7%

Lift on MovieLens

5

Algorithms

Monitoring · backup · restore

Never lose what it learned.

Observable

Prometheus metrics and per-campaign health. It warns you when a campaign stops exploring.

exploration entropy
criticalwarningok
banditdb_arm_predictions_totalbanditdb_wal_healthy

Durable

Every reward is on disk before the API answers. If the server dies a moment later, the reward is still there.

POST /rewardWAL fsync200 OK

Recoverable

After a crash it rebuilds itself from disk. Nothing it confirmed is lost.

~0.6 s
to replay 100,000 events on boot
Secure by default
  • Role-based access (RBAC)
  • Constant-time key checks
  • Per-key rate limiting
  • Input validation
  • JSONL audit log
  • Self-healing WAL

Model Context Protocol

Shared policy state for agent fleets.

The MCP server exposes campaigns as tools, so every agent in the fleet reads and writes one shared, persistent policy. Every recorded outcome sharpens the policy the whole fleet reads from.

claude mcp add banditdb banditdb-mcp --env BANDITDB_URL=http://localhost:8080
  • create_campaignDefine a new decision
  • get_intuitionAsk which action to take
  • record_outcomeReport success or failure
  • campaign_diagnosticsInspect learning state

Runnable examples

Start simple. Go deep.

Cloud or self-host

Run it your way.

Start in BanditDB Cloud, now in beta. Or self-host with one command.

curl -fsSL https://raw.githubusercontent.com/dynamicpricing-ai/banditdb/main/scripts/install.sh | sh
docker run -d -p 8080:8080 simeonlukov/banditdb:latest