Skip to main content

OpenScript

CI License: Apache 2.0 Live demo

Irreversible actions wait for a person, even when the model has been fooled.

OpenScript sits between an AI agent and the tools it calls. It refuses calls outside rules you write, holds the ones that cannot be undone until a person approves that exact call, masks secrets and PII, and records every decision. None of it depends on recognising an attack, so it still holds when the model is fooled, wrong, or swapped for another.

It is for anyone building an agent whose tools have real effects, such as payments, email or a shell, in Python with any framework. It is version 0.1.0 and alpha: the API may still change.

Try the live demo → The package runs in your browser tab, compiled to WebAssembly, with no backend.

What it is not

  • Not an injection detector to rely on. It has pattern detectors, and they catch 2 to 7% of attacks they were not written for. The boundary is the rules and the approvals, and the rules are only as tight as you write them.
  • Not a compliance certification. Its compliance presets assist a program and certify nothing.

What it has been shown to do

Measured on AgentDojo's banking and Slack suites, with Qwen2.5-7B-Instruct, a model that follows prompt injections. The protocol was frozen before the run.

The run
Hardware 1 NVIDIA RTX 4090 on RunPod, Secure Cloud, EU-RO-1
Serving vLLM 0.10.2, bf16, temperature 0
Size 1,430 cases, 5,382 requests, 9.8M input and 0.63M output tokens
Errors 0
Date 2026-11-04
Configuration Attacks that succeeded Attacker's irreversible actions that took effect
No protection 58 of 249 108
Session rule: hold irreversible calls after an untrusted read 6 of 249 10
Ask a person on every irreversible call 0 of 249 0
No policy at all, effect side enforcing 0 of 249 0
  • The effect side is the boundary. A ledger in front of each irreversible tool applies a call only with a token minted when a person approves it. A call that goes round the wrapper changes nothing.
  • Safety has a price, and it is published. In the run above, asking on every irreversible call meant a person on 23 of the 37 ordinary tasks. In the no-model replay of all four suites it is 59 of 97. The session rule asks less and misses the attacks that arrive through Slack's channel listing.
  • It was attacked before it was trusted. A red team searched for bypasses and published 7 findings, each committed as a failing test before its fix.

Every number, with its date, command and caveats, is in docs/metrics.md. The claim and what it does not cover are in the threat model.

How it works

agent ── calls a tool ──► SecureTool ── before: tool rules · session rule ──► refuse / hold for a person
                              │
                              ▼  the call that was checked, and nothing else
                         effect side ── a person's token? ──► apply, and write it in the ledger
                              │
                              ▼
                          after: mask secrets and PII · record
  • Tool rules limit which tools, arguments, recipients and amounts are allowed, in YAML.
  • The session rule remembers when a session has read something a stranger wrote, and then holds the calls you list as irreversible.
  • An approval is single-use, expires in an hour, and is bound to the tool, its exact arguments and the session.
  • The effect side (evals/ledger.py) is a reference implementation, standard library only.

Quick start

pip install openscript-sdk          # Python 3.11+; pulls pydantic, structlog and PyYAML

The distribution is openscript-sdk and the package imports as openscript_sdk. The extras are [server] (the FastAPI server, whose database migrations are in this repository's alembic/), [redis], [metrics] and [otel]. To work on it, clone the repository and run make install.

A tool that the rules hold waits for a person, and the retry with the approval runs that exact call once:

from openscript_sdk import ActionBlockedError, SecureTool, ToolFirewallPolicy

async def transfer_funds(to: str, amount: int) -> str: ...

transfer = SecureTool(transfer_funds, policies=[ToolFirewallPolicy(rules_path="tools.yaml")])

call = {"to": "acct-22", "amount": 500}
try:
    await transfer.call(call)                       # held: the tool does not run
except ActionBlockedError as held:
    approval_id = held.approval_id                  # a person approves it ...

await transfer.call(call, approval_id=approval_id)  # ... and the same call runs, once
# tools.yaml
default_deny: true
rules:
  transfer_funds:
    requires_approval: true
    args:
      amount: {min: 0, max: 1000}

Also in the package: redaction of secrets and PII, input screening, an audit trail and an event server. The guide covers each.

Where it runs

Surface Start here
Python agents and tools (LangChain, LangGraph, anything with invoke) the guide
Claude Code, as a hook, with a strict profile that holds Bash after a web read the hook
Java agents, through the server clients/java
A browser, and a Chrome extension the demo

Further reading

Contributing

make install && pytest && ruff check . && black --check . && mypy --strict openscript_sdk/ --exclude openscript_sdk/server/

CONTRIBUTING.md has the full checklist, including the Pyodide and Java checks. Changes to approvals, the session rule or the hook also run pytest tests/bypass.

License

Apache License 2.0. See LICENSE.

Metadata

Release files for openscript-sdk 0.1.0

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

Source distribution (sdist)

Source distribution for openscript-sdk 0.1.0
File Size Uploaded Provenance Actions
openscript_sdk-0.1.0.tar.gz 216.4 kB Without provenance Details for openscript_sdk-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for openscript-sdk 0.1.0
File Interpreter ABI Platform Actions
openscript_sdk-0.1.0-py3-none-any.whl Python 3 none any Details for openscript_sdk-0.1.0-py3-none-any.whl

Total release size: 364.4 kB

Release files / openscript_sdk-0.1.0.tar.gz

Download URL openscript_sdk-0.1.0.tar.gz
Size 216.4 kB
Tags Source
SHA-256 checksum
How to use checksums
4d41b13c0674728d80989f12a2268f92b9e03aad15389a29c26bc34b0405ebb1
BLAKE2b-256 checksum
How to use checksums
b39a690bd377c14abdc6eafc71eee50e6c9ba9e365b79cf06f41c67c649aa621
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release files / openscript_sdk-0.1.0-py3-none-any.whl

Download URL openscript_sdk-0.1.0-py3-none-any.whl
Size 148.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
95bc64ad15b8e1499c88dc2f3a76f4404956a7507b42968aa6985d924e29862f
BLAKE2b-256 checksum
How to use checksums
ad5c68a018ea1071e07aa9d4e2f493a2924349db51d522d8eeb0e26deae145d5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Security for openscript-sdk 0.1.0

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.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

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