IT-RAT the stack/wardryx GitHub ↗
policy plane · wave 2

Wardryx. Deterministic allow, deny or hold, with a human on the expensive stuff.

Your gateway asks one question before an agent acts: POST /v1/decide. Wardryx answers allow, deny or hold in one deterministic pass. No LLM sits in the decision path, so the same policy and the same request always return the same verdict, and a big spend waits for a human who signs off with a short-lived token. The pattern is old and good: PDP/PEP, XACML's good ideas, pointed at what agents do.

statuspre-1.0 · main is supported
coreGo · deterministic PDP
APIPOST /v1/decide on :8090
primitivesdeny_tool · deny_if_unattested · require_human_above_usd · deny_above_usd · max_steps · allow_domains
lineagePDP/PEP · XACML's good ideas
sixty seconds, thirty-four agents

Watch the gate sort a stampede.

This is a simulation, and it says so. It replays the shape of the live validation record: a 34-request concurrent burst, different agents, budgets and policies, all hitting /v1/decide at once. In the real run the filtering came back exact: 6/6 permission oversteppers denied with 403, unattested calls denied until attested, 176 decisions across the full campaign.

under the hood

One question in. One of three answers out.

The PEP posts the proposed action: agent, tools, declared domains, step count, estimated cost, attestation. Wardryx matches policies by agent:// glob and applies the rules in a fixed order, where deny_above_usd outranks every approval and the hold check comes after it. The verdict returns with a cacheable flag, the caller's cache keys on agent, tool set and attestation, and every decision leaves as an event.

TokenFuse PEP asks per request /v1/decide wardryx PDP :8090 policy set YAML · agent:// globs rule order deny_above_usd wins attestation “None” never passes decision cache agent+tools+attest deterministic: same request, same verdict no LLM anywhere in the decision path verdict allow · deny · hold + cacheable flag approval tokens HMAC-signed · short-lived cost-bound · single-use a hold resolves out of band agent-event bus source: wardryx policy_allow · policy_deny + one OTLP span per decision policies as code · terraform-provider-taipan PUT /v1/policies/{id}
what it decides

Six primitives. One fixed order. No moods.

Three verdicts, zero improvisation

Every answer is allow, deny or hold. No LLM sits in the decision path, so the same policy set and the same request return the same verdict, every time. A decision you can replay in a test is a decision you can defend in an audit.

Hold means a human

require_human_above_usd turns a big spend into a hold, not a guess. A human grants it out of band, and Wardryx mints a signed approval token bound to the cost the human actually saw. The agent resubmits with the token; nothing parks a connection waiting for a signature.

A hard ceiling that outranks approvals

deny_above_usd is the rule no token can talk past. It is checked before the hold logic ever runs, so even a granted approval cannot authorize a spend over the ceiling. Some numbers should end the conversation, and this one does.

Attestation as a first-class gate

deny_if_unattested demands a live attestation before an agent touches the sensitive rules. Methods are trimmed and lowercased on the way in, so a literal “None” string reads as no attestation instead of sneaking past as a value.

Fail-open or fail-closed, your call

When the PDP is unreachable, the enforcement point picks the failure mode per deployment. Fail-open keeps traffic moving and silently drops policy for the outage; fail-closed blocks every governed action until Wardryx is back. The default is documented, and so is the tradeoff.

Policy admin API + Terraform

PUT, GET and DELETE /v1/policies/{id} manage a runtime policy layer with validate-then-apply semantics; the file-loaded set stays a permanent floor no API write can erase. The taipan_wardryx_policy resource drives the same API from Terraform.

an honest comparison

Where the no comes from matters.

Two substitutes get proposed for a policy plane: asking the model to behave in the system prompt, and pointing at the IAM you already run. Keep your IAM; it answers a different question. Neither substitute sees tools, dollars and runs in one place.

Wardryx“Prompt the model to behave”IAM alone
DeterministicYes: same input, same verdictNoYes
Knows about costHolds above $XNoNo
Human approval flowBuilt in, token-boundNoTicket queue
Sees declared-but-not-invoked toolsYes, since the live-found bypass was fixedn/aNo
AuditabilityEvery decision an eventVibesPartial
in the stack

The desk every expensive idea stops at.

TokenFuse's PEP hook asks Wardryx on every request and stamps the verdict on the response. Each decision lands on the bus as a source: wardryx event, which Idryx correlates into the identity graph. Mockryx rehearses the denials in pre-prod, so the first real no is never the first no ever. And the policies themselves are code: the Platform page's Terraform provider creates, changes and destroys them like any other resource.

try it now
make build && ./bin/wardryx serve

Boots on :8090 with an in-memory store: allow-all until you load a policy, and it logs that choice. Then dry-run a policy offline against a directory of Agent Passports:

./bin/wardryx check ./passports ./policies/finance.yaml