Metadata-Version: 2.4
Name: siphrix
Version: 1.0.2
Summary: Siphrix — AI Action Firewall & Policy Runtime. Evaluates every agent action against a policy before execution, emits an auditable decision trail, and fails closed when in doubt.
Author: Siphrix Contributors
License: MIT License
        
        Copyright (c) 2026 Denis Ghengeaua
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/Ghengeaua/siphrix
Project-URL: Repository, https://github.com/Ghengeaua/siphrix
Project-URL: Documentation, https://github.com/Ghengeaua/siphrix/tree/main/docs
Project-URL: Changelog, https://github.com/Ghengeaua/siphrix/blob/main/CHANGELOG.md
Project-URL: Issues, https://github.com/Ghengeaua/siphrix/issues
Keywords: ai,ai-agents,ai-safety,action-firewall,policy-engine,policy-runtime,governance,audit,enforcement,fail-closed
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: Intended Audience :: Information Technology
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Monitoring
Classifier: Typing :: Typed
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: cryptography>=45.0.0
Requires-Dist: jsonschema==4.23.0
Requires-Dist: PyNaCl>=1.5.0
Requires-Dist: PyYAML>=6.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0.0; extra == "dev"
Provides-Extra: build
Requires-Dist: build>=1.0; extra == "build"
Requires-Dist: twine>=5.0; extra == "build"
Dynamic: license-file

﻿# Siphrix v1.0.0

**Siphrix — AI Action Firewall & Policy Runtime.**
Siphrix sits between what an AI *wants to do* and what it is *allowed to do*: it evaluates every agent action against a policy before execution, emits an auditable decision trail, and fails closed when in doubt.

**Evaluating Siphrix?** Start with [docs/launch/QUICK_EVAL.md](docs/launch/QUICK_EVAL.md) — a 60-second pitch, a 6-command offline smoke block, and pointers to the 5-minute live demo script ([docs/launch/DEMO_SCRIPT.md](docs/launch/DEMO_SCRIPT.md)), launch-grade release notes ([docs/launch/RELEASE_NOTES_v1.0.0.md](docs/launch/RELEASE_NOTES_v1.0.0.md)), and the post-install cheat sheet ([docs/launch/PUBLIC_HANDOFF.md](docs/launch/PUBLIC_HANDOFF.md)) with the expected `doctor`/`demo` signals.

Under the hood Siphrix is built from four coordinated layers — a **policy decision layer**, a **runtime enforcement layer**, a **trust / audit / governance support layer**, and an **operator readiness surface** — but externally it is one product: the firewall that sits at the boundary between agent intent and real-world action.

---

## Try it in 30 seconds

After `pip install siphrix` the canonical first-run path is three
commands — fully offline, no API keys, no Docker:

```bash
python -m siphrix --help     # discover every subcommand
siphrix demo                 # the official three-flow walkthrough (block, allow, audit)
siphrix doctor               # human-readable launch-readiness report
```

`siphrix demo` is the golden path; it prints a blocked unsafe action,
an allowed safe action under the shipped `safe_defaults` pack, and an
auditable decision-trail recap. The repo-only walkthrough at
[`examples/example_agent.py`](examples/example_agent.py) is a deeper
practical-integration tour, useful after `siphrix demo`.

> **Heads up — fail-closed by default.** The focused examples under
> [`examples/basic_agent/`](examples/basic_agent/),
> [`examples/tool_calling/`](examples/tool_calling/), and
> [`examples/universal_pattern/`](examples/universal_pattern/) emit
> `BLOCK (policy_empty_allowlist)` when no policy is configured. That
> is Siphrix's expected security posture, not a broken install. Run
> `siphrix demo` for the canonical ALLOW/BLOCK walkthrough, or set
> `SIPHRIX_POLICY_FILE` to bind the example to a real policy.

---

## What it looks like in practice

These examples are abridged from the current practical integration demo:

    $ python examples/example_agent.py --scenario blocked_delete

    ======================================================================
    DEMO SCENARIO
    {'scenario_id': 'blocked_delete', 'title': 'Blocked destructive request', ...}
    ======================================================================
    USER INPUT
    delete the payroll file
    ======================================================================
    LLM PLAN
    {'tool': 'file_delete', 'path': './payroll/payroll.xlsx', 'reason': 'User requested deletion of payroll file.'}
    ======================================================================
    POLICY PACK RESULT
    {'decision': 'deny', 'reason': 'file_delete is disabled by policy.'}
    ======================================================================
    FINAL RESULT
    {'status': 'blocked_or_review', 'decision': 'deny', 'reason': 'file_delete is disabled by policy.'}


    $ python examples/example_agent.py --scenario allow_report_read

    ======================================================================
    DEMO SCENARIO
    {'scenario_id': 'allow_report_read', 'title': 'Allowed report read', ...}
    ======================================================================
    USER INPUT
    read the quarterly report
    ======================================================================
    LLM PLAN
    {'tool': 'file_read', 'path': './reports/report.txt', 'reason': 'User requested reading a report file.'}
    ======================================================================
    POLICY PACK RESULT
    {'decision': 'proceed', 'reason': 'Read path allowed by policy.'}
    ======================================================================
    FINAL RESULT
    {'status': 'completed', 'result': '[stub] Read file: ./reports/report.txt'}


The agent never executes anything directly. Every action passes through the enforcement layer first.

---

Siphrix v1.0.0 is the **AI Action Firewall & Policy Runtime**. It sits at the boundary between model output and real-world action, turning structured agent intents into policy-evaluable, auditable, fail-closed decisions. A practical integration layer is included in the repository so you can place Siphrix between a planner and a real executor without allowing direct tool execution.

## What Siphrix v1.0.0 Includes

Siphrix ships one product with four coordinated layers. Every bullet below fits into one of the four:

**Policy decision layer** — *what is the right verdict?*

- canonical policy runtime and execution interception
- analysis modules for trajectories, threat graphs, formal/proof checks, cross-agent reasoning, escalation, simulation, and determinism

**Runtime enforcement / mediation layer** — *turn the verdict into a real outcome*

- runtime mediation, enforcement, hooks, evidence ledgers, sessions, broker flows, and capability binding
- the canonical kernel syscall interception layer as an Siphrix policy/evaluation/enforcement-decision capability
- the supported orchestrator pipeline and interactive demo entrypoint

**Trust / audit / governance support layer** — *make every decision defensible*

- trust, signing, attestation, policy activation, remote policy sync, integrity ledgers, and trust rechecks
- governance, evidence export, explainability, compliance mapping, replay, and retention workflows
- resilience controls including tenant isolation, distributed control concepts, temporal policy evaluation, healing, and adaptive guardrails

**Operator readiness surface** — *is this install actually ready?*

- engine-level summaries, manifests, stack declarations, and the canonical global smoke runner
- `siphrix doctor`, `siphrix doctor --json`, and the `siphrix demo` golden path

No feature has been removed from v1.0.0; the grouping above is a reading aid, not a surface change.

## What Siphrix v1.0.0 Does Not Include

Siphrix v1.0.0 does not include:

- a shipped native kernel driver
- automatic installation of seccomp, eBPF, WFP, EndpointSecurity, or similar OS hooks on your machine
- a hosted SaaS control plane
- full deployment automation for distributed production environments
- hardware-rooted attestation or TPM-backed key management

The kernel syscall interception layer in v1.0 is a canonical model-level and
policy-level interception capability inside Siphrix. It produces normalized
interception plans, decisions, and evidence payloads. It is not a real OS
kernel hook or production kernel driver in this repository.

## Official Public API

The stable, product-facing surface is exposed from the top-level
``siphrix`` package. Nine names are guaranteed; everything else lives
under an explicit subpackage path and is considered a secondary surface.

```python
from siphrix import (
    # Runtime execution
    run_pipeline,                # main runtime execution entrypoint
    PipelineResult,              # runtime result type

    # Policy evaluation
    PolicyManager,               # policy evaluation entrypoint
    PolicyDecision,              # policy decision result type
    PolicyInput,                 # validated policy input contract
    PolicyInputValidationError,  # raised for invalid policy input

    # Agent / tool-calling integration
    ActionEvaluator,             # one-call adapter over PolicyManager
    ActionEvaluationResponse,    # stable scalar response

    __version__,
)

# Runtime execution
result = run_pipeline("your input")
# result.outcome -> "proceed" | "block" | "ask_confirm" | "clarify"
# result.final_text, result.law_id, result.reason_code

# Policy evaluation
policy_input = PolicyInput.from_dict({"action_name": "http_get"})
decision = PolicyManager().decide(policy_input.to_action_context())
# decision.verdict -> "ALLOW" | "BLOCK" | "ABORT"
# decision.reason, decision.policy_id, decision.matched_rule_id

# Agent integration (composes the two layers above)
response = ActionEvaluator().evaluate({"action_name": "http_get"})
# response.allowed, response.verdict, response.reason, ...
```

These nine names are covered by the public-API contract test in
``tests/test_public_api_surface.py`` and are intended to remain stable
across patch and minor releases. Additional product-facing surfaces
live at dedicated module paths (``siphrix.config``,
``siphrix.audit``, ``siphrix.explanation``, ``siphrix.doctor``,
``siphrix.policy_packs``) and are documented in their own sections
below.

## Canonical Package Surface

Use the canonical package surface.

**Product-facing modules** (the supported entrypoints for integrators):

- `siphrix` — top-level public API (see above)
- `siphrix.policy_runtime` — `PolicyManager`, `PolicyDecision`, `PolicyInput`, `PolicyInputValidationError`
- `siphrix.policy_packs` — shipped packs, `list_policy_packs`, `resolve_policy_pack`, `ShippedPolicyPack`
- `siphrix.agent` — `ActionEvaluator`, `ActionEvaluationResponse`
- `siphrix.config` — `RuntimeConfig`, `load_runtime_config`, `RuntimeConfigError`, `SUPPORTED_PROFILES`
- `siphrix.audit` — `AuditRecord`, `write_audit_record`, audit builders
- `siphrix.explanation` — `DecisionExplanation`, `explain_decision`, `explain_action_evaluation`
- `siphrix.doctor` — `run_doctor`, product-diagnostics checks
- `siphrix.readiness` — `SubsystemHealth`, `SystemHealthReport`, subsystem-health verdicts

**Deeper canonical domains** (stable subpackages with explicit ``__all__``):

- `siphrix.orchestrator` — supported pipeline used by `run_pipeline`
- `siphrix.contracts` — typed boundary contracts
- `siphrix.foundation` — ASPL parsing/typing, policy compilation, audit chains
- `siphrix.trust` — signing, attestation, remote sync, integrity ledgers
- `siphrix.runtime` — mediation, broker flows, sessions, capabilities, enforcement
- `siphrix.governance` — governance records, evidence, compliance, replay, retention
- `siphrix.policy_versioning` — policy lifecycle, versioning, overlays, explanation
- `siphrix.analysis` — trajectory, threat-graph, formal, cross-agent, zero-trust replay
- `siphrix.resilience` — tenant isolation, temporal policy, healing, guardrails
- `siphrix.risk` — scoring, factor engine, thresholds, orchestration
- `siphrix.simulation` — non-executing policy modeling
- `siphrix.integration_flow` — context / planner / executor adapter orchestration
- `siphrix.adapters` — pluggable context / executor / framework / planner adapters
- `siphrix.console` — operator workspaces, projections, commands
- `siphrix.engine` — manifests, stack declarations, cross-layer runner surface

Every canonical package publishes an explicit ``__all__``. The
``siphrix.governance`` and ``siphrix.policy_versioning`` public
surfaces are fully enumerated (no wildcard re-exports).

## Practical Integration Layer

Siphrix is LLM-agnostic and framework-agnostic. The top-level
`ActionEvaluator` is the recommended integration surface for most users;
everything below is additive.

**Start here — adoption entry points:**

- [docs/integration/QUICKSTART.md](docs/integration/QUICKSTART.md)
  Five-minute path from `pip install` to the first allow/block decision,
  with a vendor-neutral provider mapping and the integration taxonomy.
- [docs/integration/ADVANCED.md](docs/integration/ADVANCED.md)
  Next step after the quickstart — reference agents, the integration
  flow orchestrator, the provider-swap map (OpenAI / Anthropic / Gemini
  / Ollama / local / mock), and the local dev control panel.
- [docs/integration/README.md](docs/integration/README.md)
  Index over the full integration documentation set.
- [examples/basic_agent/](examples/basic_agent/)
  The minimum viable integration: one hardcoded action, one evaluation,
  allow/block.
- [examples/tool_calling/](examples/tool_calling/)
  A fake LLM producing a structured intent dict; `fake_llm_plan` swaps
  1:1 for OpenAI tool-calling, Anthropic tool use, Gemini function
  calling, or any local model.
- [examples/universal_pattern/](examples/universal_pattern/)
  The canonical `intent -> evaluation -> execution` pipeline as a
  drop-in `process(prompt)` function — the shape every integration
  converges on.

None of the three canonical examples above import a provider SDK.

**Additional demos and local tooling** (still adoption-grade, but
opinionated about their dependencies or purpose):

- `examples/official_demo.py`
  **Official golden-path demo.** Provider-neutral, no third-party SDK,
  no network. Three curated flows (block, allow, audit/readiness) in
  a single script. Start here.
- `examples/app.py`
  Interactive orchestrator loop — type a message, see the verdict.
- `examples/example_agent.py`
  Uses the mock planner adapter and safe stub execution; supports
  `--list-scenarios` and the four curated scenarios in
  `examples/demo_scenarios.py`.
- `examples/example_agent_openai.py`
  **Optional, provider-specific.** Requires `pip install openai` and
  a valid `OPENAI_API_KEY`. Not on the golden path — Siphrix's
  value is visible without it.
- `siphrix/policy_packs/` (shipped as package data)
  Deployment-oriented policy profiles and role overlays (`admin`, `finance`,
  `support`, `developer`).
- `siphrix.integrations.audit`
  Writes local JSON Lines audit records.
- `tools/integration_control_panel.py`
  Local/dev control-panel UI for poking at planner, policy, and audit
  output during development. Not a production surface.

This layer is intentionally provider-agnostic. OpenAI is one planner adapter,
not a requirement of Siphrix core.

## Install

### From source (development)

```powershell
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"
```

### From built wheel

```powershell
python -m build
python -m pip install dist/siphrix-1.0.0-py3-none-any.whl
```

### Runtime environment variables

By default Siphrix writes runtime logs, state, caches, and the memory
store to `~/.siphrix/`. Override with:

- `SIPHRIX_HOME` — base directory for all runtime state (default: `~/.siphrix`)
- `SIPHRIX_LOG_PATH` — absolute path for the `events.jsonl` audit log
- `SIPHRIX_STATE_PATH` — absolute path for `state.json`
- `SIPHRIX_REMOTE_POLICY_CACHE` — absolute path for the canonical remote-policy cache
- `SIPHRIX_ARTIFACTS_DIR` — absolute path for engine runner profile artefacts

The canonical memory store path is
`$SIPHRIX_HOME/memory/memory_store.json` (default:
`~/.siphrix/memory/memory_store.json`). It is created automatically on
first use by `siphrix.memory.api.add_memory` /
`siphrix.memory.api.search_memory`; callers may still pass an explicit
`store_path=` to target a different file.

Nothing is written to the installed package tree or the repository working tree
under default behaviour.

### Trust posture

Siphrix's trust-seal layer (`siphrix.trust.trust_seal`) signs the
in-process integrity chain with HMAC-SHA256. Two explicit postures are
supported:

- **`development`** *(default, alias: `reference`)* — reachable via the
  built-in development secret; preserves backward-compatible behaviour
  for local smoke tests and demo runners. Not for production. The
  development posture is clearly surfaced by `siphrix doctor`.
- **`hardened`** *(alias: `production`)* — requires a real secret via
  `$SIPHRIX_TRUST_SEAL_SECRET` (≥ 32 UTF-8 bytes) or an explicit
  caller argument. Fails closed with a stable
  `trust_seal_secret_missing` / `trust_seal_secret_too_short` error
  when the secret is unavailable or too short.

Environment variables:

- `SIPHRIX_TRUST_MODE` — `development` (default) or `hardened`
- `SIPHRIX_TRUST_SEAL_SECRET` — required in hardened mode

The reference remote-policy server in
`siphrix.trust.remote_policy_server` is a **development / reference
surface only** — no authentication, no access control. Production
deployments must terminate TLS and authenticate at a reverse proxy.

## Quickstart

After ``pip install siphrix`` (or ``pip install -e ".[dev]"`` from a
check-out), the ``siphrix`` command is on your ``PATH``. Verify the
installation, run the official product demo, and evaluate one action:

```powershell
# 1. Verify the install
siphrix version
siphrix doctor

# 2. The golden path — the official three-flow product demo
siphrix demo                       # from any install, or:
python examples/official_demo.py     # from a repository check-out

# 3. List the shipped policy packs
siphrix packs

# 4. Evaluate an action with the JSON context contract
'{ "action_name": "http_get", "resource.domain": "example.com" }' | Out-File -Encoding utf8 ctx.json
siphrix policy-check --context ./ctx.json

# 5. Run the runtime pipeline on a single input
siphrix run --input "hello"

# 6. Launch the local operator dashboard (repo check-out only)
python tools/siphrix_dashboard/dev_server.py
# then open http://127.0.0.1:8765/
```

For the guided 5-minute tour that wires steps 1 → 2 → 6 → the
release gate together, see
[docs/ui/SHOWCASE.md](docs/ui/SHOWCASE.md).

### Local AI Firewall flow (copy-paste)

A condensed eight-command path through the local AI Firewall —
local-only, no network, no real secrets, no production claim.
`python -m siphrix` is the robust form of the console script
and works without `PATH` adjustments.

```bash
python -m pip install -e ".[dev]"

python -m siphrix doctor --json
python -m siphrix quickstart
python -m siphrix demo --json
python -m siphrix evaluate --context examples/actions/file_delete.json --json

# capture an audit record, then summarize it
python -m siphrix --audit-file ./siphrix-audit.jsonl \
  evaluate --context examples/actions/file_delete.json --json
python -m siphrix audit-summary --file ./siphrix-audit.jsonl

# operator dashboard, loopback bind only
python tools/siphrix_dashboard/dev_server.py
```

`examples/actions/file_delete.json` is a synthetic action context
(no real secrets, no real personal data, no destructive absolute
path). Under the shipped policy it produces a deterministic
`BLOCK` verdict with reason `policy_empty_allowlist`.

Under a default development install `siphrix doctor`'s
`launch_readiness.production_ready` is `false` with blocker
`trust_posture:not_production_ready`. This is expected locally.
Production-grade trust posture is a deployment decision; opt in by
setting `SIPHRIX_TRUST_MODE=hardened` and
`SIPHRIX_TRUST_SEAL_SECRET` before running `doctor`.

For the same flow with longer narration and per-step expected
output, see [docs/launch/QUICK_EVAL.md](docs/launch/QUICK_EVAL.md)
→ **Local AI Firewall flow**. For wheel-install / outside-repo
smoke notes, the minimal `evaluate --context` schema, and a
Windows PowerShell UTF-8 (no BOM) writing pattern, see the same
file → **Wheel install, end-user context, and Windows notes**.

[`siphrix demo`](siphrix/cli/demo.py) is the official product
demo: a single provider-neutral walkthrough with three tightly curated
flows — a blocked destructive action, an allowed safe action under the
shipped `safe_defaults` pack, and an auditable recap that prints every
decision_id together with the `siphrix doctor` launch-readiness
posture. The repo-level [`examples/official_demo.py`](examples/official_demo.py)
is a thin wrapper over the same code path, so both invocation styles
produce byte-identical output.

### What ships vs. what's repo-only

| Surface | Ships with `pip install siphrix`? | Notes |
| --- | --- | --- |
| `siphrix` Python package (public API) | **Yes** | Top-level `__all__` is the stable surface contract |
| `siphrix` console script | **Yes** | Entry point `siphrix.cli.app:main` |
| `siphrix demo` | **Yes** | Installable golden-path demo |
| Shipped policy packs + role overlays (`safe_defaults`, `enterprise_defaults`, `dev_agent_defaults`; `admin`, `developer`, `finance`, `support`) | **Yes** | Package data under `siphrix/policy_packs/` |
| Canon laws + baseline policy YAMLs | **Yes** | Package data under `siphrix/canon/`, `siphrix/policies/` |
| `examples/basic_agent`, `tool_calling`, `universal_pattern`, `official_demo.py` | **No, repo-only** | Read them from the repo; the demo itself is installable as `siphrix demo` |
| `examples/example_agent_openai.py` | **No, repo-only** | Optional + provider-specific; requires `pip install openai` and `OPENAI_API_KEY` |
| `tests/`, `tools/`, `scripts/`, `docs/` | **No, repo-only** | Available in the sdist for auditability but not exposed at runtime |

The same operations from Python, in four lines:

```python
from siphrix import ActionEvaluator

response = ActionEvaluator().evaluate({"action_name": "http_get"})
print(response.allowed, response.verdict, response.reason)
```

For deeper detail on each surface, see the sections below:
[Shipped policy packs](#shipped-policy-packs),
[Configuration](#configuration),
[Product Contracts](#product-contracts),
[Python integration (agent / tool-calling)](#python-integration-agent--tool-calling),
[Diagnostics (doctor)](#diagnostics-doctor),
[Decision explanation](#decision-explanation),
[Audit](#audit),
[Command-line interface](#command-line-interface).

## Shipped policy packs

Siphrix ships three canonical policy packs as package data. A policy
pack is a tool-level behavioural preset (pack-schema YAML) consumed by
pack-based integration flows; it is **not** an engine policy file.

### Canonical packs

| Pack | Description |
| --- | --- |
| ``safe_defaults`` | Conservative defaults for general AI assistants. |
| ``enterprise_defaults`` | Enterprise-oriented defaults with controlled internal execution. |
| ``dev_agent_defaults`` | Developer-oriented defaults for local testing and controlled experimentation. |

Role overlays ``admin`` / ``finance`` / ``support`` / ``developer`` are
also shipped and can be merged on top of a base pack via
``siphrix.policy_packs.resolver.resolve_policy(name, role)``.

### Discovery

From the command line:

```powershell
siphrix packs
# safe_defaults: Conservative defaults for general AI assistants.
# enterprise_defaults: Enterprise-oriented defaults with controlled internal execution.
# dev_agent_defaults: Developer-oriented defaults for local testing and controlled experimentation.
```

From Python:

```python
from siphrix.policy_packs import (
    SUPPORTED_BASE_POLICIES,
    list_policy_packs,
    resolve_policy_pack,
    ShippedPolicyPack,
    PolicyPackError,
)

for pack in list_policy_packs():
    print(pack.name, "->", pack.path)

try:
    pack: ShippedPolicyPack = resolve_policy_pack("safe_defaults")
except PolicyPackError as exc:
    ...
```

### Precedence: explicit policy file, runtime profile, shipped pack

Three distinct concepts. They are complementary, not competing. Ranked
by effect on the engine, highest first:

| # | Mechanism | Effect on the engine |
| --- | --- | --- |
| 1 | **Explicit policy file** — ``--policy-file PATH`` / ``RuntimeConfig.policy_file`` / ``SIPHRIX_POLICY_FILE`` | Loaded directly by ``PolicyManager`` as the active engine YAML. Always wins. |
| 2 | **Runtime profile** — ``--profile NAME`` / ``RuntimeConfig.profile`` | Product operating mode. Writes engine env vars where a direct mapping exists (today: ``safe_defaults`` sets ``SIPHRIX_NO_SIDE_EFFECTS=1``). Does **not** load a shipped pack into the engine. |
| 3 | **Shipped policy pack** — ``siphrix packs`` / ``resolve_policy_pack(name)`` | **No direct engine effect.** Packs are discoverable behavioural presets for pack-based integration flows (for example the example agent at ``examples/example_agent.py``). The engine consumes a different YAML schema. |

Three profile names (``safe_defaults``, ``enterprise_defaults``,
``dev_agent_defaults``) intentionally match shipped pack names, but the
two concepts are kept distinct: profile = product operating mode; pack
= shipped YAML asset. If a pack's rules should also govern engine
behaviour, translate the pack to the engine schema and supply it via
``--policy-file``; there is no silent auto-wiring.

### Pack-to-engine bridge

A shipped pack and an engine policy file use two different schemas.
The pack-to-engine bridge is an **explicit** translation step you run
by hand; it never auto-wires a pack into the engine.

From the command line:

```powershell
siphrix pack-export --name safe_defaults --output ./policy.yaml
# wrote engine policy for pack 'safe_defaults' to ./policy.yaml

siphrix --policy-file ./policy.yaml policy-check --context ./ctx.json
```

From Python:

```python
from siphrix.policy_packs import translate_policy_pack, export_policy_pack

data = translate_policy_pack("safe_defaults")     # -> engine-policy dict
export_policy_pack("safe_defaults", "./policy.yaml")
```

The generated YAML begins with a header comment listing what was
preserved and what was dropped. The translation subset is small and
honest:

| Pack concept | Translated? |
| --- | --- |
| ``mode: fail_closed`` | yes → engine ``default_action: BLOCK`` |
| ``tools.<name>: bool`` | yes → one engine rule per declared tool (``file_read`` / ``file_write`` / ``file_delete`` / ``email_send`` / ``shell_exec`` / ``network_access``). ``network_access`` maps to ``when: {category: network}``; the others to ``when: {action_name: <tool>}``. |
| ``llm.*`` | **no** — LLM orchestration; not engine-enforceable |
| ``files.*`` | **no** — engine ``when`` clauses do not support path-prefix matching |
| ``email.allow_external_recipients`` / ``allowed_domains`` | **no** — beyond the tool boolean |
| ``network.allowed_hosts`` | **no** — beyond the tool boolean |
| ``shell.allowed_commands`` / ``blocked_patterns`` | **no** — command substring matching unsupported |
| ``decision_defaults.*`` | **no** — engine has a single ``default_action`` |

If you need the unsupported semantics, edit the produced YAML by
hand. The bridge will not silently invent behaviour the engine
cannot enforce.

## Configuration

Siphrix is configured through a small, disciplined layer that sits in
front of the existing engine environment contract. Three inputs are
supported, in priority order:

1. **Explicit CLI flags** — ``--profile NAME``, ``--policy-file PATH``.
2. **TOML config file** — ``--config PATH`` with an ``[siphrix]`` table.
3. **Built-in defaults** — profile ``"default"``, no policy file.

### Config file shape

```toml
[siphrix]
profile      = "safe_defaults"
policy_file  = "/etc/siphrix/policy.yaml"
```

Both keys are optional. Unknown keys are rejected. Invalid values raise
a concise, traceback-free error and cause the CLI to exit with code
``3``.

### Supported profiles

Exactly four names, matching the shipped policy-pack layer where
applicable:

| Profile | Behavior |
| --- | --- |
| ``default`` | Zero-config baseline. No environment variables are written by the profile. |
| ``safe_defaults`` | Conservative / fail-closed. Sets ``SIPHRIX_NO_SIDE_EFFECTS=1`` so every action with ``effect_type = "SIDE_EFFECT"`` is blocked by the engine's side-effect layer. |
| ``enterprise_defaults`` | Neutral profile for enterprise deployments. Expect a ``policy_file`` to be supplied alongside. |
| ``dev_agent_defaults`` | Most permissive shipped profile; for local development. |

``safe_defaults``, ``enterprise_defaults`` and ``dev_agent_defaults``
are the canonical names also used by
``siphrix.policy_packs.SUPPORTED_BASE_POLICIES`` and by
``examples/example_agent.py``.

### CLI examples

```powershell
# Run with a named profile
siphrix --profile safe_defaults run --input "hello"

# Point at an explicit policy file
siphrix --policy-file ./policy.yaml policy-check --context ./ctx.json

# Load everything from a TOML config
siphrix --config ./siphrix.toml run --input "hello"
```

CLI flags always override config-file values. Configuration does not
introduce new environment variables — ``RuntimeConfig.apply()`` only
writes to the existing ``SIPHRIX_POLICY_FILE`` and
``SIPHRIX_NO_SIDE_EFFECTS`` names that the engine already reads.

## Product Contracts

The product surface is defined by three stable contracts. Behaviour of
the underlying engine is unchanged; these contracts are the validated
boundary callers integrate against.

### Runtime result — ``PipelineResult``

``run_pipeline(text)`` returns a ``PipelineResult`` with the following
fields:

| Field | Type | Allowed values |
| --- | --- | --- |
| ``outcome`` | str | ``"proceed"``, ``"block"``, ``"ask_confirm"``, ``"clarify"`` |
| ``final_text`` | str | generated text when ``outcome == "proceed"``; otherwise empty |
| ``law_id`` | Optional[str] | canonical law identifier when the outcome was driven by Canon |
| ``reason_code`` | Optional[str] | stable reason code when the outcome was driven by Canon |

### Policy decision — ``PolicyDecision``

``PolicyManager().decide(...)`` returns a ``PolicyDecision`` with the
following fields:

| Field | Type | Allowed values |
| --- | --- | --- |
| ``decision_id`` | str | per-evaluation UUID |
| ``verdict`` | str | ``"ALLOW"``, ``"BLOCK"``, ``"ABORT"`` |
| ``reason`` | str | stable reason code |
| ``policy_id`` | str | identifier of the policy that produced the decision |
| ``matched_rule_id`` | Optional[str] | id of the rule that matched, if any |
| ``decision_graph`` | Optional[list] | per-layer evaluation trace (present when emitted by the engine) |
| ``explain`` | Optional[dict] | structured explanation (present when emitted by the engine) |

### Policy input — ``PolicyInput``

``PolicyInput`` is the validated input contract for
``PolicyManager().decide(...)`` and for ``siphrix policy-check``. The
JSON shape is:

```json
{
  "action_name": "http_get",

  "resource": "https://example.com/api/data",
  "resource.scheme": "https",
  "resource.domain": "example.com",
  "resource.path": "/api/data",
  "resource.raw": "https://example.com/api/data",

  "origin": "user",
  "category": "network",
  "effect_type": "READ_ONLY",
  "risk_level": "LOW",
  "trust_boundary": "api.external",
  "intent": "NORMAL",
  "agent_id": "agent.local",
  "tool_id": "tool.http",
  "source": "user",

  "params": { "timeout": 10 }
}
```

Only ``action_name`` is required and must be a non-empty string. All
other fields are optional. Enum fields are closed:

- ``effect_type`` ∈ ``{"READ_ONLY", "SIDE_EFFECT"}``
- ``risk_level`` ∈ ``{"LOW", "MEDIUM", "HIGH", "CRITICAL"}``
- ``intent`` ∈ ``{"NORMAL", "SENSITIVE"}``

``params`` must be a JSON object. Unknown top-level keys are rejected.
Invalid input raises ``PolicyInputValidationError`` from Python and
causes ``siphrix policy-check`` to exit with code ``3`` and a
concise, traceback-free error.

Minimal valid input:

```json
{ "action_name": "file_read" }
```

## Python integration (agent / tool-calling)

The official v1 integration surface for AI agents and tool-calling
runtimes is :class:`siphrix.ActionEvaluator`. It composes the existing
product contracts — :class:`PolicyInput`, :class:`PolicyManager`,
:class:`PolicyDecision` — into one small callable.

```python
from siphrix import ActionEvaluator

evaluator = ActionEvaluator()

response = evaluator.evaluate({
    "action_name": "http_get",
    "resource.domain": "example.com",
    "effect_type": "READ_ONLY",
    "risk_level": "LOW",
})

if response.allowed:
    perform_action()
else:
    handle_block(response.reason, response.verdict, response.decision_id)
```

``evaluate()`` accepts either a raw mapping — validated through
``PolicyInput.from_dict`` — or a pre-built :class:`PolicyInput`.
Invalid input raises :class:`PolicyInputValidationError`.

### ``ActionEvaluationResponse``

Stable scalar projection of :class:`PolicyDecision`. The unstable
``decision_graph`` and ``explain`` are intentionally not exposed; call
``PolicyManager().decide(...)`` directly if you need them.

| Field | Type | Notes |
| --- | --- | --- |
| ``allowed`` | bool | ``True`` iff ``verdict == "ALLOW"`` |
| ``verdict`` | str | ``"ALLOW"`` / ``"BLOCK"`` / ``"ABORT"`` |
| ``reason`` | str | stable reason code |
| ``decision_id`` | str | per-evaluation UUID |
| ``policy_id`` | str | identifier of the policy that produced the decision |
| ``matched_rule_id`` | Optional[str] | id of the rule that matched, if any |

### Optional audit hook

Pass an ``audit_file=Path(...)`` to emit one compact JSONL record per
evaluation, using the same shape the CLI writes:

```python
evaluator = ActionEvaluator(audit_file="agent-audit.jsonl", audit_profile="safe_defaults")
```

Audit writes inside the adapter are non-fatal — if the file cannot be
written, the evaluation still returns its response. Callers that
require fail-closed audit behaviour should write records themselves
via ``siphrix.audit.write_audit_record``.

## Integration pattern (LLM-agnostic)

Siphrix is provider-independent. It has no SDK dependency on
OpenAI, Anthropic, Gemini, or any other model — it never calls an
LLM. What you hand to ``ActionEvaluator.evaluate`` is a plain Python
dict that conforms to the :class:`PolicyInput` contract. Any
producer of such a dict — tool-calling, function-calling, rule
engines, hand-written planners — integrates the same way.

The canonical shape is three clearly separated stages:

```
intent  ->  evaluation  ->  execution
```

- **intent** — your LLM / planner / rule engine yields a structured
  action dict.
- **evaluation** — one call to
  ``ActionEvaluator.evaluate(intent) -> ActionEvaluationResponse``.
  Siphrix touches your code only here.
- **execution** — the side-effect runs only when
  ``response.allowed`` is true.

Runnable, vendor-neutral examples live under [examples/](examples/):

- [examples/basic_agent/](examples/basic_agent/) — the minimum
  viable integration: one hardcoded action, one evaluation,
  allow/block.
- [examples/tool_calling/](examples/tool_calling/) — a fake LLM
  that returns a structured intent dict; trivially swappable for a
  real model.
- [examples/universal_pattern/](examples/universal_pattern/) — the
  canonical ``intent -> evaluation -> execution`` pipeline as a
  drop-in ``process(prompt)`` function.

None of the examples import a provider SDK. Replace the intent
producer with your own model integration and Siphrix stays
unchanged in the middle.

## Diagnostics (doctor)

``siphrix doctor`` runs a small set of product-facing checks and
prints a compact report. It reuses the canonical health dataclasses
from :mod:`siphrix.readiness`, so every check result conforms to the
same :class:`SubsystemHealth` / :class:`SystemHealthReport` shape used
elsewhere in the codebase.

### Checks (canonical order)

| Check | Purpose |
| --- | --- |
| ``core_package`` | Top-level public API imports cleanly (``run_pipeline``, ``PolicyManager``, ``ActionEvaluator``, ``PolicyInput``, ``__version__``). |
| ``shipped_policy_packs`` | Every entry in ``SUPPORTED_BASE_POLICIES`` resolves and its YAML file exists on disk. |
| ``config_file`` | The TOML at ``--config PATH`` loads via ``load_runtime_config``. ``SKIPPED`` if no ``--config``. |
| ``policy_file`` | The file at ``--policy-file PATH`` exists on disk. ``SKIPPED`` if no ``--policy-file``. |

### Exit codes

| Verdict | Exit | Meaning |
| --- | --- | --- |
| ``READY`` | ``0`` | All applicable checks healthy. |
| ``DEGRADED`` | ``0`` | Some checks degraded but none unhealthy — usable. |
| ``NOT_READY`` | ``1`` | At least one check is unhealthy — the installation or the supplied input is broken. |

### CLI example

```powershell
siphrix doctor
# siphrix doctor: READY: 2/4 healthy
#   [HEALTHY] core_package: Siphrix core package importable.
#   [HEALTHY] shipped_policy_packs: All 3 shipped policy packs present on disk.
#   [SKIPPED] config_file: No --config provided.
#   [SKIPPED] policy_file: No --policy-file provided.

siphrix --config ./siphrix.toml --policy-file ./policy.yaml doctor
```

The summary counts HEALTHY checks against the total number of checks;
SKIPPED checks are counted in the denominator but not the numerator.
``2/4 healthy`` with the other two SKIPPED is the steady-state when no
optional inputs are supplied.

When ``--config`` or ``--policy-file`` points at something broken the
doctor reports it as a structured check (not a pre-dispatch error):

```powershell
siphrix --policy-file /does/not/exist.yaml doctor
# siphrix doctor: NOT_READY: 2/4 healthy, 1 unhealthy
#   [HEALTHY]   core_package: Siphrix core package importable.
#   [HEALTHY]   shipped_policy_packs: All 3 shipped policy packs present on disk.
#   [SKIPPED]   config_file: No --config provided.
#   [UNHEALTHY] policy_file: Policy file not found: /does/not/exist.yaml
# (exit code: 1)
```

### Python example

```python
from siphrix.doctor import run_doctor

report = run_doctor()
print(report.summary)
for check in report.subsystems:
    print(check.subsystem_id, check.status, check.message)
```

## Decision explanation

For logs, tests, and user-facing messaging, Siphrix provides a
compact, stable projection of a policy decision. It lives under
:mod:`siphrix.explanation`.

```python
from siphrix import ActionEvaluator
from siphrix.explanation import explain_action_evaluation

response = ActionEvaluator().evaluate({
    "action_name": "http_get",
    "resource.domain": "example.com",
})
explanation = explain_action_evaluation(response)

print(explanation.summary)
# BLOCK (policy_empty_allowlist) — policy=policy_v0 rule=-

print(explanation.to_dict())
# {"allowed": False, "verdict": "BLOCK", "reason": "policy_empty_allowlist",
#  "policy_id": "policy_v0", "matched_rule_id": None,
#  "decision_id": "...", "summary": "BLOCK (policy_empty_allowlist) — ..."}
```

Callers holding a raw :class:`PolicyDecision` use :func:`explain_decision`
instead; both factories produce identical :class:`DecisionExplanation`
objects for the same underlying decision.

### Contract

| Field | Type | Source |
| --- | --- | --- |
| ``allowed`` | bool | ``True`` iff ``verdict == "ALLOW"`` |
| ``verdict`` | str | ``"ALLOW"`` / ``"BLOCK"`` / ``"ABORT"`` |
| ``reason`` | str | stable reason code |
| ``policy_id`` | str | identifier of the policy that produced the decision |
| ``matched_rule_id`` | Optional[str] | id of the rule that matched, if any |
| ``decision_id`` | str | per-evaluation UUID |
| ``summary`` | str | ``"{verdict} ({reason}) — policy={policy_id} rule={matched_rule_id or '-'}"`` |

The engine's internal ``decision_graph`` and ``explain`` payloads are
**not** part of this surface — they vary by engine code path and are
not considered stable product API. Callers that need them should
continue to use ``PolicyManager().decide(...)`` and read
``PolicyDecision.decision_graph`` / ``PolicyDecision.explain``
directly.

## Audit

``siphrix run`` and ``siphrix policy-check`` can emit one compact
audit record per invocation. Audit is **opt-in**: without
``--audit-file PATH``, nothing is written.

```powershell
siphrix --audit-file ./siphrix-audit.jsonl run --input "hello"
```

### Output format

One JSON line per event, using the same envelope the rest of the
codebase writes through ``siphrix.logs.logger.log_event``:

```json
{"ts":"2026-04-19T12:34:56.789+00:00","event_type":"runtime_run","payload":{"profile":"default","status":"ok","input_summary":{"input_length":5,"input_preview":"hello"},"result_summary":{"outcome":"block","law_id":"CANON-022","reason_code":"COHERENCE_NO_DECISION","final_text_length":0},"outcome_id":null,"error_message":null}}
```

### Record shape

Payload fields (stable):

| Field | Type | Notes |
| --- | --- | --- |
| ``profile`` | str | ``"default"`` / ``"safe_defaults"`` / ``"enterprise_defaults"`` / ``"dev_agent_defaults"`` |
| ``status`` | str | ``"ok"`` / ``"failed"`` / ``"invalid_input"`` |
| ``input_summary`` | object | Compact; see below |
| ``result_summary`` | object | Compact; see below |
| ``outcome_id`` | string or null | ``decision.decision_id`` for ``policy_check``; ``null`` for ``runtime_run`` |
| ``error_message`` | string or null | Present only when ``status != "ok"`` |

Envelope fields: ``ts`` (ISO-8601 UTC), ``event_type`` (``"runtime_run"`` or ``"policy_check"``).

``input_summary`` for ``runtime_run``: ``{"input_length": int, "input_preview": str}`` — the preview is truncated to 128 characters.

``input_summary`` for ``policy_check``: a subset of ``action_name``,
``resource.domain``, ``origin``, ``category``, ``effect_type``,
``risk_level``, ``trust_boundary``, ``intent`` — keys are present only
when the corresponding field was supplied. ``params``,
``resource`` (single-string form), ``resource.path``, ``resource.raw``,
``resource.scheme``, ``agent_id``, ``tool_id`` and ``source`` are **not**
emitted, because they can carry secrets, IDs, or high-cardinality
values that do not belong in a compact audit record.

``result_summary`` for ``runtime_run``:
``{"outcome", "law_id", "reason_code", "final_text_length"}``. The
runtime text itself is not included.

``result_summary`` for ``policy_check``:
``{"verdict", "reason", "policy_id", "matched_rule_id"}``.

### Behavior on audit write failure

Audit writing is **non-fatal by design**. If the audit file cannot be
opened or appended to (permission denied, disk full, bad parent
directory), the CLI prints a single warning line to stderr —

```
siphrix: audit write failed: <reason>
```

— and the primary operation's exit code is unchanged. Operators who
require fail-closed audit behaviour should wrap the CLI in a
supervisor that inspects this stderr line.

### Inspecting an audit file

Two read-side subcommands consume the JSONL shape above.

``siphrix audit-tail`` prints the most recent N records (default
10) as compact one-line summaries:

```powershell
siphrix audit-tail --file ./siphrix-audit.jsonl --tail 3
# 2026-04-19T20:29:44.134957+00:00  policy_check   ok             verdict=BLOCK reason=policy_empty_allowlist
# 2026-04-19T20:29:44.135151+00:00  policy_check   ok             verdict=BLOCK reason=policy_empty_allowlist
# 2026-04-19T20:29:44.135320+00:00  policy_check   invalid_input  error=action_name missing
```

Each line shows the timestamp, ``event_type``, ``status``, and a
single compact result indicator that depends on the event:

- ``runtime_run`` + ``status=ok`` → ``outcome=<value>``
- ``policy_check`` + ``status=ok`` → ``verdict=<value> reason=<value>``
- any non-``ok`` status → ``error=<error_message>``

``siphrix audit-summary`` walks the whole file once and prints
deterministic counts:

```powershell
siphrix audit-summary --file ./siphrix-audit.jsonl
# audit summary for ./siphrix-audit.jsonl
#   total records:      6
#   malformed lines:    0
#
#   by event_type:
#     policy_check:  3
#     runtime_run:   3
#   by status:
#     ok:             5
#     invalid_input:  1
#   top verdicts (policy_check):
#     BLOCK:  2
#   top reasons:
#     policy_empty_allowlist:  2
```

Counts are sorted by count descending, ties broken by key ascending —
identical runs produce byte-identical output.

**Malformed-line behavior.** Lines that are not valid JSON, are not
a JSON object, or are missing the ``ts`` / ``event_type`` / ``payload``
envelope keys are **counted and skipped**, not fatal. ``audit-summary``
reports the count in its ``malformed lines`` field; ``audit-tail``
surfaces a non-zero count on stderr as:

```
siphrix audit-tail: skipped N malformed line(s)
```

Blank lines are ignored and do not count as malformed. Only a
missing or unreadable file causes the commands to exit with code
``3``.

## Command-line interface

Installing the package registers a single console script, ``siphrix``,
with eight subcommands:

| Subcommand | Purpose |
| --- | --- |
| ``version`` | Print the installed Siphrix version. |
| ``run`` | Execute the runtime pipeline on a single input. |
| ``policy-check`` | Evaluate a JSON action context against the policy runtime. |
| ``packs`` | List the shipped policy packs with descriptions. |
| ``pack-export`` | Translate a shipped pack into an engine policy YAML file. |
| ``doctor`` | Run product-facing diagnostic checks and print a compact report. |
| ``audit-tail`` | Show the most recent audit records from a JSONL audit file. |
| ``audit-summary`` | Summarize a JSONL audit file (counts by event_type, status, verdict, reason). |

Top-level flags (apply to every subcommand): ``--config PATH``,
``--profile NAME``, ``--policy-file PATH``, ``--audit-file PATH``.

```powershell
siphrix version
# 1.0.0

siphrix run --input "read the quarterly report"
# outcome: proceed
# law_id: -
# reason_code: -
# final_text: [local-llm] received: read the quarterly report

siphrix policy-check --context ./ctx.json
# verdict: BLOCK
# decision_id: 8f2e...-...
# reason: policy_empty_allowlist
# policy_id: policy_v0
# matched_rule_id: -

siphrix packs
# safe_defaults: Conservative defaults for general AI assistants.
# enterprise_defaults: Enterprise-oriented defaults with controlled internal execution.
# dev_agent_defaults: Developer-oriented defaults for local testing and controlled experimentation.

siphrix doctor
# siphrix doctor: READY: 2/4 healthy
#   [HEALTHY] core_package: Siphrix core package importable.
#   [HEALTHY] shipped_policy_packs: All 3 shipped policy packs present on disk.
#   [SKIPPED] config_file: No --config provided.
#   [SKIPPED] policy_file: No --policy-file provided.
```

``siphrix run`` without ``--input`` prompts once on stdin. The two
"outcome-bearing" subcommands (``run`` and ``policy-check``) report
the policy outcome in their **output**, not in the exit code.

Exit codes:

| Code | Meaning |
| --- | --- |
| ``0`` | Success. For ``run`` / ``policy-check``, the outcome is in the output. For ``doctor``, the verdict is ``READY`` or ``DEGRADED``. |
| ``1`` | Unexpected internal failure during ``run`` / ``policy-check``, or ``doctor`` reported ``NOT_READY``. |
| ``2`` | Argparse usage error. |
| ``3`` | User input error: invalid ``--config`` / ``--profile`` / ``--policy-file``, missing or malformed ``--context`` JSON, or a policy-input shape violation. |

## Developer integration surfaces

Siphrix is local-first: an SDK you import in Python and a CLI you
run on your own machine. There is no hosted SaaS to call, no browser
extension, no kernel driver, no OS-level enforcement, no cloud sync —
those belong to future phases and are not implemented in this
release. Every surface below runs offline, requires no real secrets,
and produces no hidden side effects.

### A. SDK — direct Python integration

The recommended integration surface is ``siphrix.ActionEvaluator``:

```python
from siphrix import ActionEvaluator

evaluator = ActionEvaluator()
result = evaluator.evaluate({
    "action_name": "file_read",
    "effect_type": "READ_ONLY",
    "risk_level": "LOW",
})

if result.allowed:
    ...  # perform the real side-effect here
else:
    ...  # branch on result.verdict / result.reason instead
```

``result`` is an ``ActionEvaluationResponse`` with these stable
fields:

| Field | Meaning |
| --- | --- |
| ``result.allowed`` | Boolean — true only when the engine returns ``ALLOW``. |
| ``result.verdict`` | One of ``ALLOW`` / ``BLOCK`` / ``ABORT``. The native engine alphabet. |
| ``result.reason`` | Stable short reason code. |
| ``result.decision_id`` | UUID for the audit trail. |
| ``result.policy_id`` | Identifier of the policy that produced the decision. |
| ``result.matched_rule_id`` | Rule that matched, or ``None``. |
| ``result.risk_score`` | Optional numeric risk envelope. |
| ``result.risk_band`` | Optional ``low`` / ``medium`` / ``high`` / ``critical`` band. |

Invalid intent dicts raise ``PolicyInputValidationError`` with a
short, stable message — no path leak, no traceback in user-facing
output.

### B. CLI — human-readable

```bash
siphrix demo                                   # official walkthrough
siphrix status                                 # read-only local summary
siphrix policy-check --context ./ctx.json     # evaluate a JSON action context
siphrix evaluate --context ./ctx.json         # friendly alias of policy-check
siphrix run --input "read the report"         # runtime pipeline on one input
siphrix policy-validate --file ./policy.yaml  # validate a policy YAML, do not apply
```

### C. CLI — machine-readable JSON

Every command above carries a ``--json`` flag that emits a stable
payload to stdout with no banners and no stderr noise on success:

```bash
siphrix demo --json
siphrix status --json
siphrix policy-check --context ./ctx.json --json
siphrix evaluate --context ./ctx.json --json
siphrix run --input "read the report" --json
siphrix policy-validate --file ./policy.yaml --json
```

### D. Stable JSON schema names

| Command | Schema identifier |
| --- | --- |
| ``siphrix demo --json`` | ``official_demo_v1`` |
| ``siphrix status --json`` | ``status_result_v1`` |
| ``siphrix policy-check --json`` / ``siphrix evaluate --json`` | ``policy_check_result_v1`` |
| ``siphrix run --json`` | ``pipeline_result_v1`` |
| ``siphrix policy-validate --json`` | ``policy_validate_result_v1`` |

### E. Notes on the integration surfaces

- ``siphrix evaluate`` is a friendly alias of ``siphrix
  policy-check``. They share the same handler, the same exit codes,
  the same text output, and the same JSON schema
  (``policy_check_result_v1``).
- ``siphrix policy-validate`` *validates* a policy YAML file —
  structure and schema only. It does not apply the policy to the
  runtime, does not write audit, does not mutate environment, and
  does not contact the network. Errors map to stable short codes
  (``policy_yaml_invalid``, ``policy_missing_or_invalid_version``,
  ``policy_schema_version_unsupported``, ``policy_rule_invalid_then``,
  ``policy_file_not_found``, …); raw exception text and absolute
  paths never reach the output.
- ``siphrix status`` is strictly read-only: no policy is loaded, no
  audit record is written, no environment variable is mutated.
- ``siphrix run --json`` does not surface raw user input. It emits
  ``input_length`` (an integer character count) instead of the raw
  prompt text.
- All file path slots that a user can configure (``--policy-file``,
  ``--audit-file``, the policy file passed to ``policy-validate``)
  are surfaced in JSON as the scrubbed ``file:<basename>`` form so
  absolute or temp paths cannot leak through the JSON output.

## Run The Demo

Supported interactive demo entrypoint:

```powershell
python examples/app.py
```

Canonical smoke runner (ships in the wheel; requires repo fixtures to run from
a git checkout):

```powershell
python -m siphrix.tests_all_global
```

Practical integration examples:

```powershell
python examples/example_agent.py --list-scenarios
python examples/example_agent.py --scenario blocked_delete
python examples/example_agent.py --scenario review_quarterly_report
python examples/example_agent.py --scenario allow_report_read
python examples/example_agent.py --scenario allow_developer_shell
python examples/example_agent_openai.py --policy safe_defaults --input "read report"
python tools/integration_control_panel.py
```

What is real versus simulated in these examples:

- real
  policy loading, role-aware resolution, planner normalization, Siphrix pipeline calls, policy decisions, and local audit logging
- simulated
  file changes, email sending, shell execution, and other real-world side effects

## Run Tests

```powershell
# Compile check (import-time validation)
python -m compileall -q siphrix

# Repo-level test suite (uses pytest with pythonpath = . examples tools)
python -m pytest -q

# Or via unittest discover (identical coverage)
python -m unittest discover -s tests -q

# Package-internal public-API suite (repo-only; not shipped in the wheel)
python -m unittest discover -s siphrix/tests -t .

# Canonical smoke runner
python -m siphrix.tests_all_global
```

In a normal developer environment, `python -m pytest -q` resolves to the real
external `pytest` package from the dev dependencies. The repository also keeps
a repo-local fallback module under `siphrix/devtools/pytest_fallback/` for
self-contained offline validation; it is internal-only and is excluded from
the distributed wheel.

## Getting Started

For a new developer, the shortest useful path is:

1. Create and activate a virtual environment.
2. Install the package in editable mode with dev extras: `python -m pip install -e ".[dev]"`.
3. Run `python -m pytest -q` to execute the repo-level test suite.
4. Run `python -m unittest discover -s siphrix/tests -t .` for the package-internal public-API suite.
5. Run `python -m siphrix.tests_all_global` for the canonical smoke runner.
6. Run `python examples/example_agent.py --list-scenarios` to see the curated demo set.
7. Run `python examples/example_agent.py --scenario blocked_delete` and `python examples/example_agent.py --scenario allow_report_read`.
8. If you have `OPENAI_API_KEY` and the SDK installed, run `python examples/example_agent_openai.py --policy safe_defaults --input "read report"`.
9. Launch `python tools/integration_control_panel.py` for interactive testing.

## Architecture Map

High-level package map:

- `siphrix.orchestrator`
  The supported top-level pipeline used by `run_pipeline` and the interactive demo.
- `siphrix.foundation`
  ASPL parsing and typing, policy compilation, audit chains, proof bundles, proof-of-execution helpers, and signing primitives.
- `siphrix.contracts`
  Typed boundary contracts for all system interfaces including execution, planner, simulation, risk, and multi-agent surfaces.
- `siphrix.trust`
  Policy signing, activation, policy anchors, remote sync, attestation, trust epochs, heartbeat validation, integrity ledgers, and trust seals.
- `siphrix.runtime`
  Policy evaluation, execution interception, mediation, broker flows, sessions, capabilities, enforcement, evidence ledgers, and kernel syscall interception decisions.
- `siphrix.governance`
  Governance records, decision ledgers, explainability, delegated authority, exceptions, quorum flows, compliance export, replay, and retention workflows. Internally sub-packaged into `audit/`, `compliance/`, `evidence/`, `incident/`.
- `siphrix.policy_versioning`
  Policy lifecycle management, versioning, replay, overlays, activation, distribution, evaluation, and explanation. Internally sub-packaged into 14 semantic domains.
- `siphrix.analysis`
  Trajectory analysis, threat graphs, formal checks, bounded exploration, cross-agent reasoning, escalation, simulation, determinism, and zero-trust style replay helpers.
- `siphrix.resilience`
  Tenant isolation, distributed enforcement concepts, temporal policy/state machinery, health monitoring, healing, adaptive guardrails, and failure containment.
- `siphrix.risk`
  Risk scoring, factor engine, thresholds, orchestration, and execution adapters.
- `siphrix.simulation`
  Simulation engine and audit for non-executing policy evaluation modeling.
- `siphrix.integration_flow`
  Integration flow orchestration connecting context, planner, and executor adapters.
- `siphrix.adapters`
  Pluggable context, executor, framework, and planner adapters with a registration registry.
- `siphrix.console`
  Operator dashboard, workspaces, projections, and operator commands.
- `siphrix.engine`
  Canonical manifests, stack declarations, gap summaries, unified engine summaries, and the supported cross-layer runner surface.

For a short architecture reference, see [docs/architecture/ARCHITECTURE_v1.md](docs/architecture/ARCHITECTURE_v1.md).

## Repository Layout

Installable Python package (ships in the wheel):

- `siphrix/` canonical product code and runtime modules
- `siphrix/policies/*.yaml` canonical policy assets
- `siphrix/policy_packs/*.yaml` + `roles/*.yaml` deployment-oriented policy profiles
- `siphrix/canon/*.yaml` + `canon_v1.md` canon laws and conformance data
- `siphrix/integrations/` canonical integration library (audit, layer_utils, snapshot)
- `siphrix/examples/` compatibility re-export shims (canonical paths are in `siphrix.integrations`)

Repository-only (not installed by the wheel):

- `tests/` repo-level unit and compatibility coverage (shipped in sdist for auditability)
- `tests/fixtures/keys/` committed example/dev crypto fixtures used by local validation
- `tests/fixtures/policies/compat/` compatibility policy fixtures
- `siphrix/tests/` package-internal public-API test suite (repo-only, not shipped)
- `siphrix/research/` internal research notes (repo-only, not shipped)
- `siphrix/devtools/pytest_fallback/` offline pytest fallback (repo-only, not shipped)
- `docs/` release, architecture, and integration documentation (shipped in sdist)
- `examples/` runnable demo agents (repo-only, not packaged)
- `tools/` supported operator scripts (repo-only, not packaged)
- `scripts/` dev scripts (repo-only, not packaged)

Planner adapters live in `siphrix.adapters.planners`. Planner contracts live
in `siphrix.contracts.planner`.

Only example or smoke-safe assets should live in tracked paths. Real private
keys, operator secrets, tenant-specific ledgers, and environment-specific trust
material must not be committed. The `.gitignore` already excludes the standard
runtime output paths (logs, state, caches, `.venv`, `__pycache__`, generated
artefacts).

## Key Hygiene

- committed key-like files in this repo are example/dev fixtures only
- local smoke and tests use example fixtures under `tests/fixtures/keys`
- real signing keys should live outside the repository or in untracked local secret storage
- do not place operator or production private keys in `artifacts/` or any tracked path

## Internal Hardening Model

Siphrix enforces defence-in-depth at several internal boundaries.  Each
limit is small, explicit, and covered by dedicated tests so a future
change cannot silently weaken the guarantee.

- **Canon DSL evaluator** (`siphrix.canon.canon_runtime`): trigger
  conditions in Canon YAML are parsed with ``ast.parse`` in ``mode="eval"``
  and walked through a strict node whitelist before any value is read.
  No Python builtins, function calls, subscripts, comprehensions,
  arithmetic, or attribute calls can reach the evaluator.  Any
  disallowed construct is rejected up front.  See
  [tests/test_canon_runtime_hardening.py](tests/test_canon_runtime_hardening.py).

- **Shell executor** (`siphrix.adapters.executors.shell_executor`): only
  the hostname/whoami allowlist is executable.  Commands are bounded
  in length (512 chars), argument count (16), and wall-clock time
  (10 s subprocess timeout).  Null bytes, newlines, and shell
  metacharacters are rejected before ``shlex.split`` runs.  See
  [tests/test_shell_executor_hardening.py](tests/test_shell_executor_hardening.py).

- **HTTP interception** (`siphrix.exec_intercept.intercept`): the
  ``http_get`` choke point enforces an ``http``/``https`` scheme
  allowlist before any policy or network work runs, and caps response
  bodies at 16 MiB to keep callers memory-bounded.  See
  [tests/test_intercept_http_hardening.py](tests/test_intercept_http_hardening.py).

- **Public API surface**: every canonical package publishes an explicit
  ``__all__``.  ``siphrix.governance`` and
  ``siphrix.policy_versioning`` list every re-exported symbol by name
  instead of using wildcard re-exports.  See
  [tests/test_public_api_surface.py](tests/test_public_api_surface.py).

## Security and contribution

- Vulnerability reports and the detailed threat model live in
  [SECURITY.md](SECURITY.md).
- Development workflow, test commands, and rules for adding canon laws
  or public API symbols live in [CONTRIBUTING.md](CONTRIBUTING.md).
- A cross-platform [Makefile](Makefile) exposes the common developer
  tasks (``make smoke``, ``make test``, ``make coverage``, ``make clean``).

## v2+ Roadmap

Areas intentionally deferred beyond v1.0:

- Linux backend
  Add a concrete Linux enforcement backend for the kernel syscall interception layer, such as a seccomp/eBPF integration, behind the existing canonical decision model.
- hardware attestation
  Extend current trust and attestation flows toward hardware-rooted verification instead of software-only local attestations.
- distributed enforcement
  Move distributed control concepts toward stronger real-node coordination, activation discipline, and enforcement propagation across environments.
- mesh features
  Expand broker, remote policy, and trust flows into more explicit mesh-style coordination and multi-node policy distribution capabilities.

## Development Rules

- extend canonical non-versioned modules
- do not add new `vXX` package paths
- keep backward compatibility unless correctness requires a change
- treat generated logs, caches, ledgers, and smoke outputs as disposable runtime material

## Release Documents

- [docs/release/RELEASE_RUNBOOK.md](docs/release/RELEASE_RUNBOOK.md) — the canonical live release runbook (three-gate model, preflight checklist, one release-gate command, publish + rollback steps).
- `.github/workflows/release-gate.yml` — CI release gate (runs tools/release_check.py)

## UI / Dashboard

The local operator dashboard is implemented and framework-free. It
ships as [`tools/siphrix_dashboard/`](tools/siphrix_dashboard/)
in the repository (it is not part of the installable wheel) and is
served by a stdlib-only dev server on `127.0.0.1:8765`. No npm, no
bundler, no external frontend dependencies.

```powershell
python tools/siphrix_dashboard/dev_server.py
# then open http://127.0.0.1:8765/
```

Eight pages are wired against existing product surfaces —
**Overview**, **Readiness**, **Policy Packs**, **Release State**,
**Audit**, **Policy Check**, **Demo**, **Runtime**. The first four
are read-only projections of the doctor / packs / release-check
JSON; the latter four are narrow ephemeral endpoints over the
canonical `PolicyManager.decide()` / `run_pipeline()` / `siphrix
demo` product calls. No write path, no terminal emulator, no
filesystem browser.

- [docs/ui/SHOWCASE.md](docs/ui/SHOWCASE.md) — 5-minute operator
  tour covering version / doctor → demo → dashboard → release gate.
- [docs/ui/README.md](docs/ui/README.md) — UI documentation entry
  point, philosophy, and tech stance.
- [docs/ui/DASHBOARD.md](docs/ui/DASHBOARD.md) — canonical
  dashboard spec: page map, component list, data contracts, UI
  states, explicit out-of-scope list.
- [tools/siphrix_dashboard/README.md](tools/siphrix_dashboard/README.md)
  — implementation-level walkthrough (endpoints, safety limits,
  what each page binds to).
- [docs/release/FINAL_RELEASE_STATUS.md](docs/release/FINAL_RELEASE_STATUS.md)
- [docs/release/SIPHRIX_FULL_ABSORPTION_AUDIT.md](docs/release/SIPHRIX_FULL_ABSORPTION_AUDIT.md)
- [docs/architecture/ARCHITECTURE_v1.md](docs/architecture/ARCHITECTURE_v1.md)
- [docs/architecture/policy_versioning.md](docs/architecture/policy_versioning.md)
- [CHANGELOG.md](CHANGELOG.md)
- [docs/integration/CONTROL_PANEL.md](docs/integration/CONTROL_PANEL.md)
- [docs/integration/HOW_TO_INTEGRATE_SIPHRIX.md](docs/integration/HOW_TO_INTEGRATE_SIPHRIX.md)
- [docs/integration/PLANNER_ADAPTERS.md](docs/integration/PLANNER_ADAPTERS.md)
- [docs/release/RELEASE_NOTES_v1.md](docs/release/RELEASE_NOTES_v1.md)
- [docs/release/RELEASE_CONTENTS_v1.md](docs/release/RELEASE_CONTENTS_v1.md)

## Author

Denis Ghengeaua

Siphrix was originally designed and implemented by Denis Ghengeaua.

