Make your first decision
You write a small function that sends every payload through a decision pack and branches on the action it returns. Here the pack is the built-in example pack (data protection, compliance.regulatory_pii_guard.v1), whose actions fall into three outcomes: permit the payload, forward a redacted copy, or block it. Every later tutorial builds on this function.
About the example
This tutorial uses the built-in data-protection pack so you can run everything without writing a pack first. The same calls work for any decision pack: eligibility, limits, routing and so on. See Core concepts.
What you'll build#
A script, first_guard.py, that evaluates five payloads (four strings and one dict) and prints the outcome, the rules that fired, the text you may forward and the receipt for each one.
Prerequisites#
- The runtime installed in a virtual environment. See Installation.
- You have read the Quickstart, or you know what
evaluate()returns.
No license file, account or network access is needed. HelixorEngine() loads the built-in example pack.
Steps#
- Create the engine once
An engine is cheap to call and safe to reuse, so create one at module level and call it for every payload. Creating one per request wastes time and gains nothing.
from helixor_runtime import HelixorEngine engine = HelixorEngine() print(f"pack={engine.pack_id} version={engine.version} tier={engine.tier}") - Map every action to an outcome class
A pack returns one of a closed list of actions, so you can map every one of them to what your code does next. In the example pack they fall into three classes. Check for
blockfirst, because a blocked payload also hasinvariants_passed == False, just like a redacted one.Outcome How to detect it What you forward block action.startswith("block")Nothing. The payload must not leave your process, redacted or not. permit invariants_passedisTrueremedy.clean_text, which equals the input.redact Anything else. Today that means redact_and_permit_contact_pii.remedy.clean_text, the repaired copy.def guard(payload): """Return (outcome, text_to_forward, decision).""" decision = engine.evaluate(payload) if decision.action.startswith("block"): return "block", None, decision if decision.invariants_passed: return "permit", decision.remedy.clean_text, decision return "redact", decision.remedy.clean_text, decision - Evaluate a list of inputs
Add five payloads that cover every outcome class. The last one is a dict:
evaluate()accepts a dict and reads itstext,messageorpayloadkey.inputs = [ "Move the design review to Thursday at 2pm.", "Please email the invoice to billing@example.com or call (415) 555-0100.", "New hire paperwork: SSN 123-45-6789, start date Monday.", "Charge the renewal to 4111-1111-1111-1111 and email jane@example.com.", {"message": "Reach me at (212) 555-0199 after lunch.", "channel": "chat"}, ] for payload in inputs: outcome, forward, d = guard(payload) print(f"\n{outcome.upper():6} {d.action}") print(f" rules : {[t.rule_id for t in d.triggers]}") print(f" forward : {forward!r}") print(f" receipt : {d.receipt_hash}") - Run it
python first_guard.py
pack=compliance.regulatory_pii_guard.v1 version=1.0.0 tier=COMMUNITY PERMIT permit_clean_payload rules : [] forward : 'Move the design review to Thursday at 2pm.' receipt : hx_proof_d41e4ee7179255ffa8ed178a REDACT redact_and_permit_contact_pii rules : ['RULE-GDPR-EMAIL-REDACT', 'RULE-TCPA-PHONE-REDACT'] forward : 'Please email the invoice to [REDACTED_EMAIL] or call [REDACTED_PHONE].' receipt : hx_proof_067cd4020bd4f1ba3ff796ea BLOCK block_glba_ssn_leakage rules : ['RULE-GLBA-SSN-BLOCK'] forward : None receipt : hx_proof_6ae04f03dd436188714e822b BLOCK block_pci_dss_pan_leakage rules : ['RULE-PCI-DSS-PAN-BLOCK', 'RULE-GDPR-EMAIL-REDACT'] forward : None receipt : hx_proof_c8bb35dc65e91d5219f2d95f REDACT redact_and_permit_contact_pii rules : ['RULE-TCPA-PHONE-REDACT'] forward : 'Reach me at [REDACTED_PHONE] after lunch.' receipt : hx_proof_0686c07a3cb8f0ad22dea925Receipts are deterministic, so the same input gives the same receipt on every machine.
- Look inside one decision
The card payload shows two things worth knowing. Every rule that matched is reported in
triggers, and the first fatal one decides the action. The remedy covers everything the pack found: here it redacts every category, including the email.from helixor_runtime import HelixorEngine engine = HelixorEngine() d = engine.evaluate("Charge the renewal to 4111-1111-1111-1111 and email jane@example.com.") print("action :", d.action) print("invariants_passed :", d.invariants_passed) print("reason :", d.reason) for t in d.triggers: print("trigger :", t.rule_id, t.severity, t.law) print("clean_text :", d.remedy.clean_text) print("redactions :", d.remedy.redactions_count, d.remedy.redacted_categories) print("latency_us :", d.latency_us) print("tokens / egress :", d.tokens_spent, d.egress_bytes) print("edition :", d.edition)action : block_pci_dss_pan_leakage invariants_passed : False reason : Statutory violation: Credit Card PAN (PCI-DSS Requirement 3) detected trigger : RULE-PCI-DSS-PAN-BLOCK FATAL PCI-DSS Requirement 3 trigger : RULE-GDPR-EMAIL-REDACT WARNING GDPR Article 6 & CCPA clean_text : Charge the renewal to [REDACTED_CARD_PAN] and email [REDACTED_EMAIL]. redactions : 2 ['Credit Card PAN (PCI-DSS)', 'Email (GDPR/CCPA)'] latency_us : 72.79 tokens / egress : 0 0 edition : COMMUNITY
latency_usvaries by machine and is highest on the first call. It covers evaluation only, not license checks or receipt hashing.
Dict input reads one field only
evaluate(dict) evaluates the first of text, message and payload that is present, even if it is empty, and ignores every other key. For example, {"text": "hi", "message": "SSN 123-45-6789"} is permitted. A dict with none of those keys, or with a value that is not a string, raises CodonRuntimeError. To screen a whole record, evaluate each string field, or serialize the record, as the API middleware tutorial does.
How it works#
For each payload the engine runs the pack's codons to extract typed facts into state, then checks every one of the pack's rules in a fixed order. The first fatal rule to match decides the action, and every match is reported in triggers. In the example pack, the codons are pattern extractors (with a Luhn check for card numbers) that build a state such as has_ssn or has_email, and the rule order is SSN, card, health record, then contact details. If no fatal rule fires, any contact detail produces the single redact action with one trigger per category. The remedy is always computed, so a blocked result still tells you what was found without you having to show the value.
A few inputs that look sensitive are permitted by the example pack by design. A phone number needs ten digits, so 555-0100 alone does not match. A 16-digit number that fails the Luhn check is not treated as a card. Put inputs like these in your tests; see Testing policies.
For the full field list, see the Python reference. For how rules and remedies fit together, see Core concepts and Evaluating decisions.