Waveframe Guard
Stop unsafe AI and automated actions before they execute.
Waveframe Guard is an execution-boundary SDK. It wraps sensitive actions, resolves compiled authority, evaluates through CRI-CORE, and only runs the action when the outcome is allowed.
Current release: 0.16.0.
Guard does not generate actions.
Guard does not author governance.
Guard does not replace Cloud.
Guard decides whether this action may run now.
Install
pip install waveframe-guard==0.16.0
No Ollama installation or Waveframe repository checkout is required. Keep the customer's existing model, agent framework, and tool functions; Guard wraps the tool that can cause a real-world change.
30-second integration
With the Cloud environment variables from the next section configured, wrap an existing Python function directly:
import os
from waveframe_guard import Guard
guard = Guard.cloud(
authority=os.environ["WAVEFRAME_AUTHORITY_REF"],
runtime_id=os.environ["WAVEFRAME_RUNTIME_ID"],
environment=os.environ["WAVEFRAME_RUNTIME_ENVIRONMENT"],
actor_identity={
"id": os.environ["WAVEFRAME_ACTOR_ID"],
"type": "agent",
"role": os.environ["WAVEFRAME_ACTOR_ROLE"],
},
)
guarded_allocate = guard.tool(
action="allocate_budget",
target="account_id",
include_arguments=("amount",),
)(your_existing_allocate_budget)
Call or register guarded_allocate wherever the original function was used.
Guard evaluates immediately before the existing mutation and remains separate
from model calls and agent orchestration.
Five-minute Cloud quickstart
Start in an empty directory. No Ollama installation or Waveframe repository checkout is involved:
mkdir guard-quickstart
cd guard-quickstart
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install waveframe-guard==0.16.0
Invoke-WebRequest https://raw.githubusercontent.com/Waveframe-Labs/Waveframe-Guard/main/examples/external_agent_quickstart.py -OutFile quickstart.py
The example expects an active published authority that allows a 500-unit
allocate_budget action for the configured actor role and requires missing
approval evidence at 10,000 units or above. Configure the runtime credential,
runtime identity, actor identity, and exact authority reference:
$env:WAVEFRAME_CLOUD_URL="https://cloud.waveframelabs.com"
$env:WAVEFRAME_CLOUD_ORGANIZATION_ID="acme"
$env:WAVEFRAME_CLOUD_API_KEY="<runtime credential>"
$env:WAVEFRAME_RUNTIME_ID="budget-agent-runtime"
$env:WAVEFRAME_RUNTIME_ENVIRONMENT="development"
$env:WAVEFRAME_ACTOR_ID="budget-agent"
$env:WAVEFRAME_ACTOR_ROLE="allocator"
$env:WAVEFRAME_AUTHORITY_REF="budget-quickstart@1.0.0"
python quickstart.py
Expected terminal proof:
runtime_id=budget-agent-runtime
actor_id=budget-agent
authority_ref=budget-quickstart@1.0.0
allowed_decision=allowed
blocked_decision=blocked
mutation_count=1
exactly_once=True
allowed_package_id=<Cloud package identifier>
allowed_receipt_id=<Cloud receipt identifier>
allowed_proof_sha256=<Cloud proof digest>
blocked_package_id=<Cloud package identifier>
blocked_receipt_id=<Cloud receipt identifier>
blocked_proof_sha256=<Cloud proof digest>
The allowed callback mutates once. The blocked callback never runs. Open Console Activity or Executions to verify both decisions under the same runtime, actor, and bound authority.
The integration inside the quickstart is the same wrapper used around an existing agent tool:
from waveframe_guard import Guard
guard = Guard.cloud(
authority="repository-change-policy@1.0.0",
environment="production",
actor_identity={
"id": "release-agent",
"type": "agent",
"role": "repository-maintainer",
},
)
@guard.tool(
action="allocate_budget",
target="account_id",
include_arguments=("amount",),
agent={"framework": "custom-python"},
)
def allocate_budget(account_id: str, amount: int):
return your_existing_mutation(account_id, amount)
The three choices are intentionally independent:
actor_identityidentifies the agent or human attempting the action.authorityselects the explicit, versioned policy Guard will enforce.agentrecords optional framework and model metadata for Console and audit evidence.
Guard.cloud(...) fetches the published compiled authority from Cloud, verifies
its identity and hash, and fails closed if it cannot obtain a trustworthy
contract. It uses runtime_id= when provided and otherwise uses
actor_identity["id"] as the runtime identity. Guard registers that runtime,
sends its first heartbeat, and exposes the observational result as
guard.runtime_connection. Guard still evaluates locally before calling the
wrapped function. Afterward, it preserves the decision and attests whether the
wrapped callback executed, failed, or did not run.
Long-running processes may call guard.heartbeat() from their existing health
loop. Cloud reporting failures are returned as structured status and never
change Guard's local decision or cause an allowed callback to run twice.
Evidence preservation uses a 10-second timeout by default. Configure it only
when needed: Guard.cloud(..., preservation_timeout_seconds=15.0). Guard
never retries an ambiguous preservation write automatically, because Cloud may
already have committed the immutable evidence.
Tool arguments are excluded from preserved evidence by default. Add only safe,
decision-relevant names to include_arguments; prompts, tokens, file contents,
and other sensitive values should remain excluded.
By default, an allowed tool returns the wrapped function's original value and a
blocked tool raises, which fits normal agent framework tool registration. Set
return_result=True with raise_on_block=False when an integration needs the
same structured Guard envelope for both decisions.
Works with existing agents
@guard.tool(...) is framework-neutral. It wraps an ordinary Python callable,
so the model may be hosted or local and the orchestration layer may be a custom
agent, LangGraph, CrewAI, an OpenAI tool loop, or another framework. Guard does
not generate the tool call and does not require the model to emit Guard-specific
JSON.
A framework-neutral adapter only registers the already-guarded callable:
guarded_tool = guard.tool(action="publish_release", target="repository")(publish_release)
agent_tools.register(name="publish_release", callable=guarded_tool)
agent_tools represents the customer's existing registry. It may call the
model and choose tools, but only guarded_tool can reach publish_release, so
Guard remains the enforcement boundary rather than becoming the agent framework.
The wrapper derives a normalized proposal from the real function call, asks Guard to evaluate it against the selected authority, and invokes the original function only when admissible. A blocked call never reaches the original function.
Target scope
Target scope controls which resources an automated action may or may not
change. A compiled authority can allow README.md while denying the
deployment/ prefix:
{
"target_requirements": {
"allow": [{"match": "exact", "value": "README.md"}],
"deny": [{"match": "prefix", "value": "deployment/"}]
}
}
Guard enforces the compiler-defined target requirements against the normalized target from the actual tool call before the callback runs. Rules are literal and case-sensitive; deny rules win. Missing or malformed scope, or a missing/invalid target when scope is present, fails closed. Authorities with no target requirements retain their legacy target-free behavior.
CRI-CORE Contract Compiler v0.4.0 defines deterministic target requirements;
Guard consumes the compiled authority artifact unchanged and enforces it. It
does not compile policy. The native Ledger v2 path uses the base
governance-ledger>=0.7.0,<0.8.0 base package for publication verification; it
tests the public 0.7.0 minimum and never uses Ledger's guard extra. Immutable
artifact schema versions, not a single patch-level package pin, define the v2
validation boundary.
Five-minute Ledger v2 repository example
Ledger translates the company policy with its trusted repository-changes/1.0.0
domain pack and publishes the versioned authority bundle plus receipt. Configure
the existing resolver once for the publication registry, then protect the
repository mutation:
from waveframe_guard import Guard
from waveframe_guard.authority.adapters import LocalRegistryResolver
resolver = LocalRegistryResolver(workspace_root=".")
guard = Guard.local(
authority="repository-authority@1.0.0",
authority_resolver=resolver,
actor_identity={
"id": "repository-agent",
"type": "agent",
"role": "repository-maintainer",
},
)
@guard.tool(action="modify", target="path")
def write_file(path: str):
return your_existing_write(path)
write_file("README.md") # allowed; callback runs once
write_file("deployment/production.yml") # blocked; callback never runs
Guard verifies the complete publication before the authority is cached or used. It then supplies only the fact names and types selected by the published domain pack. Guard does not read or interpret policy prose. Fact derivation and enforcement are deterministic and fail closed.
Guard verifies the exact Ledger-published authority, derives only schema-approved runtime facts, and binds every decision to immutable evidence. The evidence binds the complete bundle, receipt, contract, domain pack, runtime fact schema, Constraint IR, and derived fact set. Execution attestations report callback invocation and completion truthfully; after a callback exception, mutation state remains unknown rather than being guessed.
Application code does not open bundle or receipt files, calculate hashes, construct runtime facts, or call Ledger validators. The resolver retrieves the complete publication package by identity; physical storage layout remains an implementation detail behind that boundary.
Native v2 support initially covers only repository-changes/1.0.0. Other
domains require their own separately trusted domain pack and Guard fact
provider; finance and existing integrations continue through the legacy v1
compatibility path.
Guard does not interpret policy prose and contains no AI, NLP model, heuristic policy interpretation, or runtime inference. Ledger and a trusted domain pack produce authority. Only the repository-change fact provider is native in this release; other domains require separately trusted domain packs and deterministic fact providers. Cloud integration for the complete v2 workflow is follow-on work, and this release does not claim that Cloud distributes or consumes the full v2 chain.
Ledger's published governance-ledger[guard]==0.7.0 extra still represents its
previously released Guard 0.15 compatibility pairing. Install
waveframe-guard==0.16.0 directly for this release. Guard itself depends only
on the public Ledger base package through
governance-ledger>=0.7.0,<0.8.0, never on the guard extra.
Local development path
For offline development, a local authority registry is still supported:
from waveframe_guard import Guard
guard = Guard.local(
workspace=".guard-local",
authority="finance-policy@1.0.0",
actor_identity={"id": "agent-1", "type": "agent", "role": "analyst"},
)
@guard.tool(action="wire_transfer", target="account_id")
def wire_transfer(account_id, amount):
return perform_transfer(account_id, amount)
Guard.local(authority=...) loads either a legacy Ledger authority_bundle.v1
or a provenance-complete Ledger authority_bundle.v2. A v2 registry entry must
also name the matching publication receipt and its canonical hash; a standalone
or directly injected v2 contract is rejected. Direct contract=...,
authorities={...}, and authority_loader=... inputs remain available for v1
advanced integrations and compatibility.
What Guard owns
Guard owns the developer-side enforcement boundary:
- local SDK integration
- compiled authority resolution
- normalized execution request enforcement
- local allow/block/escalate outcomes
- continuation windows and deferred release checks
- local receipts, replay artifacts, and runtime diagnostics
- evidence spooling for later Cloud submission
Guard does not author governance, publish authority, host organization workflows, operate the long-term evidence system, or ship the proprietary Guard Inspector UI.
Guard, Cloud, and Ledger
| Product | Responsibility |
|---|---|
| Guard | Verify published authority, derive schema-approved runtime facts, and enforce locally before execution. |
| Cloud | Store authority, evidence, receipts, replay packages, lifecycle state, and continuity records. |
| Ledger / Workspace | Author, review, activate, and publish deterministic governance authority. |
| CRI-CORE | Deterministic admissibility kernel used under the Guard boundary. |
The complete Ledger v2 product flow is:
Ledger translates policy with a trusted domain pack and publishes authority
-> Guard resolves and verifies the complete publication
-> Guard derives typed facts and enforces before execution
-> Guard emits bound decision evidence and execution attestation
Cloud integration for distribution and consumption of this complete v2 chain is follow-on work. Existing Cloud-facing v1 and finance behavior remains compatible; Cloud is not claimed to distribute or consume the full v2 chain in this release.
Cloud can publish lifecycle metadata such as active, superseded, or revoked, but Cloud does not decide runtime admissibility. Guard evaluates locally against compiled authority.
The selected domain pack owns the vocabulary and runtime fact schema. Guard supplies those facts from the intercepted proposal and never interprets policy language.
See the single authoritative release compatibility matrix for minimum, recommended, and release-tested pairings.
Local authority registry
For applications that resolve published contracts from a local registry, use the runtime layer:
from waveframe_guard import GovernedRuntime
runtime = GovernedRuntime(
registry_path="contracts/index.json",
reject_revoked_authority=True,
warn_on_superseded=True,
)
runtime.install_actor({"id": "user-1", "type": "human", "role": "manager"})
runtime.bind_contract("finance-policy@1.0.0")
result = runtime.execute(
fn=transfer,
args=(1250000,),
raise_on_block=False,
)
Runtime authority refs are explicit and versioned. Use finance-policy@1.0.0; unversioned IDs such as finance-policy are rejected because replay, audit, and cache integrity depend on deterministic authority identity.
Cloud-connected runtime
For application code that needs Cloud authority metadata and evidence delivery, use the Cloud-connected runtime:
from waveframe_guard import GuardRuntime
runtime = GuardRuntime.from_cloud(
authority="finance-policy@1.0.0",
api_key="...",
)
result = runtime.execute(
actor={"id": "user-1", "type": "human", "role": "manager"},
fn=transfer,
args=(1250000,),
raise_on_block=False,
)
runtime.flush_evidence()
execute(...) still enforces locally. Cloud availability is only required when you explicitly call flush_evidence().
Guard writes evidence to a durable local spool first:
.waveframe_guard/evidence/
pending/
sent/
failed/
If a flush fails, evidence is retained and can be submitted again later.
Continuation and deferred release
Guard separates admissibility from release. An action can be admissible at T1, queued or delayed, and then blocked at T2 if its continuation lease no longer validates.
Guard emits:
guard_continuation_lease.v1guard_release_validation.v1release blockedwhen execution was admissible earlier but a runtime dependency expired before release
Continuity signals are not Cloud decisions. Guard evaluates continuity locally; Cloud may display and preserve the evidence.
Guard Inspector
Guard Inspector is the private operational visualization layer for SDK-emitted evaluations, receipts, replay artifacts, continuity signals, and release posture.
It consumes Guard outcomes and artifacts. It is not part of the public Guard SDK package, does not author policy, and does not own enforcement semantics.
Repository surface
The public Guard surface includes:
- SDK facade
- local runtime
- deterministic evaluation model
- continuation governance
- replay artifacts
- deferred release model
- examples
- docs
- tests
- sample compiled contracts
Non-production or split-bound work is quarantined under temp/. In particular, temp/labs/cloud_runtime/ is a lab preview for future Cloud product work, not production Guard Cloud and not required for local enforcement.
Release discipline
Every substantive Guard change must update the release surface together:
code
+ README / docs
+ CHANGELOG
+ pyproject metadata
+ version-dependent files
+ tests
+ package build
+ tag
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 waveframe_guard-0.16.0.tar.gz.
File metadata
- Download URL: waveframe_guard-0.16.0.tar.gz
- Upload date:
- Size: 131.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f336da1ed4c7227047d20a7610b8f5a73be0f19031eda9fd01cd2764aff6e3bc
|
|
| MD5 |
03e13a8be365d81046ef210aa9ea8b6b
|
|
| BLAKE2b-256 |
6b66d60481516ee6c8d40e850d1e89d56c37a893d580584233a6548dff24c37b
|
File details
Details for the file waveframe_guard-0.16.0-py3-none-any.whl.
File metadata
- Download URL: waveframe_guard-0.16.0-py3-none-any.whl
- Upload date:
- Size: 92.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b70adb46aec54fe4b5be4b6bbc065b6ce3246f89e678857cdd83b3cf1b311c60
|
|
| MD5 |
a50b593d580fcf484bbd24a0cc9a132e
|
|
| BLAKE2b-256 |
c2ac44f21db9fc4a9a687d9f21c603cd2b7077c526d152a2708a7258ca234fe1
|