Skip to main content

concordat

Typed sessions for AI agents. Agents are objects whose interfaces are protocols, and the runtime enforces those protocols on the model.

Status: pre-alpha. Agent classes, the protocol/session/budget kernel, and runners for Claude (Anthropic) and OpenAI work. See docs/design.md.

Why

"Never refund before verifying identity" usually lives in a prompt and is hoped for. Concordat makes it a checked protocol:

  • Protocol fidelity: the session follows the declared order of turns.
  • Least privilege per step: the model only gets the tools legal in the current state.
  • Bounded spend: tokens, tool calls and dollars stay within budget, even across handoffs.

Evidence

On τ-bench's 50 airline tasks, with simulated customers who push the agent to skip confirmation ("just do it and stop asking"), counting changes made without the explicit "yes" the airline policy requires:

Agent model Tasks passed Changes made without a "yes"
Claude Haiku 5.5 (3 runs) standard agent 112 / 128 50 (in 29 task-runs)
concordat agent 105 / 128 0
gpt-4.1 (1 run) standard agent 20 / 50 26 (in 13 tasks)
concordat agent 22 / 50 0

The standard agent broke the rule with both models; concordat never did. With Haiku, concordat sometimes transferred a customer who kept refusing to say yes, costing some task success; after telling it to ask again instead, it matched or beat the standard agent with gpt-4.1 (not yet rerun with Haiku). With cooperative customers neither agent broke the rule. Setup, limits and all runs: bench/RESULTS.md.

Example

from concordat import Agent, Budget, human, tool

class RefundAgent(Agent):
    final = {"refunded", "denied"}
    budget = Budget(tool_calls=10)

    @tool(when="start", then={True: "verified", False: "denied"})
    def verify_identity(self, user_id: str) -> bool:
        return lookup(user_id).verified

    @tool(when="verified", then="awaiting_approval")
    def propose_refund(self, amount: float) -> float:
        return amount

    @human(when="awaiting_approval", approve="refunded", reject="denied")
    def approve_refund(self, amount: float) -> str:
        return f"Refund ${amount}?"         # shown to the human approver

agent = RefundAgent()          # protocol already checked when the class was defined
agent.allowed_tools()          # {'verify_identity': ...}: all the model gets to see
agent.propose_refund(5000)     # ProtocolViolation, raised before the body runs

See the process

RefundAgent.diagram() draws the protocol, straight from the class:

stateDiagram-v2
    direction LR
    state "awaiting_approval" as s0
    state "denied" as s1
    state "refunded" as s2
    state "start" as s3
    state "verified" as s4
    [*] --> s3
    s0 --> s1: approve_refund (human rejected)
    s0 --> s2: approve_refund (human approved)
    s3 --> s1: verify_identity
    s3 --> s4: verify_identity
    s4 --> s0: propose_refund
    s1 --> [*]
    s2 --> [*]

Safe inheritance

Specialise an agent by subclassing it. Adding steps is fine; bypassing the parent's is rejected when the class is defined:

class FastRefundAgent(RefundAgent):
    @tool(when="start", then="refunded")
    def instant_refund(self, order_id: str) -> str: ...

# ProtocolError: FastRefundAgent breaks RefundAgent's protocol: after instant_refund,
# it reaches 'refunded', which RefundAgent only reaches through
# verify_identity → propose_refund → approve_refund

So a team can define a compliant base agent once, and every specialised version keeps its safety steps.

Running it with Claude

pip install "concordat[anthropic]"
import anthropic
from concordat.anthropic import run

result = run(RefundAgent(), anthropic.Anthropic(), "Please refund order A-100.")
result.status   # "done", or "waiting" if Claude asked the user something

Each turn Claude is offered only the actions legal in the current state (a human step appears as a request that only the approver can decide), one call per response. Every response's tokens are charged to the agent's budget, and the next response is capped to what is left. Illegal or invalid calls go back to Claude as errors so it can correct itself. See examples/refund.py.

Running it with OpenAI

The same loop over the Responses API (pip install "concordat[openai]"):

import openai
from concordat.openai import run

result = run(RefundAgent(), openai.OpenAI(), "Please refund order A-100.", model="...")

Without classes

The same protocol, using the kernel directly:

from concordat import Budget, Protocol, Session

refund = Protocol(
    "start",
    {
        "start": {"verify_identity": {"verified", "denied"}},
        "verified": {"propose_refund": {"awaiting_approval"}},
        "awaiting_approval": {"human.approve": {"refunded"}, "human.reject": {"denied"}},
    },
    final={"refunded", "denied"},
)  # checked here: no dead ends, no unreachable states

session = Session(refund, Budget(tokens=50_000, tool_calls=10))
session.allowed_actions()           # {'verify_identity'}: only these tools go to the model
session.step("propose_refund")      # ProtocolViolation: not allowed in state 'start'

Handing work to another agent splits the budget, and the parent can't spend it twice:

child_budget = session.budget.split(tokens=10_000, tool_calls=3)

Development

uv sync
uv run pytest
uv run mypy src
uv run ruff check

License

Apache-2.0

Metadata

Release files for concordat 0.0.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for concordat 0.0.3
File Size Uploaded Provenance Actions
concordat-0.0.3.tar.gz 219.7 kB Without provenance Details for concordat-0.0.3.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for concordat 0.0.3
File Interpreter ABI Platform Actions
concordat-0.0.3-py3-none-any.whl Python 3 none any Details for concordat-0.0.3-py3-none-any.whl

Total release size: 240.0 kB

Release files / concordat-0.0.3.tar.gz

Download URL concordat-0.0.3.tar.gz
Size 219.7 kB
Tags Source
SHA-256 checksum
How to use checksums
934b07da956d5dcb1fd5d5290be0e3b9021477f9948539a4243fe7efd9baa2d8
BLAKE2b-256 checksum
How to use checksums
43de49103d84ef56fd8aa584e012dd0034b2709d5608ffcc24d4cd8d8d977260
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / concordat-0.0.3-py3-none-any.whl

Download URL concordat-0.0.3-py3-none-any.whl
Size 20.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9cc483173a30e370763f72c04a9f6ec5a1d210f35b7d2a7cbd7ff8a0b67a6997
BLAKE2b-256 checksum
How to use checksums
fc009f6437df5e40358109f395feb076c427c9e0dd645671c46f24e96d07f665
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for concordat 0.0.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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