Request lifecycle

Every authenticated tool call follows the same skeleton: verify the session, load the definition, validate the claim the agent is making, advance the state, reseal it, and sign the trace. That uniformity is possible because the whole system crosses one boundary — sixteen MCP tools with schema-validated parameters, no side channel, no shared files as API. This page walks that skeleton using next_activity — the most eventful call — as the example.

The handlers live in src/tools/workflow-tools.ts; the shared machinery each stage uses is mapped in server anatomy.

The seven stages of an authenticated call Seven boxes in sequence: validate parameters, load and verify the session, load the workflow, fidelity checks, advance the state, persist and reseal, sign trace and respond. Validate parameters Zod schema on the call Load + verify session seal check, schema parse Load the workflow YAML to validated model Fidelity checks five validators Advance the state seq++, history events Persist and reseal atomic write + HMAC Sign trace, respond trace token in _meta
The seven stages of an authenticated call. Stages one and two are identical for every tool; which validators run in stage four, and what stage five mutates, depend on the tool. Read-only tools such as get_activity skip stages five and six unless they record fetch or delivery events.

1–2. Entry, and proving the state is trustworthy

Parameters are validated by the Zod schema attached at registration, so a handler never sees a malformed call. The handler runs inside withAuditLog, which times it and records a trace event whatever the outcome.

loadSessionForTool then turns the six-character session_index into trusted state: it resolves the planning folder (how the index maps to a folder), recomputes the HMAC of session.json, and compares it with the stored .session-token digest using a timing-safe comparison. A mismatch raises SessionStoreError(SEAL_MISMATCH) and the call goes no further — the server refuses to act on state it cannot vouch for. The file is finally parsed against the session schema, so downstream code works with typed state, never raw JSON.

One more gate applies after loading: if state.activeCheckpoint is set, the session is paused — navigation and content reads alike are refused until the checkpoint is resolved (the checkpoint model).

3. Loading the definition

The workflow named in the session is loaded fresh from the workflow directory: the manifest is parsed and validated, each activity file is validated and gets its step ids populated, and the artifactPrefix is derived from the activity filename's numeric prefix. Rule and checkpoint fragment refs are materialized at load; borrowed cross-workflow activities retain their source-workflow id for technique and fragment scoping. Nothing is cached across calls — the definition on disk is always the definition in force, which is what lets workflow hotfixes land mid-session (with a version-drift warning rather than a failure).

The get_activity delivery path

Read-only tools skip stages five and six unless they record fetch or delivery events. get_activity is the richest read path: after the session gate and definition load, the handler composes the inherited technique bundle, materializes checkpoint fragment refs in the activity YAML, derives an eager step-technique budget from the caller's context_tokens, and inlines ungated step-bound techniques that fit under a step_techniques map. Each inlined entry is identical to a step-bound get_technique fetch — including binding-seam provenance annotations — and is recorded as a technique_bundled history event. When the activity contains agent-interpreted constructs, an enforcement_notes block names who executes them. Reference delivery may collapse already-delivered bundle entries and inlined techniques to { delivery: "unchanged", content_hash } markers before the response is returned.

4. Fidelity checks

With trusted state and a validated definition, the server checks the claim the call is making. For next_activity that means five validators from utils/validation.ts:

ValidatorChecksOn failure
validateActivityTransitionThe requested activity is a declared transition from the current one (the terminal sentinel is always valid).Blocks
validateWorkflowVersionThe definition's version still matches the version captured at start_session.Warns
validateStepManifestThe reported step_manifest covers the activity's declared steps — nothing missing, nothing invented, order preserved, no empty outputs.Warns
validateTechniqueFetchesEvery manifested technique step has a matching technique_fetched or technique_bundled history event — the step was actually loaded, not summarized from memory.Warns
validateTransitionCondition, validateActivityManifestThe stated transition condition exists in the definition, and the completed-activity trail is consistent with the workflow graph.Warns

The split is deliberate: only checks that are cheap and certain block the call; everything judgment-shaped becomes a warning in the response and the trace — see the advisory layers on the fidelity page.

5. Advancing the state

advanceSession applies the mutation as a controlled update: the monotonic seq counter increments, the timestamp refreshes, and the handler's mutator appends history events — activity_exited for the activity being left, activity_entered for the new one, and workflow_completed when the transition is terminal. A child session reaching its terminal state also notifies its parent, flipping the child's entry in the parent's triggeredWorkflows to completed (best-effort — a moved parent is tolerated).

6. Persisting and resealing

The updated state is written atomically — to a temporary file first, then renamed over session.json, with a copy-based fallback when the rename crosses filesystems. The HMAC is recomputed over the canonical JSON bytes and written to .session-token, and both files are kept at mode 0600. There is no code path that writes state without resealing it.

7. Signing the trace and responding

When tracing is enabled, the events accumulated since the last next_activity are packaged into a trace-token payload, HMAC-signed, and returned in _meta.trace_token — a tamper-evident receipt for that leg of the run, reconstructable later via get_trace.

The response body itself stays minimal: next_activity returns just the new activity's id and name, because the full definition is the worker's to fetch via get_activity. Alongside it, _meta.validation carries the outcome of stage four — { status, warnings } — so deviations are visible to the orchestrator on the very call that detected them. The warning taxonomy, error surfaces, and delivery markers an agent may encounter are catalogued in Protocol.

Next

The state this lifecycle protects is described field-by-field in the session store; the checks that guard the definitions themselves are in the quality system.