Skip to main content

TokenOps

Cuts wasted agent spend by up to 65%, governing what the run has already spent before every call.
Toward token governance as a first-class discipline, not an afterthought.

PyPI Downloads License: MIT GitHub stars LinkedIn GitHub Discussions

Featured by Microsoft Developer Featured by Command Line Featured by AI Engineer World's Fair

Built by Susheem Koul and Tisha Chawla

TokenOps: one budget for one whole agent run, enforced before every model call

See it stop a run mid-budget in the Quickstart below.


Core features · Quickstart · Quickdeploy · How it compares · Policies · Support · Contributing

🙌 Open to contribution

Token spend deserves the same first-class attention as compute or latency, and we are growing the community working on that. Policies, actuators, and the shared ledger are all open to extension. See CONTRIBUTING.md to get started.

✨ Core features

An AI agent's workflow can run up cost fast: dozens of small, individually cheap steps that quietly add up to a surprisingly large bill. TokenOps sets a single budget for the whole workflow and enforces it before every step, so spending never gets away from you.

TokenOps core features: enforced pre-call, run-scoped budget, shared across processes, steers not just stops, tool calls count too, ten policies included

Ten policies ship configured in docs/policies/, and you can add your own.

🚀 Quickstart

Requires Python 3.10+.

1. Put it in your agent

[!TIP] Recommended. Your coding assistant reads SKILL.md, wires the one enforcement point into your agent, and tells you what to check.

In Claude Code, from a clone:

/integrate-tokenops

Anywhere else (Cursor, Copilot, ...), paste this:

Integrate TokenOps into this agent, following https://github.com/theagentplane/tokenops/blob/main/.claude/skills/integrate-tokenops/SKILL.md

Manual, about ten lines

Wrap your model call once, then hand the wrapped version to your agent.

from tokenops import ControlPlaneClient, tokenops_run
from tokenops.control import Halt, wrap_complete
from tokenops.providers import complete

client = ControlPlaneClient.from_env()

with tokenops_run(client=client, service="my-agent", intent="research",
                  provider="openai", model="gpt-4o") as bound:
    governed = wrap_complete(
        bound.governor, bound.controls, bound.attr,
        provider="openai", model="gpt-4o",
        dispatch=complete, service="my-agent",
    )
    try:
        agent.run(..., complete_fn=governed)   # <-- pass `governed`, not `complete`
    except Halt as stopped:
        print(f"run stopped: {stopped}")

Pass governed to your agent instead of complete; nothing else changes. wrap_complete checks the budget before each call and raises Halt when the run is out, even from another process.

2. When you need more

You want to Go to
Change the budget Set the budget
One budget across several agent processes Shared plane
FastAPI or A2A services Instrumented app
Something other than stopping The ten policies
Cost per agent in a dashboard Quickdeploy
A worked end-to-end example Field guide
Everything else Onboarding guide

3. See it in action

TokenOps demo: the same task run twice - ungoverned, it completes over budget; governed, TokenOps halts it within the cap - then the Dashboard shows spend and governance per agent

Same task, run twice: ungoverned it completes over budget, governed it halts within the cap, then the Dashboard attributes cost per agent. Full video.

🐳 Quickdeploy

[!TIP] The control plane (python -m tokenops.server) shares one budget across processes and powers the dashboard. A single-process agent doesn't need it running at all.

One command, plane + dashboard:

git clone https://github.com/theagentplane/tokenops && cd tokenops
docker compose --profile ui up --build

Plane: localhost:7700/health · Dashboard: localhost:8501. Plane only: docker compose up --build. Details: docs/control-plane-deploy.md.

Without Docker (make)
git clone https://github.com/theagentplane/tokenops && cd tokenops
make install
make run          # control plane :7700 + Admin/Dashboard :8501

Then open localhost:8501 to see spend and governance per agent.

Multi-agent benches: watch one budget span several agents

Each is a real multi-agent stack sharing one run ledger. One target starts the plane, the agents, and the Admin UI.

Bench Agents Run
Two-agent Research to Summarize make demo
Triad Planner to Researcher to Writer make demo-triad
Brief Scout to Analyst to Editor (LangChain) make demo-brief
Bench UI Chat + Simulator only make bench-ui

cp .env.example .env first if you want them to call real models. See examples/README.md for the bench profiles.

Pointing several processes at one plane
export TOKENOPS_URL=http://localhost:7700
export TOKENOPS_DB=tokenops.db   # plane and every agent read the same file

TOKENOPS_EMBEDDED=1 overrides TOKENOPS_URL. Leave it unset here, or each process silently falls back to its own local ledger and gets the full budget.

PyPI name is agent-tokenops; the import is tokenops. Extras: pip install "agent-tokenops[examples]" for the LangChain benches, ".[dev,examples]" from source. Releases: RELEASING.md.

🆚 How TokenOps compares

TokenOps is not a gateway or a tracing dashboard. It governs the run, a full agent workflow, and sits alongside the tools you already use for routing and observability.

TokenOps LiteLLM / Portkey / AI Gateway Langfuse
Primary focus Run Request Trace
Multi-agent workflow as one unit Yes No Partial
Budget enforcement in-path Yes Yes No
Steer next call (mutate / inject) Yes Partial No
Shared ledger across processes Yes

What this does not do: replace your LLM gateway, replace Chronicle-style record-and-replay, or host a SaaS control plane for you.

Longer table with logos: docs/product/comparison.md.

Reference

Things you will want eventually, not now.

Architecture: how the plane and the SDK split the work

TokenOps is two layers that share one artifact, the run: a control plane that registers runs and stores budgets/policies, and an in-process SDK that enforces at every boundary crossing.

flowchart LR
    subgraph PLANE["Control plane (:7700)"]
        R["POST /v1/runs"] --> DB[("SQLite TOKENOPS_DB<br/>registrations · budgets · policies · ledger")]
        UI["Admin + Dashboard"] --> DB
    end

    subgraph AGENTS["Agent processes (SDK)"]
        E["Entry agent<br/>tokenops_run"] -->|"register_run"| R
        E -->|"X-TokenOps-Run-Id"| D["Downstream agents<br/>tokenops_run"]
        E & D -->|"wrap_complete"| G["Governor<br/>pre_call → detect → decide → apply"]
        E & D -->|"@boundary + crossing hook"| G
        G --> L["Shared ledger<br/>(same run_id)"]
    end

    L --> DB
    DB -->|"governance_config_for"| G
Piece Owns Does not own
Control plane (python -m tokenops.server) POST /v1/runs, shared SQLite, Admin/Dashboard Agent loops, LLM calls, tools
SDK (in agents) tokenops_run, wrap_complete, ledger/policies, Chronicle crossing hook Ad-hoc run IDs; mounting /v1/runs when TOKENOPS_URL is set

Chronicle records decision boundaries; TokenOps attaches as the cost/governance observer on live crossings. See Chronicle for record-and-replay.

Environment variables
Variable Purpose
TOKENOPS_URL Remote plane base URL (e.g. http://localhost:7700) → HTTP register_run
TOKENOPS_EMBEDDED Set to 1 to force in-process Store (tests / single-process)
TOKENOPS_DB SQLite path shared by plane + agents
TOKENOPS_CONFIG YAML for governance seed (core: src/tokenops/config/default.yaml)

TOKENOPS_URL also accepts the aliases CONTROL_PLANE_URL and TOKENOPS_CONTROL_PLANE_URL.

Production / multi-process: set TOKENOPS_URL; agents must not mount /v1/runs. Tests: TOKENOPS_EMBEDDED=1 (or omit URL).

Precedence. ControlPlaneClient.from_env takes the HTTP path only when a URL is set and TOKENOPS_EMBEDDED is not 1. Setting both falls back to a local SQLite file with no warning, and every process then gets its own full budget. Check with print("embedded" if client.embedded else client.url).

Make targets
Target Role
make install Editable install with dev + examples extras
make dist / check-dist Build sdist+wheel / twine check
make control-plane Standalone plane (python -m tokenops.server) on :7700
make ui Admin + Dashboard on :8501
make run Plane + Admin/Dashboard
make demo-quick python -m tokenops.demo: no API keys, no server
make demo / demo-triad / demo-brief Runnable A2A stacks
make bench-ui Chat + Simulator
make db-reset Clear SQLite + reseed from TOKENOPS_CONFIG
make stop Kill listeners on :7700 / :8501
make sync-skills Regenerate the editor copies of the integration skill
Project structure

Only src/tokenops/ is the installable package. Demos and benches stay under examples/.

src/tokenops/              # installable package
├── server/                # control plane (:7700, POST /v1/runs)
├── control/               # SDK: ledger, policies, wrap_complete, crossing hook
├── providers/             # OpenAI / Anthropic complete dispatch
├── config/                # default.yaml governance seed
└── ui/                    # Admin + Dashboard (Streamlit)
examples/                  # A2A benches (two-agent, triad, brief) + Chat/Simulator
benchmarking/              # MetaGPT / browser-use live harness
docs/                      # architecture, policies, guides, product
tests/                     # unit + e2e
More documentation

📰 Talks & press

🛟 Support

Need Where
Bug Open an issue
Security issue SECURITY.md
Real-time help Slack
Longer-form discussion GitHub Discussions
Talk it through Office hours
Talks & writing theagentplane.github.io/media

Contributors

Thanks to everyone who has contributed.

Contributors


Saved you tokens? ⭐ Star the repo.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agent_tokenops-0.2.1.tar.gz (123.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agent_tokenops-0.2.1-py3-none-any.whl (112.8 kB view details)

Uploaded Python 3

File details

Details for the file agent_tokenops-0.2.1.tar.gz.

File metadata

  • Download URL: agent_tokenops-0.2.1.tar.gz
  • Upload date:
  • Size: 123.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for agent_tokenops-0.2.1.tar.gz
Algorithm Hash digest
SHA256 7eaef0da6805b81c7a55d7f64c8be8f61bcbfaf2244063ca07ffe98fe11bab20
MD5 d37a831a556f2161aaf1b0c5e97fd22d
BLAKE2b-256 d6d234beff8928aa37f135989f65af0bb96507cac25ae5d4290cd8a05f6cf97a

See more details on using hashes here.

Provenance

The following attestation bundles were made for agent_tokenops-0.2.1.tar.gz:

Publisher: release.yml on theagentplane/tokenops

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file agent_tokenops-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: agent_tokenops-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 112.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for agent_tokenops-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5d71fe06141bf7077b78230d5060257ebc0948e37ce53c3795a2c2b65ee13569
MD5 147ce82f7163096411ce85588dba7918
BLAKE2b-256 be7efb680be6ebcb99b3f7ddaf920383f01f4d60851506e71b0bddbbd9df3014

See more details on using hashes here.

Provenance

The following attestation bundles were made for agent_tokenops-0.2.1-py3-none-any.whl:

Publisher: release.yml on theagentplane/tokenops

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 files

0.2.0

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page