diff --git a/site/design/protocol.html b/site/design/protocol.html index 067cffba..9853d44d 100644 --- a/site/design/protocol.html +++ b/site/design/protocol.html @@ -77,6 +77,7 @@

Call order and authentication

  • next_activity moves; get_activity reads. The orchestrator advances the session and gets back only the new activity's id; the worker then loads the full definition. Later transitions come from the transitions field of the current activity, validated server-side against the definition.
  • An active checkpoint locks the session. Between yield_checkpoint and respond_checkpoint, navigation and content reads (next_activity, get_activity, get_technique, get_resource, get_trace) are refused; only the checkpoint tools and get_workflow_status proceed. respond_checkpoint with a user choice is additionally rejected if it arrives less than three seconds after the yield — a response that fast did not involve a person.
  • Replays are safe. Yielding a checkpoint that was already resolved returns the cached response instead of pausing again, so a worker resumed with stale context cannot double-ask.
  • +
  • get_activity requires context_tokens. The worker declares its own context window in tokens on every activity fetch. The server derives an eager step-technique bundling budget from it (availability headroom × a token→char factor, both server config) and inlines ungated step-bound techniques that fit. It is per-agent and per-call — never stored on the session, never defaulted. Omitting context_tokens is a validation error. See eager bundling and Resolution.
  • Errors: the call failed

    @@ -107,7 +108,7 @@

    Warnings: the call succeeded, and left evidence

    Missing / unexpected steps in manifestThe reported step_manifest doesn't match the activity's declared steps — work was skipped, invented, or renamed. Step order mismatch, empty step outputSteps reported out of declared order, or a step claimed complete with nothing to show. - Technique not fetchedA manifested technique step has no technique_fetched event — the step was summarized from memory, not executed from its definition. + Technique not fetchedA manifested technique step has no technique_fetched or technique_bundled event — the step was summarized from memory, not executed from its definition. Workflow version driftThe definition changed on disk since start_session; the run continues under the new definition. Parent chain depthMore than five levels of nested dispatch — usually a sign the dispatch topology has gone wrong. @@ -138,7 +139,7 @@

    Reference delivery

    hash already in the ledger? deliveredContent, per agent - { unchanged: true, + { delivery: "unchanged", content_hash } full content delivered @@ -157,7 +158,16 @@

    Reference delivery

    Reference delivery in persistent mode. The ledger is keyed per agent and per channel (technique bundles, rules, individual techniques), so an orchestrator and a worker on the same session have independent delivery state. An agent that has lost its context can force re-delivery with get_activity { bundle: "full" } or get_technique { full: true }.
    -

    The marker is a contract, not a hint: unchanged: true asserts the content is byte-identical to what this agent already received, which the server can promise because payload composition is deterministic. If your context no longer contains the earlier copy, ask for full delivery rather than proceeding from a summary.

    +

    The marker is a contract, not a hint: delivery: "unchanged" asserts the content is byte-identical to what this agent already received, which the server can promise because payload composition is deterministic. If your context no longer contains the earlier copy, ask for full delivery rather than proceeding from a summary.

    + +

    Eager step-technique bundling

    +

    Every get_activity call automatically inlines small, ungated step-bound techniques under a step_techniques map — there is no per-activity opt-in. The worker supplies context_tokens; the server computes a cumulative per-activity character budget:

    +

    context_tokens × headroomFraction × charsPerToken — defaults 0.80 and 4, overridable via BUNDLE_HEADROOM_FRACTION and BUNDLE_CHARS_PER_TOKEN. Ungated technique steps are inlined in document order until the next would overflow the budget; gated steps (when/condition on the step or an enclosing loop) and oversized techniques stay lazy via get_technique { step_id }. A per-activity bundleTechniques.maxChars caps any single technique; maxChars: 0 opts the activity out entirely. Resources referenced by inlined techniques are never inlined — the worker still calls get_resource on demand.

    +

    Bundled entries share the technique:<resolvedId> ledger key with get_technique, so in persistent context mode a bundled delivery collapses a later step-bound refetch to an unchanged marker. Each bundled step is recorded as a technique_bundled event and counts toward manifest fidelity checks alongside technique_fetched.

    + +

    Enforcement notes and provenance

    +

    The server is a state ledger and payload composer, not an executor. Some constructs are agent-interpreted — step ordering, condition evaluation, actions[] verbs, protocol execution — and the server never checks them. Because a payload-only reader cannot see this classification, get_activity surfaces an enforcement_notes block (also in _meta) when the current activity contains agent-interpreted constructs: an actions note when a step is kind:action or carries an actions[] list; an auto_advance note when a checkpoint declares autoAdvanceMs. An activity without these constructs carries no block.

    +

    A step-bound get_technique fetch annotates the binding seam: each of the technique's own inputs carries a source: line stating where its value comes from (step-binding value, workflow variable, prior step output, declared default, or UNRESOLVED); remapped outputs carry a destination: line. Contract-inherited inputs are annotated only when the resolution says something the block note does not. Classification is purely static — same corpus and step always produce byte-identical annotations, which is what makes reference delivery safe.

    Dispatch in practice

    A typical work package starts before any planning folder exists: the meta session created by start_session for workflow selection is transient, living in the system temp directory. The first dispatch_child that commits to real work does three things at once — promotes the transient session into .engineering/artifacts/planning/<slug>/ (the slug from your request, or a dated fallback), creates the child session embedded in the parent's file, and returns the child's own session_index for the worker. From there:

    diff --git a/site/design/quality-system.html b/site/design/quality-system.html index de726158..cc477d02 100644 --- a/site/design/quality-system.html +++ b/site/design/quality-system.html @@ -72,37 +72,104 @@

    Quality system

    For contributors. Guards live in scripts/ as npm run check:*; tests run under Vitest in tests/.

    The guard suite

    -

    Most guards audit the workflow corpus (YAML and markdown). A summary by category:

    -
    - - - - - - - - - - - - - - -
    GuardWhat it enforces
    validate-workflow-yaml, validate-activitiesEvery workflow manifest and activity file parses and satisfies the schemas — a dry run of the server's own loaders.
    check-all-refsEvery technique reference resolves to a real technique; no misspellings, no dangling paths.
    check-binding-fidelityStep bindings are coherent end to end: arguments conform to declared inputs, reads resolve to a producer, outputs are consumed, and inputs have a source. Only new findings fail — known ones are listed in binding-fidelity-baseline.json.
    check-identifier-qualificationTechnique input and output ids are qualified noun phrases (completion_summary, never a bare summary).
    check-technique-templateTechnique markdown follows the normative structure of the technique protocol.
    check-resource-anchorsEvery #section anchor a technique uses to reference a resource exists in that resource.
    check-activity-technique-overlap, check-self-provisioned-input, check-prism-lens-reachabilityNamespace collisions between activities and techniques, inputs that circularly reference themselves, and unreachable review-lens paths.
    check-site-links, check-svg-layoutThis site: every internal link and anchor resolves, every GitHub link points at a real file, and no SVG diagram text collides with boxes, arrows, or sibling text.
    -
    +

    Guards are TypeScript scripts under scripts/ that walk the workflows worktree or this site's HTML and report violations. Each convention named in a specification or architecture page has a matching check — the spec defines the rule; the guard enforces it mechanically. Run them with npm run check:<name>; a clean tree always yields the same result.

    + +
    + + What the guard suite scans + Specifications and schemas define conventions. Guard scripts scan either the workflows worktree — YAML and markdown grouped into loadability, technique shape, wiring, and workflow safety — or the documentation site for link and diagram integrity. + + + + + + + + Specifications + schemas + the rules guards encode + + scripts/check-*.ts + npm run check:<name> + + workflows worktree + YAML + markdown + + Load + schema, refs + + Techniques + protocol shape + + Wiring + bindings, vars + + Safety + workflow rules + + documentation site + hand-authored HTML + generated regions + + check:site + links, nav, anchors + + check:svg + diagram layout + + + + + + + +
    Guards mirror the specification model: corpus checks group around loadability, technique contracts, static wiring, and workflow-specific safety; site checks keep links and inline diagrams honest. Per-guard behaviour lives in the scripts and in the spec pages that name them — for example Workflows, State, Resolution, and Fidelity.
    +
    + +
    + + Where guards run + Three entry points invoke the same guard scripts: local npm run check commands during authoring, Vitest drift tests for a subset of corpus guards, and the deploy-docs GitHub Actions workflow for site changes. + + + + + + + + Workflow authoring + npm run check:* + + npm test + corpus guards as drift tests + + deploy-docs CI + site guards + build:site + + scripts/check-*.ts + same scripts, reproducible exit codes + + + + + + + +
    Authors run guards locally while editing the workflows branch; Vitest mirrors key corpus checks so regressions fail npm test; the deploy-docs workflow runs the site pipeline on documentation PRs.
    +
    + +

    Most guards are hard-zero — any finding fails the run. A few compare against a committed baseline of reviewed, pre-existing findings and fail only when the corpus grows beyond that snapshot; re-snapshot with --update-baseline after an intentional change. The full command list is in package.json.

    The test architecture

    The Vitest suite (thirty-plus files) is organized around what could break:

    Generated, then guarded

    -

    Two artifacts are machine-derived from the source, and both are guarded against drift rather than trusted to stay fresh. The documentation site itself follows the same pattern — hand-authored pages with generated API regions — and check-site-links / check-svg-layout keep links and diagrams honest:

    +

    Two artifacts are machine-derived from the source, and both are guarded against drift rather than trusted to stay fresh. The documentation site itself follows the same pattern — hand-authored pages with generated API regions — and check:site / check:svg keep links and diagrams honest:

    diff --git a/site/design/request-lifecycle.html b/site/design/request-lifecycle.html index 44be27d1..c90f9ca7 100644 --- a/site/design/request-lifecycle.html +++ b/site/design/request-lifecycle.html @@ -121,7 +121,10 @@

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

    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. 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 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:

    @@ -134,7 +137,7 @@

    4. Fidelity checks

    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 history event — the step was actually loaded, not summarized from memory.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 diff --git a/site/design/server-anatomy.html b/site/design/server-anatomy.html index e8430da3..6c8918b2 100644 --- a/site/design/server-anatomy.html +++ b/site/design/server-anatomy.html @@ -116,7 +116,40 @@

    The shape of the codebase

    Module map

    -

    Grouped by what a request touches. Each row links to the primary source file.

    +

    Grouped by what a request touches. Tool handlers sit on shared machinery; machinery reads definitions and reads or writes session state on disk.

    + +
    + + How modules stack + An MCP tool call enters the tools layer, delegates to shared machinery for loading, validation, and delivery, and reaches the session store when state is read or written. + + + + + + + + MCP tool call + Zod-validated parameters + + tools/ + sixteen closures in workflow-tools.ts and resource-tools.ts + + Shared machinery + loaders · schema · validation · delivery · trace · result/errors + + utils/session/ → planning folders on disk + + + + + + + +
    Every tool is a thin handler over the same machinery. Loaders and validators are stateless; only the session store owns mutable run state. The tables below link each group to its source files.
    +
    + +

    Primary source files by group:

    Startup

    @@ -152,7 +185,48 @@

    Persistence and delivery

    The layer every call passes through

    -

    There is no central router — each tool is a closure registered at startup — but session-bound handlers follow the same skeleton so logging, seal checks, and persistence are uniform. Every handler is wrapped in withAuditLog. Tools that take a session_index call loadSessionForTool before touching state and saveSessionForTool after any mutation. Bootstrap entry points — discover, list_workflows, health_check, and start_session — get audit logging only. The worked example is request lifecycle.

    +

    There is no central router — each tool is a closure registered at startup — but session-bound handlers follow the same skeleton so logging, seal checks, and persistence are uniform. Bootstrap entry points (discover, list_workflows, health_check, start_session) get audit logging only. The worked example is request lifecycle.

    + +
    + + Handler wrapper skeleton + Session-bound tools pass through withAuditLog, loadSessionForTool, handler logic, and saveSessionForTool on the write path. Bootstrap tools skip session load and save. + + + + + + + + withAuditLog + audit + trace on every call + + loadSessionForTool + index → folder, seal check, parse + + Tool handler + load definitions · validate · deliver content + + advanceSession → saveSessionForTool + mutators only · atomic write + reseal + + Bootstrap path + withAuditLog + → handler + no session_index + + + + + + + + Read-only tools may still call save when recording delivery or fetch events in history + +
    The nesting is literal — wrappers in logging.ts and session/resolver.ts — so a failed seal check never reaches handler logic.
    +
    + +

    Stage by stage:

    1. withAuditLog (logging.ts) — outermost wrapper on every registered handler. It times the call, emits a structured audit event to stderr, and — when the parameters include a session_index — appends a trace event to the session's in-process TraceStore buffer. This runs on success and on thrown errors alike, so a failed seal check or validation still leaves an audit and trace record.
    2. loadSessionForTool (session/resolver.ts) — resolves the six-character session_index to a planning folder (how the index maps to disk), verifies the HMAC seal on session.json against .session-token, and parses the file into typed SessionFile state. Child sessions dispatched via dispatch_child live inside the parent's session.json; the loader navigates to the embedded sub-state the index addresses. If the seal does not match or the file fails schema validation, the call stops here — the handler never runs on state the server cannot vouch for.
    3. @@ -178,11 +252,40 @@

      Error discipline

      How these surface to a calling agent — and how they differ from non-blocking validation warnings — is covered in Protocol.

      Where things live on disk

      -
        -
      • Workflow definitions are read from the configured workflow directory — in this repository, the workflows/ worktree of the orphan workflows branch (why an orphan branch).
      • -
      • Session state is written under <workspace>/.engineering/artifacts/planning/<slug>/ — the session store page covers the folder's contents.
      • -
      • The server key lives at ~/.workflow-server/secret, per user, outside any repository.
      • -
      +

      Three locations, three lifetimes — definitions are read-only content, session state belongs to the workspace, and the server key is per-user infrastructure.

      + +
      + + Three on-disk locations + Workflow definitions live in the workflows worktree. Session state is written under the workspace engineering tree. The HMAC server key lives in the user home directory. + + + workflows/ worktree + orphan workflows branch + workflow.yaml, activities/, + techniques/, resources/ + read at call time, never cached + + workspace/.engineering/ + artifacts/planning/<slug>/ + + session.json + .session-token + workflow-trace.json + + written by session store + + ~/.workflow-server/ + secret — 32-byte HMAC key + session seals + session indexes + trace tokens + outside any repository + + loaders read left · session store reads and writes centre · crypto.ts reads right + +
      Definitions and session artifacts are version-controlled in their respective trees; the server key is created lazily at ~/.workflow-server/secret (mode 0600). Folder contents are detailed in session store and getting started.
      +

      Next

      Follow one request through this structure in the request lifecycle, or read how state is kept honest in the session store.

      diff --git a/site/specs/checkpoints.html b/site/specs/checkpoints.html index 82baf576..1bfb5ce1 100644 --- a/site/specs/checkpoints.html +++ b/site/specs/checkpoints.html @@ -192,6 +192,9 @@

      Resolving

      Resuming

      Agents wake in reverse order using the host's resume mechanism, with effects passed down as plain instructions. Before the worker can touch regular tools again it must call resume_checkpoint — a hard gate that verifies the checkpoint really was resolved and hands back the recorded variable updates. In inline (single-agent) execution the wake is a no-op persona switch; the server-side gates are identical.

      +

      Shared checkpoint fragments

      +

      A checkpoint reused at several sites is declared once as a checkpoint fragment under fragments.checkpoints in the owning workflow's workflow.yaml. Each use site is a kind:checkpoint step carrying only its site-local id and ref: [workflow::]name — plus a condition when the fragment declares none. The loader materializes the fragment body into the step before delivery, so yield, present, respond, and every downstream consumer see an ordinary full checkpoint. The check:fragments guard rejects an inline body that duplicates a declared fragment.

      +

      Why this design

      • Pause and presentation are separate — the worker records the pause with yield_checkpoint and steps aside; the user-facing agent later presents and responds. Nothing advances past an unresolved checkpoint, wherever it was raised.
      • diff --git a/site/specs/resource-resolution.html b/site/specs/resource-resolution.html index 37d867bb..8fc79e0f 100644 --- a/site/specs/resource-resolution.html +++ b/site/specs/resource-resolution.html @@ -199,13 +199,28 @@

        References

        Example: bare names resolve workflow-first with a meta fallback; nested segments address sub-techniques; a leading workflow segment reaches shared layers explicitly.
        +

        Borrowed activities and source-workflow scoping

        +

        A workflow may reuse an activity file authored in another workflow — a borrowed cross-workflow activity. Bare technique refs inside that activity (including activity-group shorthand like activity-id::op) resolve against the source workflow the activity file was authored in, not the borrowing session's workflow. Explicit workflow:: prefixes still reach named workflows directly. The same scoping applies to checkpoint fragment refs and to binding-provenance producer scans on step-bound get_technique fetches. Non-borrowed activities keep source scope equal to the session workflow, so behaviour is unchanged outside the borrowed-activity case.

        + +

        Workflow fragments

        +

        Beyond technique refs, a workflow can declare reusable content once under fragments in workflow.yaml and import it by reference:

        +
          +
        • fragments.rules — shared rule texts; rules slots accept either a rule string or { ref: "[workflow::]name" }
        • +
        • fragments.checkpoints — shared checkpoint bodies (message, options, effects); a kind:checkpoint step imports one via ref, contributing its own site-local id
        • +
        +

        Resolution follows the same scoping as technique refs: workflow::name resolves only in that workflow's fragments; a bare name tries the declaring workflow first, then meta. Fragment bodies are plain content — a fragment cannot itself contain a reference. The loader materializes refs at load and delivery time, so agents always receive full content, never a ref to resolve. The check:fragments guard rejects inline copies that duplicate a declared fragment.

        +

        Delivery at workflow and activity granularity

        Agents never chain resolution calls at runtime. The server pre-resolves reference lists into bundles when you call:

        • get_workflow — orchestrator bundle: workflow-declared refs plus core orchestrator techniques (engine traversal, checkpoints, dispatch, discipline)
        • get_activity — worker bundle: activity refs, inherited techniques.activity from the workflow, plus core worker techniques (yield/resume, finalize, conduct rules)
        -

        Each bundle groups resolved content into three buckets. When a single technique is delivered, ancestor Initial / Final protocol blocks wrap the technique body recursively and the server renumbers the combined sequence. In persistent-context mode, reference-not-repeat delivery replaces already-delivered content with unchanged hash markers; fetch recording warns when a manifested step was never loaded.

        +

        Each bundle groups resolved content into three buckets. When a single technique is delivered, ancestor Initial / Final protocol blocks wrap the technique body recursively and the server renumbers the combined sequence. In persistent-context mode, reference-not-repeat delivery replaces already-delivered content with { delivery: "unchanged", content_hash } markers; fetch recording warns when a manifested step was never loaded.

        + +

        Eager step-technique bundling

        +

        The lazy per-step model above is complemented by automatic eager bundling on every get_activity call. The worker passes context_tokens — its context window size in tokens — and the server derives a cumulative per-activity character budget:

        +

        context_tokens × headroomFraction × charsPerToken (defaults 0.80 × 4; env-overridable). Ungated step-bound techniques are inlined in document order under step_techniques until the budget would overflow; gated steps and per-activity bundleTechniques.maxChars oversize caps stay lazy. maxChars: 0 opts the activity out entirely. Each inlined entry is byte-identical to a step-bound get_technique fetch, including provenance annotations; resources referenced inside inlined techniques are never inlined. Bundled steps are recorded as technique_bundled events and satisfy manifest fidelity checks. Protocol details are in Protocol.

        diff --git a/site/specs/state-management.html b/site/specs/state-management.html index cb8ea1e5..447b81a0 100644 --- a/site/specs/state-management.html +++ b/site/specs/state-management.html @@ -125,6 +125,13 @@

        The rule of determinism

        When an activity completes, the orchestrator consults the activity's transitions array. Conditions are structured objects — simple comparisons (==, !=, >, <, >=, <=, exists, notExists) composable with and, or, and not. The orchestrator must not ask you or the model what to do next: it evaluates conditions in array order against the current variables, and the first true names the next activity. Transitions can also come from decision branches and checkpoint-option effects.

        Path variation works through ordinary state: an activation variable set early (by a detection step or a checkpoint) marks a variant — review mode, monorepo handling — and conditional transitions and step gates branch on it for the rest of the run.

        +

        Step completion manifest

        +

        When an activity ends, the orchestrator passes a step_manifest to next_activity — a structured summary of completed steps from the activity just finished. Each entry names a step_id and an output: a short summary string for a single-output step, or a JSON object keyed by output id when the step declares more than one output (e.g. {"reference_path": "lib/x", "component_name": "x"}). The server validates warn-only: every ungated top-level step present, declaration order preserved, non-empty outputs. Steps gated by when or condition may be omitted; loop-body step ids are accepted but never required.

        +

        The manifest is cross-checked against fetch observability: a manifested technique step with no technique_fetched or technique_bundled event during the activity visit draws a warning — the step was reported complete but its composed technique was never loaded. See Protocol — warnings.

        + +

        Binding provenance

        +

        Where each technique input comes from and where each output lands is computed statically from the workflow definition — no session-state reads, byte-identical refetches stay byte-identical. A step-bound get_technique fetch annotates each of the technique's own inputs with a source: line (step-binding value, workflow variable, prior step output, declared default, or UNRESOLVED) and remapped outputs with a destination: line. Contract-inherited inputs are annotated only when the resolution says something the block note does not. For borrowed activities, producer scans resolve bound ops against the activity's source workflow. The same convention is enforced offline by check-binding-fidelity.

        +

        Server-managed persistence

        The server owns the canonical state and writes it on every authenticated call — agents only ever pass their 6-character session_index. Two files live in the planning folder: session.json, the human-inspectable, schema-validated state (see the session-file schema), and .session-token, an HMAC-signed seal binding that state to the workspace and server key. Writes are atomic (write-temp, then rename) and ordered; reads verify the seal and any mismatch is a hard SealMismatchError.

        Because state lives on disk rather than in the agent, a session can be paused, killed, or resumed at any point: resume is one start_session call with the planning slug, and server restarts are transparent.

        diff --git a/site/specs/workflows.html b/site/specs/workflows.html index 72199949..3acb626c 100644 --- a/site/specs/workflows.html +++ b/site/specs/workflows.html @@ -125,6 +125,7 @@

        Workflows

      • Activities — the phases the orchestrator can move between
      • Initial activity — where a new session begins
      • Rules and orchestrator techniques — behaviour that applies across the whole run
      • +
      • Fragments — shared rule texts and checkpoint bodies, imported by { ref } from rules slots and checkpoint steps (see below)

      When a session starts, the server reads this manifest. The first get_workflow call returns:

        @@ -218,9 +219,15 @@

        Activities

        Only one activity is current at a time. Two roles split the work:

        • Orchestrator — calls next_activity to move between phases
        • -
        • Worker — calls get_activity to load the step list (and may receive bundled techniques up front)
        • +
        • Worker — calls get_activity with context_tokens to load the step list and receive eagerly bundled step techniques that fit the derived budget
        +

        Borrowed activities

        +

        An activity file can be listed in more than one workflow — the borrowing workflow runs the phase, but the activity file's technique refs resolve against the workflow it was authored in. This mirrors fragment scoping: a borrowed activity's bare refs, checkpoint fragment refs, and binding-provenance scans all use the source workflow, not the session workflow. See Resolution — borrowed activities.

        + +

        Shared fragments

        +

        Rule texts and checkpoint bodies reused at several sites are declared once under fragments in workflow.yaml and imported by { ref: "[workflow::]name" }. Rules slots and kind:checkpoint steps carry the ref; the server materializes the body before delivery, so agents always see full content. A ref-form checkpoint step carries only its site-local id and, when the fragment declares none, a condition — body fields like message and options are forbidden locally. Details are in Resolution — workflow fragments and Checkpoints — shared checkpoints.

        +
        Activity file structure