Warden Policy Pack

This is not a neural network. There are no weights, no tensors and no training data. It is a deterministic rule pack: a declarative policy plus the configuration of a hand-written, regex-based classifier. It lives in a model repository because that is where Hugging Face versions artifacts, not because anything here was learned.

Nothing in this repository requires torch, transformers or scikit-learn. It requires nothing at all β€” the files are JSON.

The engine that consumes this pack is the Warden Space, a policy decision point for LLM traffic. The evaluation set that pins its behaviour is warden-eval.


What it does

Warden answers one question: may this text go to this destination, for this purpose, from this team? The answer is allow, redact, reroute or deny, always accompanied by the rule_id that produced it.

This pack is the part a human writes and versions:

File Contents
policy.json destinations, rules, default effect, budgets
classifier.json sensitive vocabulary, PII weights and threshold, entropy heuristic
detectors.json the detector specification and the ledger hash definition, generated from the engine source

What it does not promise

Warden does not guarantee legal or regulatory compliance. All it can do is apply the rules you declared, consistently, and leave a record you can verify. Deciding what the rules ought to be is a human responsibility.

The policy shipped here is an example, not a recommendation. The destinations are fictional ("Provider A", "Provider B"), the sensitive vocabulary is a starting list, and the budgets are placeholders. Replace all three before any real use. A policy you inherited and never read cannot be applied consistently, which is the only thing this tool is for.


Usage

import json
from huggingface_hub import hf_hub_download

policy     = json.load(open(hf_hub_download("NagaYu/warden-policy-pack", "policy.json")))
classifier = json.load(open(hf_hub_download("NagaYu/warden-policy-pack", "classifier.json")))

policy["classifier"] = classifier          # the engine reads the classifier config from the policy

Paste the result into the Warden Space's Policy tab and press Validate, then Validate and activate.

The published Space is a static build: the engine runs in your browser, so the policy is activated locally in that tab and there is no HTTP API. Against your own Gradio deployment of the engine, the same thing over the API is:

from gradio_client import Client

client = Client("<user>/<space>")
print(client.predict(json.dumps(policy), api_name="/validate_policy"))
print(client.predict(json.dumps(policy), api_name="/save_policy"))

Always validate before activating. Validation reports duplicate rule IDs, references to undefined destinations, and rules that can never fire because a broader, higher-priority rule covers them.


Policy format

{
  "version": "2026-09-01",
  "destinations": {
    "vendor-a-large": {"provider": "A", "region": "us", "retention": "30d"},
    "self-hosted":    {"provider": "self", "region": "jp", "retention": "none"}
  },
  "rules": [
    {"id": "R001", "priority": 10,
     "match": {"subject": ["team-hr"], "level": ["confidential", "regulated"],
               "destination_provider": ["A", "B"]},
     "effect": "deny", "reason": "HR must not send confidential data to an external provider"}
  ],
  "default_effect": "deny"
}
  • Match dimensions: subject, level, destination, destination_provider, destination_region, purpose. An omitted dimension, or ["*"], means unconstrained. An empty array is rejected rather than read as "matches everything" β€” that reading turns a forgotten value into a silent blanket allow.
  • Effects: allow, redact, reroute, deny. Lowest priority number wins; ties break on document order. reroute returns only the alternative destinations the policy actually permits. Add "reroute_to": [...] to narrow the suggestions.
  • Budgets: hard/soft are token counts. 0 means zero, not unlimited β€” write a negative number for unlimited. Only the keys you write are overridden, and when hard < soft the soft limit is lowered to the hard limit, never the reverse.

No credential can live in this file

A destination may declare only provider, region, retention, label and notes. A field whose name looks like a credential is a hard validation error β€” and so is a value anywhere in the document that looks like one: a known key prefix (sk-, ghp_, AKIA, xoxb-, AIza, …), a JWT, a PEM private-key block, or a password = … assignment. Renaming the field does not help, and neither does pasting a key into a free-text notes or reason.

This is enforced by a test, not by convention. Warden is a decision point, not a place to keep secrets.


Classifier configuration

{
  "sensitive_terms": ["employment rules", "performance review", "medical record", "..."],
  "pii_threshold": 2,
  "pii_weights": {"credit_card": 2, "email": 1, "phone": 1, "ipv4": 1,
                  "date_of_birth": 1, "postal_address": 1},
  "entropy_threshold": 3.7,
  "entropy_min_len": 32
}

Levels are ordered public < internal < confidential < regulated:

  • any credential signal β†’ regulated
  • PII weight sum β‰₯ pii_threshold β†’ confidential
  • any sensitive term, and nothing stronger β†’ internal
  • otherwise β†’ public

Detectors (all local, hand-written, no model): email, phone, credit card (only when it passes the Luhn check), IPv4, date of birth, postal address, known credential prefixes, JWT triples, and long alphanumeric strings whose Shannon entropy exceeds the threshold. detectors.json carries the exact patterns.

Detection runs twice β€” once on the raw text and once on its NFKC normalization β€” because full-width text (1KI1…) does not match the raw patterns and would otherwise walk straight through. Character spans come from the raw pass only, since normalization can change string length; anything found only after normalization is reported with an empty spans list and an explicit line in reasons.

Every classification returns its evidence: signal types, counts and character spans. A classification you cannot inspect is a classification you cannot challenge. Samples for credential signals report only the type and length β€” never any characters of the secret.

Tuning

Symptom Knob
Too much is confidential raise pii_threshold, or zero out a pii_weights entry
Too much is regulated raise entropy_threshold (3.7 β†’ 4.2) or entropy_min_len (32 β†’ 48)
Wrong vocabulary for your org replace sensitive_terms wholesale

The shipped sensitive_terms list is bilingual (English and Japanese) because a vocabulary list is data, and a bilingual one simply covers more traffic. Terms match case-insensitively; ASCII terms additionally require a word boundary, so nda does not match agenda.


Ledger hash definition

detectors.json also carries the ledger's hash definition, so an auditor can verify an exported ledger without running Warden at all:

HASH_FIELDS = [seq, timestamp, subject, level, destination,
               verdict, rule_id, content_hash, prev_hash]
HASH_INPUT  = "|".join(json.dumps(v, ensure_ascii=False, sort_keys=True) for v in HASH_FIELDS)
hash        = sha256(HASH_INPUT.encode("utf-8")).hexdigest()

Each field is JSON-quoted before being joined, so a literal | inside a value cannot forge a different field split. The first record's prev_hash is "0" * 64. The ledger never stores the text β€” only sha256 of its NFKC-normalized, whitespace-collapsed form.


Evaluation

warden-eval holds labelled cases that pin this pack to its documented behaviour: expected classification level per text, and expected verdict and rule_id per decision. Run it after any change to the vocabulary, the thresholds or the rules.

License

Apache-2.0.

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Space using NagaYu/warden-policy-pack 1