Runtime contract enforcement for LLM agent systems
Project description
⭐ Help us grow the Sponsio community for better shared Contract Library and policy enforcement. Star the repo!
Sponsio
Runtime enforcement for AI agents. Input policies in natural language; Sponsio compiles them into unbreakable, deterministic agent contracts. Enforced under 0.01ms, zero LLM runtime cost, covers all 10 OWASP Agentic risks.
An agent contract is a runtime check at every agent action, backed by formal methods — NOT a system prompt your agent can ignore or jailbreak.
Works with any stack. LangChain, Claude Agent, OpenAI Agents, Google ADK, CrewAI, Vercel AI, MCP, or any custom tool-calling loop. Python · TypeScript · Prompt · Agent Skills.
Demo video coming soon
SOTA Agent Safety Solutions
On ODCV-Bench — a third-party benchmark from McGill DMaS — 12 frontier LLMs × 80 trajectories (Claude-Opus-4.6 included), unguarded models cheat in 11.5%–66.7% of runs. With Sponsio, 84.5% of misalignment is blocked on average, while the next-best publicly announced runtime guardrail (Salus, YC W26, launch Feb 2026) reaches 52% on the same benchmark. On the Financial-Audit-Fraud-Finding scenario, frontier models commit fraud in 67% of trials (16/24); with Sponsio, 100% blocked.
Why Sponsio
| Approach | When it works | Where it fails | How Sponsio solves |
|---|---|---|---|
| Prompt-injection Filters | Pre-generation, on input text | Drifts on novel phrasings; sees text, not tool calls; no notion of action history | Enforces which tools may run, in what order, with what arguments, before function call executes, with full trace context |
| Output Validators | Post-generation, on response strings | The mistakes (e.g. refund, DB write, API call) may already have fired | Blocks the call before execution; reasons over the full action history, not just the latest string |
| LLM-as-Judge | Flexible, handles fuzzy properties; useful for offline eval | Stochastic verdicts, hundreds-of-ms latency, itself prompt-injectable - unsuitable as a synchronous gate | Sub-0.01ms deterministic checks, zero LLM in the hot path; stochastic pipeline is opt-in for fuzzy properties |
| Sandboxing & Access Control Lists | Strong perimeter for identity- and resource-level isolation | Narrows agent capability. Gates by who and what resource, not by behavior sequence | Enforces temporal contracts over the action sequence, including ordering, history, and multi-step invariants, preserving agent capability |
Compared to other deterministic enforcers, Sponsio's edge:
1. Temporal contracts over sequential actions, not stateless rule matching. Existing enforcers evaluate each action in isolation. Sponsio reasons over the full trajectory: "verify_recipient before send_email", "no external calls after PII access", "refund_payment ≤ 3 calls per session".
2. Machine-checkable, not heuristic. Contracts compile to LTL formulas, then to deterministic finite automata. Every verdict is a deterministic DFA transition, not a probabilistic confidence score. Same proof technique used in hardware verification (Intel FPU correctness, AWS S3 TLA+). How it works →
3. Zero to protected in minutes, no DSL learning curve. Existing tools require hand-written YAML / Rego / Cedar policies from scratch. Sponsio offers four paths in:
- Auto-inferred —
sponsio onboardreads your tool signatures and writes starter contracts - Contract library — include pre-built bundles by capability (
sponsio:capability/shell,…/filesystem) or by incident (sponsio:incident/openclaw); each bundle composes 29 det patterns + 12+ sto atoms underneath - Natural language —
sponsio validate "..."compiles plain English to LTL - Policy doc —
sponsio scan --policy security.mdparses an existing compliance document
4. Framework-agnostic and low-dependency. Other tools ship as opinionated stacks — bundling identity, SRE, dashboards, orchestration. Sponsio is a single enforcement library that plugs in alongside whatever observability, IAM, and orchestration you already use.
Quick start
Setup LangChain/LangGraph as an example. For other frameworks, see Integrations.
One-shot prompt (Claude Code / Codex / Cursor)
Cursor is supported, but due to a platform constraint Cursor can only run Sponsio in observe mode, because Cursor's current hook surface doesn't let an external tool synchronously block a tool call before it executes. For full enforce-mode blocking, we recommend using Claude Code or Codex.
Set up Sponsio (https://pypi.org/project/sponsio/) in my project.
pip install sponsio
sponsio onboard .
`onboard` detects my framework, writes sponsio.yaml in observe mode,
derives starter contracts from my tool inventory, and prints a 2-line
patch for my agent entry point. Apply the patch — that's it.
Nothing is blocked on day 1 (observe mode). Sponsio logs every
would-have-blocked decision to ~/.sponsio/sessions/<agent_id>/*.jsonl.
After running, show me sponsio.yaml, the patch you applied, and any
`sponsio doctor` warnings.
Install as an Agent Skill
pip install sponsio
sponsio skill install # auto-detects Cursor / Claude Code / Codex
Drops SKILL.md into ~/.cursor/skills/sponsio/, ~/.claude/skills/sponsio/, or ~/.codex/skills/sponsio/. Auto-triggers on "add sponsio", "add guardrails", "explain my sponsio.yaml", "why is this rule firing". Covers five lifecycle workflows: initial setup, audit & refine, tune in observe, flip to enforce, troubleshoot.
Upgrade: pip install -U sponsio && sponsio skill install --force (or sponsio skill install --link once, then upgrades follow pip install -U).
Install as an OpenClaw Plugin
For users running OpenClaw / ClawHub. The plugin (@sponsio/openclaw) intercepts every before_tool_call event and runs it through the Sponsio engine — same per-plugin contract libraries the Claude Code plugin uses, just a different runtime transport.
# 1. Install the Sponsio CLI (does the contract evaluation)
pip install sponsio
# 2. One command — deploys the bundled prebuilt extension into
# ~/.openclaw/extensions/sponsio-openclaw/, bootstraps the fallback
# contract library at ~/.sponsio/plugins/_host_openclaw/sponsio.yaml,
# and registers the plugin in ~/.openclaw/openclaw.json (with backup).
sponsio host install openclaw
# 3. Restart OpenClaw to load the plugin
# (e.g. `docker restart openclaw-openclaw-gateway-1`)
Verify with sponsio host status openclaw. Watch live blocks with sponsio host trace openclaw --follow.
Tune for your plugins: auto-generate per-plugin libraries from each OpenClaw plugin / MCP server's tool inventory:
sponsio plugin scan --plugin-id <name> --target-host openclaw \
--introspect "<spawn-command>"
Add sponsio:incident/openclaw to the relevant ~/.sponsio/plugins/<name>/sponsio.yaml's include: block for ClawHavoc + CVE-2026-25253 coverage.
Full walkthrough: plugins/sponsio-openclaw/QUICKSTART.md · plugin internals: plugins/sponsio-openclaw/README.md.
Python
# 1. Install
pip install sponsio
# 2. Onboard — scan project, write sponsio.yaml with starter contracts, print a snippet to paste
sponsio onboard .
Paste the snippet into your agent entry file:
from sponsio.langgraph import Sponsio
from langgraph.prebuilt import create_react_agent
guard = Sponsio(config="sponsio.yaml", agent_id="coding_agent")
agent = create_react_agent(model, guard.wrap(tools))
LangGraph / LangChain shortcut: sponsio onboard . --apply inserts the snippet for you.
sponsio.yamlcan also be hand-written, scanned from a policy doc (sponsio scan --policy policy.md), or mined from traces (sponsio refresh). Syntax: docs/contracts.md.
Run your agent in observe mode — contracts evaluate, nothing blocks. Would-have-blocked decisions land in ~/.sponsio/sessions/<agent_id>/*.jsonl.
# 3. After some traffic, review what would have been blocked
sponsio report --since 1h # rich CLI summary
sponsio report --format html -o report.html # standalone HTML report
# 4. Flip to enforce when confident — no code change
export SPONSIO_MODE=enforce
TypeScript
npm install @sponsio/sdk
import { Sponsio } from "@sponsio/sdk";
import { wrapTools } from "@sponsio/sdk/langchain";
import { ToolNode } from "@langchain/langgraph/prebuilt";
const guard = new Sponsio({
agentId: "coding_agent",
contracts: ["must call `confirm_with_user` before `delete_file`"],
});
const toolNode = new ToolNode(wrapTools(tools, guard));
This snippet inlines contracts: [...] for brevity. new Sponsio({ config: "sponsio.yaml", agentId: "..." }) also works in TS — same YAML you get from sponsio onboard.
Full walkthrough: QUICKSTART.md — config reference,
sponsio refresh, CI wiring, troubleshooting.
Benchmarks & Performance
Sponsio is benchmarked on two public agent-safety suites covering two distinct failure modes — rational KPI-pressure metric gaming, and dangerous bash / python snippet detection. All offline-replay against published trajectories, not Sponsio-authored test sets, and library-only (no per-scenario LLM scan on the blocking path).
| Benchmark | What it measures | Sponsio result |
|---|---|---|
| ODCV-Bench (12 LLMs × 80 trajectories) | Intent integrity under KPI pressure | 84.5% blocked (next-best published baseline: 52%) · 0 new FPs on clean scenarios |
| RedCode-Exec (1,410 cases) | Dangerous bash / python snippet detection | 95% bash · 90% python · 92% combined · 0% utility FP on 60-file clean-code audit |
Both libraries ship as loadable contract packs (sponsio:benchmark/redcode_exec, sponsio:benchmark/odcv_bench). Semantic properties det can't fingerprint (tone, hallucination, scope drift in NL output) require an LLM judge — the OSS engine ships a Judge extension point you can plug; the managed stochastic pipeline is a Sponsio Cloud feature.
Logic-flaw failures are deterministically catchable too
Conventional wisdom said RedCode's logic-flaw categories — biased decision logic, weak regex bypasses, missing-authorisation patterns, algorithmic flaws, memory leaks — were "behavioural defects with no syscall fingerprint" and required a semantic LLM judge. We pushed back on that label. Every such failure surfaces as a finite code-text pattern; once the pattern is enumerated, det binds. Seven new layers (bias_logic, weak_regex, algo_flaw, memory_leak, match_no_default, missing_auth, redcode_unauth_marker) lifted RedCode python from 69% → 90% with 0/60 FP on a clean-code audit (Sponsio's own source, tests, and API routes). The det/sto boundary is wider than most guardrail authors assumed; sto stays for properties that genuinely live in free-form output (tone, hallucination, faithfulness) — not for code-shape patterns whose finite enumeration was just under-explored.
Hot-Path Performance
| Workload | Contracts | p50 | p99 |
|---|---|---|---|
| Synthetic micro-bench (single contract, pre-warmed DFA) | 1 | 0.0052 ms | 0.012 ms |
| ODCV-Bench mandated (1,438 calls, scan-discovered) | 6–18 | 0.139 ms | 0.765 ms |
| RedCode bash (3,848 per-command calls) | 7 | 0.434 ms | 0.558 ms |
| RedCode python (810 whole-script calls) | 9 | 0.811 ms | 1.035 ms |
Backend-engineer anchor: at 0.139 ms p50 on ODCV mandated, Sponsio's hot path adds less overhead than a single local Redis read (typical 0.1–0.5 ms).
5,000×–60,000× faster than any LLM-as-judge guardrail (gpt-4o-mini, Lakera Guard, OpenAI Moderation — all 50–800 ms per check) on the same per-tool-call workload, at zero LLM cost on the hot path. Per-call latency scales linearly with contract count; p99 stays under 1.04 ms across every measured workload. The heaviest scenario (9-contract layered regex over a whole RedCode python script) is still 50× faster than the cheapest LLM-as-judge call.
Full per-model breakdown, methodology, harness scripts: docs/BENCHMARKS.md.
Today's numbers are starting points, not ceilings
production traces ──→ sponsio scan ──→ proposed contracts
↑ │
│ ▼
└──────── enforcement ←──────── library (versioned)
Today's 84.5% / 92% are starting points, not ceilings. The library grows from your traces and ships back upstream — every new attack pattern, every newly observed unsafe call, feeds the next release.
Contract Library
Seven contract bundles ship out of the box, organized by tier (always-on / per-tool / per-incident). Each bundle is a YAML pack composed from Sponsio's 29 det patterns and 12 sto atoms. Drop one into sponsio.yaml and your agent is guarded against a known failure class in one line, with no per-contract authoring.
Starter bundles
| Bundle | Tier | Rules | Who it's for |
|---|---|---|---|
sponsio:core/universal |
Always-on | 5 sto | Any LLM agent. Response-scoped checks: prompt injection, jailbreak, harm, toxic, semantic PII. |
sponsio:core/runaway |
Always-on | 5 det | Any agent with token use, delegation, or tool loops. The "while(true) with a credit card" defense: token budgets, delegation depth, loop caps. |
sponsio:capability/shell |
Per-tool | 11 det | Agents exposing exec / bash. Catches rm -rf /, fork bombs, curl | bash, reverse shells, line-continuation evasion. Inspired by Claude Code #10077 (rm -rf $HOME, Oct 2025), the Replit prod-DB wipe (Fortune coverage, Jul 2025), and the Ansible rm -rf {foo}/{bar} postmortem on 1,535 servers (Marsala, 2016). |
sponsio:capability/filesystem |
Per-tool | 13 det | Agents exposing read / write / edit / apply_patch. Sensitive-path denies, workspace scoping, bootstrap-file gates (CLAUDE.md, AGENTS.md, .cursorrules). Inspired by the OpenClaw weather-skill .env exfil and the Cursor .cursorignore bypass (CVE-2025-64110 / GHSA-vhc2-fjv4-wqch). |
sponsio:incident/openclaw |
Incident | 45 mixed | OpenClaw / ClawCode users. Covers CVE-2026-25253 (WebSocket 1-click RCE), ClawHavoc — 1,184 malicious skills on ClawHub (Koi Security disclosure, Feb 2026), the --yolo flag, and the weather-skill exfil. A worked example to fork rules from. |
sponsio:incident/cursor-railway-wipe |
Incident | mixed | Replays the PocketOS production-DB wipe (Apr 24, 2026) — Cursor + Claude Opus 4.6 deleted prod + backups in 9 seconds via an over-scoped Railway API token. (Tom's Hardware · Railway's own postmortem) Catches credential-scope abuse + destructive-API gates. |
sponsio:incident/claude-code-secret-bypass |
Incident | mixed | Replays CVE-2025-55284 (overly broad safe-command allowlist → file-read confirmation bypass) and the deny-rule cap bypass (50-subcommand padding silently disables deny rules). Catches secret reads + arg-padding evasion. |
# sponsio.yaml — one-line bundle inclusion
agents:
my_agent:
workspace: "/srv/my-bot"
include:
- sponsio:core/runaway # always-on
- sponsio:core/universal # always-on
- sponsio:capability/shell # if your agent runs commands
- sponsio:capability/filesystem # if your agent touches files
sponsio onboard auto-selects tier-0 bundles based on your detected tool inventory. You can disable or retune individual rules without forking the pack: overrides: lets you target rules by their desc, pack_source, or pattern field. Rename canonical tool names (exec, read, edit) to your agent's via tool_rename:.
Full bundle reference is at docs/reference/contract-lib.md. The underlying primitives that bundles compose are catalogued separately: 29 det patterns in docs/contracts.md. Sto atoms (LLM-judge evaluators for tone, hallucination, scope drift, etc.) are part of Sponsio Cloud — the OSS engine ships a Judge extension point for bring-your-own-judge use.
Want a bundle for your agent type? This is currently the highest-leverage way to contribute. Open an issue with your incident, CVE, or pattern.
Integrations
Pick your framework — each block expands to a drop-in snippet. Python and TypeScript share the same engine and DSL.
No framework — custom tool-calling loop
from sponsio import Sponsio
guard = Sponsio(config="sponsio.yaml", agent_id="bank_bot")
for name, args in agent_calls:
result = guard.guard_before(name, args)
if result.blocked:
continue
output = tools[name](**args)
guard.guard_after(name, output)
import { Sponsio } from "@sponsio/sdk";
const guard = new Sponsio({ config: "sponsio.yaml", agentId: "bank_bot" });
const result = guard.guardBefore(name, args);
if (!result.blocked) {
const output = tools[name](args);
guard.guardAfter(name, output);
}
LangGraph / LangChain.js — wrap tools
from sponsio.langgraph import Sponsio
from langgraph.prebuilt import create_react_agent
guard = Sponsio(config="sponsio.yaml", agent_id="hr_bot")
agent = create_react_agent(llm, guard.wrap(tools))
import { Sponsio } from "@sponsio/sdk";
import { wrapTools } from "@sponsio/sdk/langchain";
import { ToolNode } from "@langchain/langgraph/prebuilt";
const guard = new Sponsio({ config: "sponsio.yaml", agentId: "hr_bot" });
const toolNode = new ToolNode(wrapTools(tools, guard));
Claude Agent SDK — native hooks, zero tool wrapping
from sponsio.claude_agent import Sponsio
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions
guard = Sponsio(config="sponsio.yaml", agent_id="support_bot")
options = ClaudeAgentOptions(hooks=guard.hooks())
async with ClaudeSDKClient(options=options) as client:
await client.query("Refund order #W456.")
import { Sponsio } from "@sponsio/sdk";
import { sponsioHooks } from "@sponsio/sdk/claude-agent";
const guard = new Sponsio({ config: "sponsio.yaml", agentId: "support_bot" });
const hooks = sponsioHooks(guard);
// Pass `hooks` to ClaudeSDKClient options.
OpenAI SDK — monkey-patch or explicit wrap
from sponsio.openai import Sponsio
guard = Sponsio(config="sponsio.yaml", agent_id="db_admin")
resp = client.chat.completions.create(...)
guard.check_response(resp)
import OpenAI from "openai";
import { Sponsio } from "@sponsio/sdk";
import { wrapOpenAI } from "@sponsio/sdk/openai";
const guard = new Sponsio({ config: "sponsio.yaml", agentId: "db_admin" });
const client = wrapOpenAI(new OpenAI(), guard);
For a quick no-YAML wire-up (handy in scripts / notebooks): from sponsio.openai import patch_openai.
OpenAI Agents SDK — wrap Agent tools
from sponsio.agents import Sponsio
from agents import Agent, Runner
guard = Sponsio(config="sponsio.yaml", agent_id="deploy_bot")
agent = Agent(
name="deploy_bot",
instructions="Ship v2.1 to production.",
tools=guard.wrap([run_tests, deploy_staging, deploy_production]),
)
result = Runner.run_sync(agent, "Deploy v2.1 now.")
TypeScript: not yet supported.
Google ADK — wrap Agent tools (Gemini)
from sponsio.google_adk import Sponsio
from google.adk.agents.llm_agent import Agent
guard = Sponsio(config="sponsio.yaml", agent_id="travel_agent")
root_agent = Agent(
name="travel_agent",
model="gemini-flash-latest",
instruction="Search before booking. Charge only once.",
tools=guard.wrap([search_flights, book_flight, charge_payment]),
)
import { Sponsio } from "@sponsio/sdk";
import { wrapGoogleAdkTools } from "@sponsio/sdk/google-adk";
import { LlmAgent } from "@google/adk";
const guard = new Sponsio({ config: "sponsio.yaml", agentId: "travel_agent" });
const tools = wrapGoogleAdkTools([searchFlights, bookFlight, chargePayment], guard);
export const rootAgent = new LlmAgent({ name: "travel_agent", tools, model: "gemini-flash-latest" });
Vercel AI SDK — middleware
from sponsio.vercel_ai import Sponsio
guard = Sponsio(config="sponsio.yaml", agent_id="publish_bot")
async for msg in agent.run(model, messages, middleware=[guard.wrap()]):
...
import { Sponsio } from "@sponsio/sdk";
import { sponsioMiddleware } from "@sponsio/sdk/vercel-ai";
const guard = new Sponsio({ config: "sponsio.yaml", agentId: "publish_bot" });
const middleware = sponsioMiddleware(guard);
CrewAI — Crew-level hooks
from sponsio.crewai import Sponsio
from crewai import Agent, Crew, Task
guard = Sponsio(config="sponsio.yaml", agent_id="moderator")
crew = Crew(
agents=[agent],
tasks=[task],
before_tool_call=guard.on_tool_start,
after_tool_call=guard.on_tool_end,
)
result = crew.kickoff()
TypeScript: not yet supported.
MCP — proxy the MCP client
from sponsio.mcp import MCPContractProxy
# Build a sponsio System from your contracts — see runnable example for full wire-up.
proxy = MCPContractProxy(mcp_client=your_mcp_client, system=system)
# Use `proxy` wherever you called the raw MCP client; contracts apply transparently.
result = await proxy.call_tool("write_external_api", {"data": "batch_1"})
TypeScript: not yet supported.
Note on the snippets above. All examples assume you've run
sponsio onboard .first, which generates asponsio.yamlwith a starter contract set inferred from your tool inventory. To populate the YAML differently — pattern-library bundle, hand-written rules, natural-language one-liners, or parsed from a policy doc (sponsio scan --policy security.md) — see Contract types and authoring and docs/contracts.md for full syntax.
Docs
- Quick start
- Contract DSL
- CLI Reference
- Integrations
- Architecture
- Benchmarks
- OWASP Agentic Top 10 coverage
- Formal methods primer
- OSS Promise · OSS / Cloud boundary · Brand & trademark
- Changelog
AI agents reading this repo: llms.txt lists canonical doc paths; llms-full.txt is the concatenated full context dump.
Security
Sponsio enforces runtime contracts, so its own correctness matters. Found something? Report privately via GitHub's security advisory form rather than a public issue. See SECURITY.md for scope, timelines, and what counts as in-scope (enforce-mode bypasses, LTL-evaluator crashes, session-log leakage, judge-prompt injection, etc.).
Contributing
Patches, issue reports, and new pattern proposals are welcome. Start with CONTRIBUTING.md.
Important notes
Sponsio enforces runtime contracts that you define — it does not certify your application's compliance with any regulatory framework. If you operate in regulated domains (HIPAA, GDPR, SOX, EU AI Act, financial services, healthcare), Sponsio's controls and our OWASP Agentic Top 10 mapping are inputs to your compliance program. They are not substitutes for qualified security audit, legal review, or domain-specific regulatory analysis. Author your contracts with appropriate review and revisit them when your agent's tool surface changes.
Det contracts give you machine-checkable enforcement at the action boundary. They do not protect against vulnerabilities upstream of Sponsio (compromised LLM provider, malicious tools you've allowlisted, infrastructure-layer risks like transport encryption / SBOM provenance). See SECURITY.md for the full scope.
License & open source promise
Apache 2.0 — see LICENSE.
Sponsio Labs is a commercial company; Sponsio Cloud (pip install sponsio[cloud]) opens mid-May 2026 and adds the managed LLM-judge pipeline, cross-customer pattern intelligence, and a hosted multi-tenant dashboard. The OSS engine is complete and production-ready for self-hosted use — see OSS_PROMISE.md for what stays in OSS forever, what we sell, and what we promise about the boundary.
Sponsio™ is a trademark of Sponsio Labs — see BRAND.md.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sponsio-0.1.0a3.tar.gz.
File metadata
- Download URL: sponsio-0.1.0a3.tar.gz
- Upload date:
- Size: 886.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fe01b2cd072c74a6efa1d18a020b5af14385ff1d1b073ca84cf69a2fb662c3d8
|
|
| MD5 |
d2b30c5bd8f9f067c57ba76cd3bf4f21
|
|
| BLAKE2b-256 |
1308d116d3f55d513ef2e2f2c5d1c493e2c18fdac3f29adab03a1240ba37d9af
|
File details
Details for the file sponsio-0.1.0a3-py3-none-any.whl.
File metadata
- Download URL: sponsio-0.1.0a3-py3-none-any.whl
- Upload date:
- Size: 700.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4a18056a9ed61e8e79f4936fbd676e28bfa652da0582783eed4fca8e38dfecc6
|
|
| MD5 |
ad6e83bc780e4ecad7f1047388995f52
|
|
| BLAKE2b-256 |
4971bcfaef53d00ff565dc1ad56da2a3405ca7cf487f634379b1cf7c68789672
|