← All guides

Deploying and operating an application

How your software runs against EARL once it works on your desk: what you deploy, what the platform keeps, what to do on every outcome, how to watch state and records, and how to change the engine underneath you. This is the primary deployment guide. Deploying a frozen adjudicator container is a specific case with its own guide: deploying an adjudicator.

What is deployed where — read this first

In this release the persistent cognitive runtime is not a container you run. It runs inside the platform: one runtime image per workflow, loaded, acted on and saved per call, behind the application API (/api/v1) with the application's key. So "deploying an application" means:

  1. You deploy your own service — the code that owns the business logic — wherever you run software, with the application's API key in its secret store and the platform's URL in its configuration.
  2. The platform hosts the runtime for each of your workflows: the trained substrate, the belief store your service submits to, the records of every call. You never copy a runtime image around.
  3. Optionally, you deploy the adjudicator container: a frozen, read-only verifier over the trained domain that answers POST /verify with the same claim results and a signed evidence package. It runs anywhere Docker runs, with no platform present, and it is the only self-hosted artifact in this release.

That is the implementation boundary, stated plainly: the stateful capabilities (memory.*, reason.*, goals.plan, self.observe) are reachable only through the platform; the standalone verifier is the only part you can take off-platform. A self-hosted persistent runtime is future work, not a documented path.

1. Your service and its identity

Your service authenticates with the application's key (earl_ak_…), never with a person's session. Every capability call is recorded under the application's service identity (app-<slug>), which is how an auditor later tells your software's calls from a developer's. Keep one key per deployed environment and revoke keys from the application page when an environment is retired.

from earl_sdk import EarlClient, Result, SemanticUncertainty, OperationalError, NotFound

client = EarlClient(PLATFORM_URL, API_KEY)          # from your secret store
app = client.application(APPLICATION_ID)
wf = app.workflow()                                  # the workflow bound to the application's domain

The workflow id is stable for the life of the application. Store it with your configuration; do not create a workflow per request.

2. Handle every outcome

Every SDK call returns one of three disjoint outcomes. Your service must branch on all three; nothing is raised for a semantic answer.

outcome meaning what your service does
Result the capability did what was asked; result carries the payload act on it, with the policy disposition where one applies
SemanticUncertainty the engine declined with a reason (relation_unasserted, incomplete_derivation, no_belief_formed, a non-ALLOW policy decision …); result still carries the claim results treat as a non-answer: route to review, ask for more evidence, or record and continue — never as a denial by itself
OperationalError the environment failed (engine missing, store unavailable, lock timeout); nothing semantic happened retry or alert; the record says what failed

NotFound (404) means the object is not visible to this key — a wrong id or another tenant's object; both look identical on purpose. WorkflowBusy (409) means another call holds the workflow's lock; wait and retry.

outcome = wf.evaluate(claim_text)
if isinstance(outcome, Result):
    disposition = outcome.result["policy"]["disposition"] if outcome.result.get("policy") else None
elif isinstance(outcome, SemanticUncertainty):
    reasons = outcome.reasons          # e.g. ["relation_unasserted"]
else:                                  # OperationalError
    raise RetryLater(outcome.error)

3. Stateful operation

The workflow's runtime image is the state your service builds up. Rules of operation:

4. Watch it: records, evidence, replay

Every call is an append-only, Ed25519-signed record. Operate from them:

Alert on: OperationalError rates, substrate_identity_mismatch: true from a deployed container, a non-identical replay, and any record whose execution_path is not the one the manifest declares for that capability.

5. Change the engine under a running application

runtime.version lets an application pin or adopt an installed engine release for its workflow (wf.adopt_engine(tag), wf.rollback_engine()); the next call runs on the adopted binaries and every record names them. The contained successor interface goes one step further for candidates: evaluate a candidate release over a copy of the workflow image (evaluate_successor), then adopt it as an explicit authority action bound to that evaluation with preservation checks (adopt_successor), and roll back byte-identically (rollback_successor). Both are installed-release adoption under your control; neither is EARL producing its own successors (see the register's developmental roadmap).

Procedure for a change: evaluate the candidate → run your own acceptance tests against the evaluation's copy → adopt → verify records still contiguous and offline-valid → keep the rollback handle until your next release.

6. Data and environments

7. Checklist before you call it deployed