signet-eval — Deterministic Policy Enforcement for AI Agents
Description: Enforce spending limits, block destructive commands, and control what AI agents can do. 25ms hook eval. No LLM in the authorization path. Self-protecting locked rules.

# signet-eval

Deterministic policy enforcement for AI agents. Control what your agent can do — spending limits, destructive command blocking, credential gating — without putting an LLM in the decision path.

25ms
hook eval (e2e)
14–63μs
in-process eval
14
condition functions
17
MCP tools

    cargo install signet-eval

## Three Steps

1. Install: `cargo install signet-eval`

2. Hook into Claude Code or Codex:

    {
      "hooks": {
        "PreToolUse": [{
          "matcher": "",
          "hooks": [{"type": "command", "command": "signet-eval", "timeout": 2000}]
        }]
      }
    }

Codex: enable `codex_hooks = true`, then use `signet-eval --adapter codex` for `PreToolUse` and `signet-eval --adapter codex-permission` for `PermissionRequest`.

3. Done. Every tool call now passes through policy evaluation.

## Default Policy

Self-protection rules are LOCKED — the agent cannot remove, edit, or reorder them, even through the MCP management server.

Action | Decision
--- | ---
Write/Edit/Bash to `.signet/` LOCKED | DENY
Tamper with `signet-eval` binary LOCKED | DENY
Modify `settings.json` LOCKED | ASK
Kill signet processes LOCKED | DENY
`rm`, `rmdir` | DENY
`git push --force` | ASK
`mkfs`, `format`, `dd if=` | DENY
`curl | sh`, `wget | sh` | DENY
Everything else | ALLOW

## Custom Rules

    # ~/.signet/policy.yaml
    version: 1
    default_action: ALLOW
    rules:
      - name: books_limit
        tool_pattern: ".*purchase.*"
        conditions:
          - "param_eq(category, 'books')"
          - "spend_plus_amount_gt('books', amount, 200)"
        action: DENY
        reason: "Books spending limit ($200) exceeded"

      - name: protect_prod
        tool_pattern: ".*"
        conditions: ["contains(parameters, 'production')"]
        action: ASK
        locked: true
        reason: "Production access requires confirmation"

## Condition Functions

Function | Description
--- | ---
`contains(parameters, 'X')` | Tool input contains string
`any_of(parameters, 'X', 'Y')` | Any string present
`param_eq(field, 'value')` | Field equals value
`param_ne(field, 'value')` | Field not equal
`param_gt(field, N)` | Field > number
`param_lt(field, N)` | Field < number
`param_contains(field, 'X')` | Field contains substring
`matches(field, 'regex')` | Field matches regex
`has_credential('name')` | Credential exists in vault
`spend_gt('cat', N)` | Session spend exceeds limit
`spend_plus_amount_gt('cat', field, N)` | Cumulative spend + amount exceeds limit
`not(condition)` | Negate any condition
`or(A || B)` | Either condition true
`true` / `false` | Literal boolean

## Features

### Self-Protection

Four locked rules prevent the agent from disabling its own guardrails. Locked rules can't be removed or edited via MCP. Direct file edits break the HMAC signature, triggering fallback to hardcoded safe defaults.

### Encrypted Vault

Argon2id + AES-256-GCM. Three tiers: public ledger, session-encrypted state, compartment-encrypted credentials. Session key encrypted with device-specific key. Brute-force lockout after 5 failed attempts.

### Spending Limits

Track cumulative spend per category. "Don't spend more than $200 on books" just works. Vault ledger enforces across every tool call. Reset with `signet-eval reset-session`.

### Scoped Credentials

Store credentials with domain, purpose, amount caps, and one-time constraints. `signet_use_credential` enforces all constraints before releasing. One-time tokens auto-invalidate.

### MCP Management

Manage policies by talking to Claude. "Add a $50 limit for amazon orders." 17 MCP tools: rules, credentials, testing, validation, reordering, signing, credential use.

### MCP Proxy

Wrap upstream MCP servers with enforcement. Hot-reloads policy on every call. The agent connects to the proxy, not directly to servers.

### Policy Integrity

HMAC-sign your policy file. Hook verifies integrity on every evaluation. Tampered files fall back to safe defaults automatically. MCP mutations auto-sign.

### Locked Rules

Mark rules as `locked: true` in YAML. MCP tools refuse to modify them. Unlocked rules can't be reordered above locked ones. Self-protection rules ship locked by default.

## Architecture

Part of the Signet personal sovereign agent stack. The core principle: the authorization layer must not be an LLM. It processes structured data only. No natural language, no context window, no persuasion surface. A rule either matches or it doesn't.

    Agent proposes action  ->  signet-eval evaluates policy  ->  allow / deny / ask
                               (deterministic, 25ms, no NLP)

## Security Model

signet-eval is a seatbelt, not a cage. It enforces policy within cooperative protocols — Claude Code and Codex call signet-eval around tool use and respect supported responses. This reliably blocks destructive commands, enforces spending limits, and gates credential access during normal operation.

Codex support maps to current Codex hook semantics: `PreToolUse` enforces deny decisions, while `PermissionRequest` can explicitly allow or deny requests Codex was already going to send through approval.

It does not protect against an adversarial agent with shell access. Any process at the same privilege level can use shell indirection (`alias`, `eval`, `base64 | sh`) to evade string matching, read the session key, or replace the binary. No amount of pattern matching fixes this — it's an infinite regress.

True containment requires OS-level controls: separate user accounts, containers, stripped `$PATH`, seccomp/AppArmor, or sandboxed environments. signet-eval is the policy engine inside such a perimeter. The OS enforces the perimeter. Neither replaces the other.

## All Commands

Command | Purpose
--- | ---
`signet-eval` | Hook evaluation (default, 25ms)
`signet-eval --adapter codex` | Codex `PreToolUse` evaluation
`signet-eval --adapter codex-permission` | Codex `PermissionRequest` evaluation
`signet-eval init` | Write default policy with locked self-protection
`signet-eval rules` | Show current rules (locked rules tagged)
`signet-eval validate` | Check policy for errors
`signet-eval test '<json>'` | Test a tool call
`signet-eval setup` | Create encrypted vault
`signet-eval unlock` | Refresh vault session
`signet-eval status` | Vault status and spending
`signet-eval store <n> <v>` | Store Tier 3 credential
`signet-eval delete <n>` | Delete credential
`signet-eval log` | Recent action log
`signet-eval reset-session` | Clear spending counters
`signet-eval sign` | HMAC-sign policy file
`signet-eval serve` | MCP management server (17 tools)
`signet-eval proxy` | MCP proxy for upstream servers