Python bindings for Axiom - a verification-first policy engine for AI agents
Project description
axiom-py
Python bindings for Axiom — a verification-first policy engine for AI agents.
What Axiom Guarantees
Cite these properties when documenting your agent's safety posture:
| ID | Guarantee |
|---|---|
| G1 | Pre-flight pure query. verify() has zero side effects. The engine never reads files, opens sockets, or mutates state. |
| G2 | Effect-class-based, not heuristic. A WRITE intent is a WRITE intent whether the LLM calls it SaveDocument, OutputData, or UpdateFile. Axiom works on what an action structurally does — not on names or content, both of which are bypassable by rephrasing. |
| G3 | Deterministic. Same input always produces the same verdict. Thread-safe. |
| G4 | Monotonic ratchet. Restrictions only accumulate. A policy can add conscience predicates but never silently drop them. |
| G5 | Specific denial. verdict.reason cites the exact predicate, value, and reason. verdict.guidance provides the human-readable category. |
Installation
pip install axiom-lang
Or build from source:
cd axiom_py
pip install maturin
maturin develop
Quickstart: Under 5 Lines
Option 1 — Preset (recommended for common cases):
from axiom.presets import filesystem_readonly
engine = filesystem_readonly(allowed_paths=["/home/user/project"])
verdict = engine.verify("ReadFile", {"path": "/etc/passwd"})
# verdict.allowed == False
Option 2 — Decorator:
from axiom import guard, AxiomDenied
@guard(effect="READ", conscience=["path_safety"])
def read_file(path: str) -> str:
with open(path) as f:
return f.read()
read_file("/etc/shadow") # raises AxiomDenied
Option 3 — Builder:
from axiom import PolicyBuilder, Effect
engine = (
PolicyBuilder()
.intent("ReadFile", effect=Effect.READ, conscience=["path_safety"])
.build()
)
verdict = engine.verify("ReadFile", {"path": "/etc/shadow"})
# verdict.allowed == False
Effect Class Table
| Effect | Meaning | Default conscience (presets) |
|---|---|---|
READ |
Read data from a resource | path_safety |
WRITE |
Write or modify a resource | path_safety, no_exfiltrate |
EXECUTE |
Execute code or a command | no_harm, no_bypass_verification |
NETWORK |
Send data over the network | no_exfiltrate |
NOOP |
Pure computation, no side effects | (none) |
Conscience Predicates
Conscience predicates are named safety policies evaluated automatically against an intent's effect class and field values.
| Predicate | Effects | What it blocks | Used in preset |
|---|---|---|---|
path_safety |
READ, WRITE | /etc /proc /sys /boot /root /dev; path traversal (../); URL-encoded variants (%2e%2e); fullwidth unicode path components |
filesystem_readonly, filesystem_readwrite, agent_standard, coding_assistant |
no_exfiltrate |
NETWORK, WRITE | Any destination not in the declared-channel registry; fields: url destination endpoint address target host uri remote; blocks /mnt/ /net/ writes |
filesystem_readwrite, network_egress, agent_standard, coding_assistant |
no_harm |
WRITE, EXECUTE, NETWORK | Destructive intent names (Delete Drop Erase Format Kill Purge Remove Shutdown Terminate Truncate Wipe) unless authorized=true in fields |
code_execution_sandboxed, coding_assistant |
no_bypass_verification |
EXECUTE | Code/script/command/payload execution unless verified=true in fields or trust level ≥ TRUSTED_INTERNAL |
code_execution_sandboxed, coding_assistant |
baseline_allow |
NOOP, READ | Applied automatically — permits safe read and no-op operations without an explicit allow rule | (all) |
verdict.reason contains the specific technical string from the predicate that denied the
action. verdict.guidance contains the higher-level category message.
Presets Reference
| Function | Intents | Returns | Notes |
|---|---|---|---|
filesystem_readonly(allowed_paths=None) |
ReadFile |
GuardedEngine |
Allow-list optional |
filesystem_readwrite(allowed_paths=None) |
ReadFile, WriteFile |
GuardedEngine |
Allow-list optional |
network_egress() |
HttpRequest |
AxiomEngine |
— |
code_execution_sandboxed() |
ExecuteCode |
AxiomEngine |
— |
agent_standard(allowed_paths=None) |
ReadFile, WriteFile, ProcessData |
GuardedEngine |
Allow-list optional |
coding_assistant(project_root) |
ReadFile, WriteFile, RunCommand |
GuardedEngine |
project_root required |
from axiom.presets import (
filesystem_readonly,
filesystem_readwrite,
network_egress,
code_execution_sandboxed,
agent_standard,
coding_assistant,
)
GuardedEngine enforces allowed_paths by resolving symlinks (os.path.realpath) at
construction time. Paths outside the allow-list receive a synthetic denial before the
engine is consulted.
Builder API
from axiom import PolicyBuilder, Effect, Conscience, IntentBuilder
engine = (
PolicyBuilder(module_name="my_policy") # optional name
.intent(
"ReadFile",
effect=Effect.READ, # or "READ"
conscience=[Conscience.PATH_SAFETY], # or ["path_safety"]
takes=[("path", "String")], # optional — for introspection
gives=[("content", "String")], # optional
pre=["length(path) > 0"], # optional pre-condition expressions
bound="time(5s), memory(64mb)", # optional resource bounds
)
.intent("WriteFile", effect=Effect.WRITE, conscience=["path_safety", "no_exfiltrate"])
.build() # returns AxiomEngine
)
# Async variant
engine = await PolicyBuilder().intent(...).build_async()
# Inspect generated source
print(PolicyBuilder().intent("ReadFile", effect="READ", conscience=["path_safety"]).source())
Conscience constants: PATH_SAFETY, NO_EXFILTRATE, NO_HARM, NO_BYPASS_VERIFICATION.
Decorator API
from axiom import guard, AxiomDenied
@guard(effect="READ", conscience=["path_safety"])
def read_file(path: str) -> str:
with open(path) as f:
return f.read()
# Async functions work transparently
@guard(effect="WRITE")
async def write_file(path: str, content: str) -> None:
...
# Handle denials
try:
read_file("/etc/shadow")
except AxiomDenied as e:
print(e.reason) # specific predicate failure
print(e.guidance) # human-readable category
print(e.category) # e.g. "ResourcePolicy"
print(e.verdict) # full Verdict object
guard parameters:
| Parameter | Default | Description |
|---|---|---|
effect |
(required) | Effect class string |
conscience |
effect-based default | Conscience predicate list |
intent_name |
PascalCase of function name | Intent name in the policy |
engine |
built at decoration time | Existing engine to reuse |
field_map |
None |
Rename function params before passing to verify() |
coerce |
str |
Callable applied to each argument value |
Coercion note: coerce=str means str(True) → "True" (capital T).
Predicates that test authorized=true (lowercase) require explicit string "true".
Integrations
LangChain
from axiom.presets import filesystem_readonly
from axiom.integrations.langchain import AxiomGuardedTool
engine = filesystem_readonly(allowed_paths=["/workspace"])
guarded = AxiomGuardedTool(
base_tool=my_langchain_tool,
engine=engine,
intent_name="ReadFile", # optional — defaults to tool.name
on_deny="raise", # "raise" | "return_none" | "return_denial"
)
# Use inside a LangChain agent executor as a drop-in replacement
result = guarded._run(path="/workspace/notes.txt")
AxiomGuardedTool exposes name, description, args_schema, _run(), and _arun()
— sufficient for all LangChain agent executors. No hard LangChain import required.
OpenAI
from openai import OpenAI
from axiom.presets import filesystem_readonly
from axiom.integrations.openai import AxiomInterceptor
client = AxiomInterceptor(
OpenAI(),
engine=filesystem_readonly(allowed_paths=["/workspace"]),
auto_verify=True, # raises AxiomDenied before returning any response with denied tool calls
)
response = client.chat.completions.create(
model="gpt-4o",
messages=[...],
tools=[...],
)
# ^ raises AxiomDenied if the model requested a disallowed tool call
# Manual verification
results = client.verify_tool_calls(response)
for tool_call, verdict in results:
print(tool_call.function.name, verdict.allowed)
client.assert_tool_calls_safe(response) # raises on first denial
Limitation: auto_verify=True only works with non-streaming completions.
VS Code Syntax Highlighting
A TextMate grammar for .axm files is included in editors/vscode/.
# One-time VS Code install (no marketplace needed):
ln -s $(pwd)/editors/vscode ~/.vscode/extensions/axiom
# Reload VS Code window → .axm files gain syntax highlighting
vs. Content Filtering
Most agent safety tooling works on intent names or content — both bypassable by
renaming or rephrasing. Axiom works on what an action structurally does.
A WRITE intent is a WRITE intent whether the LLM calls it SaveDocument,
OutputData, or UpdateFile. Effect-class enforcement is structural, not
heuristic, and cannot be bypassed by rewording the request.
.axm pre/post Functions
The following functions are available in pre: and post: clauses when writing
.axm policy source (via AxiomEngine.from_source() or PolicyBuilder):
| Function | Returns | Description |
|---|---|---|
length(s) |
Int | String or array length |
path_exists(p) |
Bool | Whether the path exists on the filesystem |
path_is_safe(p) |
Bool | path_safety conscience check on a path value |
space_available(p, bytes) |
Bool | Whether sufficient disk space is available at path |
schema_is_registered(s) |
Bool | Whether a schema name is present in the registry |
structural_valid(data, schema) |
Bool | Whether data matches the structure of the named schema |
License
Apache-2.0
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 Distributions
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 axiom_lang-0.2.0-cp312-abi3-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: axiom_lang-0.2.0-cp312-abi3-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 663.1 kB
- Tags: CPython 3.12+, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.11.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
88bd730cefffa65e61ffa32ba0895c6ffd99a03f8c2cdc9df83c60de0c5b7618
|
|
| MD5 |
73bd8b1416bda16f38d16ac3cfe96ba7
|
|
| BLAKE2b-256 |
2493b247b530940ce82a69e5be24e4ddd5636f7da7aed8a13581d74973c79be4
|