Decisions as a Service
Sign Up Now →Sign Up Now

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.

Licenses are issued by Helixor; request one on the sign-up page. The CLI cannot mint or sign a license.

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. (Put custom rules in the playbook; compile_custom_rule is removed in 0.3.0.)Per-minute decision limit, stated in the license.
Launch trialAs Developer.Limits are tracked rather than enforced.
EnterpriseLicensed packs and solvers, all features, including running solver engines in your process (solver.embedded, from 0.3.1).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. Since 0.3.0 the runtime rejects licenses signed with the revoked authority key that 0.2.0 and early 0.2.1 builds trusted (LicenseRevokedAuthorityError). If your license was issued for one of those builds, ask for a reissued license when you upgrade, 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#

The license file is helixor.hxlic. The CLI and every Python loader (HelixorEngine.load_pack, the HTTP service, HelixorSolver) use one search order and take the first file they find:

  1. An explicit path (--license on the CLI, license_file= in Python).
  2. HELIXOR_LICENSE_FILE.
  3. ./helixor.hxlic in the working directory.
  4. ~/.helixor/helixor.hxlic.

The name helixor.lic that runtime 0.3.0 used is still accepted in those two directories. A directory that holds both names raises LicenseLocationAmbiguousError (LICENSE_LOCATION_AMBIGUOUS): the runtime does not guess, so keep one. When no license is found, the runtime raises LicenseNotFoundError (LICENSE_NOT_FOUND, also a FileNotFoundError), whose message lists the six locations it checked and the sign-up URL. An explicit path or HELIXOR_LICENSE_FILE that names a missing file raises the same error; the search does not continue past it.

helixor-pack inspect-license ~/.helixor/helixor.hxlic

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.

Changed in 0.3.0

A compiled pack loaded with load_pack(), run or serve 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. In 0.2.1 only the built-in example pack enforced the limits. The license's validity window is also checked on every decision.

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.