Metadata-Version: 2.4
Name: waveframe-guard
Version: 0.18.0
Summary: Execution-boundary SDK for allowing or blocking governed actions before they run.
Author-email: Shawn Wright <swright@waveframelabs.org>
License-Expression: Apache-2.0
Keywords: ai governance,execution boundary,policy enforcement,compliance,audit,agent safety
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
Requires-Dist: cricore<0.15.0,>=0.13.0
Requires-Dist: cricore-proposal-normalizer<0.3.0,>=0.2.0
Requires-Dist: governance-ledger<0.9.0,>=0.7.0
Requires-Dist: requests<3.0.0,>=2.33.0
Provides-Extra: test
Requires-Dist: build; extra == "test"
Requires-Dist: cricore-contract-compiler==0.4.0; extra == "test"
Requires-Dist: pytest; extra == "test"
Requires-Dist: tomli>=2.0.0; python_version < "3.11" and extra == "test"
Requires-Dist: twine; extra == "test"
Provides-Extra: dev
Requires-Dist: build; extra == "dev"
Requires-Dist: cricore-contract-compiler==0.4.0; extra == "dev"
Requires-Dist: pytest; extra == "dev"
Requires-Dist: tomli>=2.0.0; python_version < "3.11" and extra == "dev"
Requires-Dist: twine; extra == "dev"
Dynamic: license-file

<p align="center">
  <img src="https://raw.githubusercontent.com/Waveframe-Labs/.github/main/assets/branding/canon_wf_logo_extended.png" width="700">
</p>

# Waveframe Guard

Repository integrations in Guard 0.18.0: see the
[repository adapter boundary and migration guide](docs/architecture/REPOSITORY_WORKSPACE.md)
for issue #33, supported platforms, and the `repository_tool` API.

Allow or block mediated AI actions **before their callbacks execute**.

Waveframe Guard is an execution-boundary SDK. It wraps sensitive actions, resolves compiled authority, enforces the decision at the tool boundary, and only runs the action when the outcome is allowed.

Guard enforces actions that pass through its wrapped tool boundary. Actions
that reach the same capability through another function, tool, process,
credential, or API path are outside that enforcement guarantee.

Current release: 0.18.0.

```text
Guard does not generate actions.
Guard does not author governance.
Guard does not replace Cloud.
Guard decides whether this action may run now.
```

## Install

```powershell
pip install waveframe-guard==0.18.0
```

Published Guard 0.17.0 has an unbounded CRI dependency and must not be paired
with CRI 0.14. Guard 0.18.0 supports `cricore>=0.13.0,<0.15.0`.
Upgrade/install Guard 0.18.0 before CRI 0.14.0. Ordinary installation works
with published CRI 0.13.0 and needs no unpublished dependency. See the
[compatibility matrix](docs/getting-started/README.md#dependency-compatibility-matrix).


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.

## License and commercial boundary

The Waveframe Guard Core SDK in this repository is open source under
[Apache License 2.0](LICENSE). Commercial use, modification, redistribution, and
hosting of the Guard Core SDK are permitted under Apache-2.0. This includes use
of the local SDK without a Waveframe subscription. Retain the applicable license
and attribution notices.

Apache-2.0 does not grant rights to Waveframe names or trademarks, except for
the license's customary origin-identification and NOTICE exceptions.

Waveframe Cloud, Console, hosted translation, managed evidence operations,
Guard Inspector, Ledger Workspace, enterprise identity/integrations, support,
and other separately distributed services and products remain separate
commercial offerings; this repository does not relicense them. These product
boundaries do not restrict Apache-2.0 rights to any SDK code included here,
including its Cloud client integrations.

See [contributing](CONTRIBUTING.md) and the
[licensing scope and dependency notices](docs/LICENSING.md). This change is
included in Guard 0.18.0, the first package release under Apache-2.0. Prior
tagged and PyPI releases are not retroactively relicensed.

## 30-second integration

With the Cloud environment variables from the next section configured, wrap an
existing Python function directly:

```python
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)
# Calling guarded_allocate evaluates authority immediately before invoking
# your_existing_allocate_budget, which performs the mediated mutation.
```

Expose `guarded_allocate` to the agent. The exact wrapped mutation callable is
`your_existing_allocate_budget`; this protects that callable path, not the
entire machine or repository globally. Direct calls to the original function
bypass this wrapper. For repository writes use `repository_tool` and its bound
file capability; see the [bypass threat model and operator checks](docs/architecture/REPOSITORY_WORKSPACE.md#mediation-and-bypass-threat-model).

## Five-minute Cloud quickstart

Start in an empty directory. No Ollama installation or Waveframe repository
checkout is involved:

```powershell
mkdir guard-quickstart
cd guard-quickstart
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install waveframe-guard==0.18.0
Invoke-WebRequest https://raw.githubusercontent.com/Waveframe-Labs/Waveframe-Guard/v0.18.0/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:

```powershell
$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:

```text
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 quickstart wraps `run_quickstart`'s `allocate_budget` with `@guard.tool`;
its mediated mutation is `mutations.append(mutation)`, an in-memory example.
Evaluation occurs immediately before invoking that callback. It does not
protect the entire machine or repository globally.

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.

A connected Guard runtime means a specific Guard integration is reporting.
It does not establish global control of the repository, machine, agent, or
organization, or establish that no alternate mutation path is available.

The integration inside the quickstart is the same wrapper used around an
existing agent tool:

```python
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_identity` identifies the agent or human attempting the action.
- `authority` selects the explicit, versioned policy Guard will enforce.
- `agent` records optional framework and model metadata for Console and audit evidence.

### Cloud availability

Guard 0.18.0 can verify matching Ledger v2 and v3 publication envelopes.
Waveframe Cloud source support for atomic v2/v3 publication serving merged
in Cloud PR #135. Hosted translation backend and Console workflow source
merged in PRs #136 and #140. At the Guard 0.18.0 release date, those Cloud
changes had not yet been released or deployed to the hosted service.
Guard does not claim hosted translation availability at that date.

The `GET /v1/authorities/{authority_ref}/publication` response uses
`cloud_authority_publication.v1` to bind the bundle, receipt, logical
references, registry, and envelope as one tenant-scoped publication. Existing
organization/API-key authentication is unchanged. Legacy v1 authorities retain
their existing contract endpoint through a narrow publication-not-found
fallback; a contract-only v2 response still fails closed. Guard 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.

The runtime credential may be passed explicitly as
`Guard.cloud(cloud_url=..., runtime_credential=..., authority=...)`; the
existing `cloud_api_key=` argument and `WAVEFRAME_CLOUD_API_KEY` environment
variable remain supported. Organization and runtime identity configuration are
unchanged.

Application code supplies no runtime facts, hashes, bundles, or Ledger
validator calls. A cold resolution performs one publication request and the
complete verification chain. Warm evaluation performs no additional request
and no heavy Ledger validation. Existing v1/v2, finance, and local-resolver
behavior remains compatible.

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:

```python
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. For this integration,
the registry exposes `guarded_tool`. Calls routed through that registry entry
are evaluated before `guarded_tool` invokes `publish_release`. Direct access to
`publish_release` or another release API bypasses the wrapper; registration alone
does not remove those paths. Restrict alternate paths using the linked
[least-privilege deployment guidance](docs/architecture/REPOSITORY_WORKSPACE.md#least-privilege-deployment).
Guard remains framework-neutral and does not become 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:

```json
{
  "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.9.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:

```python
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 and v3 support currently 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 or model-provider
integration, 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. For the distinction between
merged Cloud source and hosted availability at this release date, see
[Cloud availability](#cloud-availability).

Published `governance-ledger==0.8.0` has a `[guard]` extra pinned to
`waveframe-guard==0.17.0`. Ledger's base package remains compatible with
Guard 0.18.0 through `governance-ledger>=0.7.0,<0.9.0`. Install
`waveframe-guard==0.18.0` directly for this release rather than relying on
`governance-ledger[guard]==0.8.0`; that extra does not install Guard 0.18.0.

## Local development path

For offline development, a local authority registry is still supported:

```python
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 a legacy Ledger `authority_bundle.v1` or a
provenance-complete Ledger `authority_bundle.v2` or `authority_bundle.v3`.
Every v2 or v3 registry entry must also name the matching publication receipt
and its canonical hash; a standalone or directly injected v2 contract is
rejected. Native v3 verification requires Ledger 0.8 or later. With Ledger 0.7,
v1/v2 remain supported and a supplied v3 artifact fails closed with a clear
unsupported-Ledger-version error. 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 | Upstream deterministic kernel; advisory evaluation never grants Guard execution permission. |

The complete Ledger v2/v3 product flow is:

```text
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
```

For v3, Guard verifies the complete bundle and mandatory receipt, then evaluates
the unchanged `compiled_authority_contract.v2` runtime payload. Translation
proposals and private provider evidence are not runtime inputs. Existing
Cloud-facing v1/v2 and finance client behavior remains compatible. See
[Cloud availability](#cloud-availability) for the source and hosted availability
distinction at this release date.

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](docs/getting-started/README.md#dependency-compatibility-matrix) for minimum, recommended, and release-tested pairings.

## Legacy execution migration (0.18.0)

Guard execution is never advisory. Local/cloud controls authority resolution and
service connectivity, not enforcement strength. Advisory CRI evaluation is not
permission to execute.

Legacy `waveframe_guard.execute`, `@waveframe_guard.guard`, and
`GovernedRuntime`/`GuardRuntime` execution and permission methods now fail closed
with `LegacyExecutionError` (a `GovernanceError` subclass). The exported
`evaluate_admissibility` permission helper does too. These APIs cannot establish
strict integrity/publication evidence. `fail_mode="open"` and
`raise_on_block=False` cannot bypass this migration error; no callback or new
execution evidence is produced.

Use the current `Guard.local()` / `Guard.cloud()` API and guarded tools shown
above. See the [migration guide](docs/getting-started/STRICT_EXECUTION_MIGRATION.md)
for the complete affected API list and repository-tool migration in 0.18.0.

## 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.v1`
- `guard_release_validation.v1`
- `release blocked` when 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:

```text
code
+ README / docs
+ CHANGELOG
+ pyproject metadata
+ version-dependent files
+ tests
+ package build
+ tag
```
