Decisions as a Service
Sign Up Now →Sign Up Now

Packs and manifest

What is inside a compiled .hxpack file, what it is bound to, and the fields of embedded-pack-manifest.json, the file the typed SDKs are generated from.

Runtime 0.3.1Format version 1

The .hxpack container#

helixor-pack compile turns a playbook into a .hxpack file. helixor-pack download-pack fetches a catalog pack already sealed for your license. The file holds your compiled playbook, encrypted so that only your license can open it. The runtime decrypts it in memory and never writes the plaintext to disk.

Layout#

OffsetSizeField
04 bytesMagic: ASCII HXPK
42 bytesFormat version, big-endian. 1 in 0.3.1.
62 bytesLength n of the pack ID, big-endian.
8n bytespack_id, UTF-8, in clear text.
8 + n12 bytesAES-GCM nonce, random per compile.
20 + n32 bytesSHA-256 of the plaintext playbook, used as an integrity check after decryption.
52 + nrestAES-256-GCM ciphertext of the compiled playbook (canonical JSON).

The pack_id is readable without a key, so you can tell which pack a file holds. Everything else, including your rules and patterns, is encrypted.

What a pack is bound to#

  • Your license's content key. The encryption key is derived from the content_key in your .hxlic file. A pack compiled for one license cannot be opened with another.
  • The pack ID and license ID. "<pack_id>:<license_id>" is authenticated as associated data. Changing the header's pack_id, or using a different license, makes decryption fail.

Renewing a license means recompiling

A renewed or reissued license has a new license_id and content key. Packs sealed for the old license fail to open with it, with PackUnsealError: Decryption failed: content key mismatch or corrupted pack envelope. Recompile or re-download every pack when you install a new license, and deploy the license and packs together. See Packs and Licensing.

Load-time checks#

When a pack is loaded (helixor-pack run or serve), the runtime checks, in order:

  1. The license file's signature and validity window (see License file).
  2. The file is at least 56 bytes, the magic is HXPK and the format version is 1.
  3. The license allows the pack: pack_id matches a licensed_packs pattern, or the license has the custom_playbook_compilation feature.
  4. Decryption succeeds with the license's content key and associated data.
  5. The SHA-256 of the plaintext matches the header.
  6. Every solver the pack declares matches a licensed_solvers pattern.
  7. Every rule, codon and hard rule in the pack is one the engine executes (see Playbook schema).

Any failure stops loading with an error, and no partial pack is used. The exceptions are listed in Errors.

Not in 0.3.1

Packs are encrypted and integrity-checked, but they are not signed by Helixor. Nothing in the file proves who compiled it; anyone holding your license can compile a pack for it. Signed packs are Planned.

embedded-pack-manifest.json#

The manifest describes a pack's typed interface: its state fields, rules and actions. Embedded SDK generation reads it to produce typed clients for Python, Java, C#, Rust and C; see the language capability matrix. The runtime does not read it when evaluating.

Top level#

FieldTypeValue
generatorstringhelixor-sdk-gen
generation_modestringembedded_decision
packsarrayOne entry per pack.

Pack entry#

FieldTypeMeaning
pack_idstringFor example compliance.regulatory_pii_guard.v1 (the example pack).
schema_versionstringhelixor.pack_manifest.v1
domain_namestringUsed to name generated types, for example RegulatoryPiiGuard → RegulatoryPiiGuardClient.
goal_idstringThe decision this pack answers: optimize_decision for the example pack.
actionsstring[]The pack's actions.
default_actionstringThe action when no hard rule fires: permit_clean_payload for the example pack.
floornumberConfidence floor, for example 0.85.
budget_max_latency_msnumberDeclared latency budget. 1.0 for the example pack.
state_schemaobjectMap of field name to {name, property_type, description, required, min_value, max_value, default}. property_type is for example boolean.
hard_rulesarray{id, condition, verdict, action, factor, operator, threshold, threshold_str, is_boolean, factors}. verdict is refuse for every rule of the example pack, including the contact rule; action is the action the rule sets; operator is for example is_true. factors lists every state field the condition reads when there is more than one, and is empty otherwise.
has_decision_head, decision_headbool, object | nullfalse and null for the example pack.
merkle_rootstringFor an unsealed playbook, the same value as raw_pack_sha256. Despite the name, it is a SHA-256 content digest, not a Merkle root. See the note below.
sealed_at, raw_pack_sha256, is_sealedstring | null, string, boolraw_pack_sha256 is the SHA-256 of the pack's playbook as canonical JSON (keys sorted, compact separators). sealed_at is null and is_sealed is false in 0.3.1: manifests are not tied to a sealed pack yet.
solversarraySolvers the pack uses. Empty for the example pack.
codonsstring[]Codon codes only. Empty in the example pack's manifest.
metadataobjectFree-form.

Changed in 0.3.0

merkle_root is no longer a fixed placeholder. In the example pack's manifest it is d924f870…55ee, the SHA-256 of playbooks/regulatory_pii_guard.yaml as canonical JSON, the same value as raw_pack_sha256. It is an unkeyed digest: it identifies the playbook, but it is not a Merkle proof and not tamper evidence.

Known issue in 0.3.1

The contact rule's factor names one field. In RULE-GDPR-CONTACT-REDACT, factor is still has_email although the condition also covers phone and IP. Read factors, which lists all three.

Excerpt#

{
  "generator": "helixor-sdk-gen",
  "generation_mode": "embedded_decision",
  "packs": [
    {
      "pack_id": "compliance.regulatory_pii_guard.v1",
      "schema_version": "helixor.pack_manifest.v1",
      "domain_name": "RegulatoryPiiGuard",
      "goal_id": "optimize_decision",
      "default_action": "permit_clean_payload",
      "floor": 0.85,
      "state_schema": {
        "has_ssn": {"name": "has_ssn", "property_type": "boolean",
                    "description": "Evaluated by invariant RULE-GLBA-SSN-BLOCK", "required": true,
                    "min_value": null, "max_value": null, "default": null}
      },
      "hard_rules": [
        {"id": "RULE-GLBA-SSN-BLOCK", "condition": "state.has_ssn == True",
         "verdict": "refuse", "action": "block_glba_ssn_leakage",
         "factor": "has_ssn", "operator": "is_true",
         "threshold": null, "threshold_str": null, "is_boolean": true,
         "factors": []}
      ],
      "merkle_root": "d924f870db0232502ca7cdaee40f1403d99c7348cf25b40e5a90dd2b3d2555ee",
      "raw_pack_sha256": "d924f870db0232502ca7cdaee40f1403d99c7348cf25b40e5a90dd2b3d2555ee",
      "codons": [],
      "is_sealed": false
    }
  ]
}