helixordevelopers

Licensing and tiers

A license decides which packs and features your runtime may use. It is a signed file that the runtime verifies locally; no license server is contacted during evaluation.

Tiers#

TierUnlocksLimits
CommunityThe runtime with the built-in example pack: evaluate, stream, batch, serve.Static rules; cannot compile custom rules.
DeveloperCompiling your own playbooks into packs, with your own regex rules. (compile_custom_rule has no public engine to run on in 0.2.1: a loaded pack is sealed. It is removed in the next release. Put custom rules in the playbook.)Per-minute decision limit, stated in the license.
Launch trialAs Developer.Limits are tracked rather than enforced.
EnterpriseLicensed packs and solvers, all features.None in the runtime.

Studio (ontology viewer, data-source binding) and Expert pack authoring are portal capabilities that sit on top of these runtime tiers.

What a license contains#

A .hxlic file is JSON with five parts, signed as a whole:

PartContents
identityOrganization, organization ID, contact email.
entitlementsTier, plan, licensed pack and solver patterns (wildcards allowed), features, optional decision limits.
validityvalid_from, valid_until, and a grace period (14 days by default).
cryptoKey ID and the content key used to decrypt packs issued for this license.
signatureEd25519 signature over the canonical JSON of everything above.

Field-level detail is in the license file reference.

How verification works#

  1. The runtime checks the Ed25519 signature against the Helixor license authority's public key built into the runtime. Any edit to the file invalidates it. 0.2.1 trusts a new authority key and rejects licenses signed with the previous one (LicenseRevokedAuthorityError), so ask for a reissued license when you upgrade from 0.2.0, and compile or download your packs again with it.
  2. It checks that the current time is after valid_from and before valid_until plus the grace period.
  3. Before unsealing a pack, it checks that the pack ID (and every solver the pack declares) matches the license's entitlements.

Any failure raises a typed error (LicenseSignatureInvalidError, LicenseExpiredError, LicenseNotYetValidError, LicenseEntitlementError) and nothing is evaluated. The runtime fails closed.

Where the runtime looks#

  1. An explicit path (--license on the CLI).
  2. HELIXOR_LICENSE_FILE.
  3. ./helixor.lic (CLI only; the Python loader skips this step).
  4. ~/.helixor/helixor.lic.
helixor-pack inspect-license ~/.helixor/helixor.lic

Protect the license file#

The license is a secret

It contains the content key that decrypts every pack issued for it. Anyone with your license and your packs can read your rules. Store it in a secret manager, mount it read-only, set file mode 600, and never bake it into an image, commit it, or pass it in a URL.

Expiry, grace and renewal#

  • Monitor expiry. Results carry license_status (EXPIRING_SOON, IN_GRACE_PERIOD), for the built-in pack and for compiled packs. Also check helixor-pack inspect-license on a schedule (see Reliability). Either signal should page someone. After the grace period the runtime refuses to load packs, and an engine that is already running a compiled pack raises LicenseExpiredError on every evaluate() (new in 0.2.1; in 0.2.0 a running service kept working until its next start). Monitor expiry; do not wait for requests to fail.
  • Renewal issues a new license ID, and packs are bound to the license ID they were compiled for. Recompile or re-download your packs with the new license and deploy both together.
  • Time comes from the host clock. Keep hosts synchronized to a trusted time source.

Rate limits on Developer licenses#

If the license sets max_decisions_per_minute, the runtime counts decisions in a 60-second window per engine instance. In strict mode it raises DeveloperQuotaExceededError once the limit is reached; in trial mode it records the overage and continues. Counters are per process and reset on restart.

Known issue in 0.2.1

Only the built-in example pack enforces these limits. A compiled pack loaded with load_pack(), run or serve does not.

Fixed in the next release: a compiled pack enforces max_decisions_per_minute and max_decisions_lifetime before each decision. Past a limit, a license whose overage_policy is TRUE_UP records the overage and keeps deciding; any other policy raises DeveloperQuotaExceededError. The license's validity window is also checked on every decision, as in 0.2.1.

Planned#

  • Planned One-step activation: helixor license activate.
  • Planned Binding a license to a host or cluster, revocation, and offline activation.
  • Planned Wrapping the content key so that the license file alone cannot decrypt packs.