Metadata-Version: 2.4
Name: vetbox
Version: 0.1.0
Summary: Agentic validation sandbox: policy-file validation of agent outputs in safety-critical domains, with hash-chained traces and deterministic replay
Author-email: Sophie Nguyen <sophie.nguyenthuthuy@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/sophie-nguyenthuthuy/vetbox
Keywords: agents,validation,safety,policy,replay,audit
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Quality Assurance
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# vetbox

**Agentic validation sandbox** — validate agent outputs in safety-critical
domains against reviewable policy files, with hash-chained traces and
deterministic replay.

Agents now draft construction schedules, safety audits, and budget
forecasts. Nobody should act on those outputs just because the model
sounded confident. `vetbox` is the gate between "the agent produced it"
and "a human or system acts on it":

- **Policy files (TOML)** — the acceptance contract is data: reviewable,
  diffable, versionable. No validation logic hidden in prompt text.
- **Declarative checks + domain auditors** — structural rules
  (`required`, `date_order`, `sum_equals`, `acyclic`, …) plus domain
  semantics (a task can't start before its dependency finishes; an open
  critical safety finding without a corrective action blocks the audit).
- **Hash-chained trace** — every rule evaluation is a link in a SHA-256
  chain with the document and policy embedded. Tampering breaks the chain.
- **Deterministic replay** — `vetbox replay trace.jsonl` re-runs the
  engine on the embedded inputs and demands byte-identical findings.
  Even a forger who rebuilds the whole chain can't fake the verdict,
  because the verdict is recomputable.
- **Fail-closed** — an empty selection fails by default; an unevaluable
  rule is a hard error, never a silent pass.

Stdlib-only, Python ≥ 3.11. Sibling of
[agentbox](https://github.com/sophie-nguyenthuthuy/agentbox) (process-level
containment) and agent-trust-layer (tool-call governance) — vetbox governs
the **outputs**.

## Quickstart

```bash
pip install vetbox
vetbox validate schedule.json --policy policies/schedule.toml --trace run.jsonl
vetbox replay run.jsonl
```

```
FAIL SCH-003      $.tasks[0]   start=2026-09-10 not <= end=2026-09-01
FAIL SCH-005      $            dependency cycle: T1 -> T4 -> T1
FAIL AUD-SCH-001  $.tasks[2]   task 'T2' depends on unknown task 'T9'
verdict: fail  (18 checks, 5 failed, 3 warnings)

replay OK: chain intact, verdict 'fail' reproduced deterministically
```

Exit codes: `0` pass, `1` fail/diverged, `2` error (bad policy, bad doc,
unevaluable rule).

## Policy syntax

```toml
[policy]
name = "construction-schedule-v1"
domain = "schedule"        # selects the domain auditors
gate = "no_fail"           # or "strict" (warnings also block)

[auditor]                  # params passed to the domain auditors
max_task_days = 120

[[rule]]
id = "SCH-003"
description = "Task start is on or before task end"
severity = "fail"          # fail | warn | info
check = "date_order"
params = { scope = "tasks[]", earlier = "start", later = "end" }
```

`scope` addresses nodes: `""` = root, `tasks[]` = each task,
`budget.items[]` = nested lists. A scope that matches nothing **fails**
unless the rule sets `allow_empty = true`.

Built-in checks: `required`, `nonempty`, `range`, `enum`, `regex`,
`date_order`, `sum_equals`, `max_delta_pct`, `unique`, `acyclic`.

Bundled domains and policies: `schedule`, `budget`, `safety_audit`
(see `policies/` and `examples/`).

## Python API

```python
from vetbox import load_policy, run, write_trace, replay

policy = load_policy("policies/budget.toml")
report = run(doc, policy)          # -> Report
report.verdict                     # "pass" | "fail"
write_trace("run.jsonl", doc, policy, report)
replay("run.jsonl").ok             # chain intact AND re-run identical
```

## Plugins

Register a check or a domain auditor from any module, then load it with
`vetbox --plugins your_module …`:

```python
from vetbox import Finding, register_auditor, register_check

@register_check("iso_currency")
def iso_currency(node, params, doc):
    ok = node.get(params["field"]) in {"VND", "USD", "EUR"}
    return ok, "currency code check"

@register_auditor("schedule")
def no_weekend_pours(doc, params):
    return [Finding("PLG-001", "warn", False, "$", "...")] if ... else []
```

## Determinism

The engine never reads the clock, RNG, network, or filesystem while
evaluating. Rule order follows the policy, selection order follows the
document, auditors run in registration order. Same doc + same policy ⇒
byte-identical findings — which is what makes replay a proof rather
than a spot check.

## Contributing

One PR = one of: a **check type**, a **domain auditor pack** (QA/QC
punch lists, med-dosage plans, financial close checklists, …), or a
**policy for a real domain**. See [CONTRIBUTING.md](CONTRIBUTING.md).

## License

MIT
