Schema reference
The JSON Schemas that define workflows, activities, techniques, conditions, and session state. The Zod schemas in src/schema/ are the source of truth; the JSON files under schemas/ are generated from them (npm run build:schemas) and validate workflow definitions at authoring time.
The field tables below show each schema's top-level shape and are rendered from the checked-in schema files. For authoring guidance — how the pieces fit together when writing a workflow — read the schema guide.
activity.schema.json
Activity definition schema — unified ordered, kind-tagged steps[] (technique | action | checkpoint | loop).
Top-level fields
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | Unique identifier for the activity |
version | string | yes | Semantic version of the activity |
name | string | yes | Human-readable activity name |
description | string | no | Detailed description of the activity |
variables | object | no | The session variables this activity reads and writes. Its writes are declarations contributed to the including workflow's variable set; its reads are the names it needs that workflow to supply. |
techniques | string[] | no | Activity-wide technique references (:: paths); bundled into get_activity. |
bundleTechniques | object | no | Opt-in hybrid bundling: get_activity inlines each step technique whose composed wire form is at most maxChars and whose gate answers true at activity open; larger ones, and those whose gate has no answer yet, remain lazy-fetched via get_technique. Bundled deliveries are recorded as technique_bundled history events and satisfy the manifest fidelity check. |
steps | (technique | action | checkpoint | loop)[] | no | Ordered, kind-tagged execution steps for this activity |
exits | object[] | no | Named outcomes of this activity, one of which it takes when its steps end. Each is bound to a destination in the workflow's graph; an unbound exit fails the workflow load. Omitted on an activity that is terminal by omission. |
exits[].id | string | yes | Outcome name, unique within the activity. Kebab-case, in the activity's vocabulary — never an activity id. |
exits[].label | string | no | Human-readable statement of the outcome. |
exits[].when | string | no | Inline boolean expression selecting this exit, evaluated agent-side against the variable bag in the when dialect the step gates use. Omitted on an exit only a checkpoint option selects, and on the default exit. |
exits[].isDefault | true | no | The outcome when no when matched and no checkpoint option selected an exit — including a checkpoint dismissed because its condition was not met. Declared exactly once on an activity with two or more exits; isDefault: false is redundant and rejected. |
exits[].immediate | true | no | Selecting this exit at a checkpoint ends the step sequence there: the remaining steps do not run and the step-manifest check accounts for them. Declared for the aborts, where the tail would otherwise run against the user's decision. Without it an exit is recorded when chosen and taken when the sequence ends. immediate: false is redundant and rejected. |
triggers | object[] | no | Workflows the orchestrator dispatches from this activity (via dispatch_child with an explicit workflow_id); the server does not act on trigger declarations. |
triggers[].workflow | string | yes | ID of the workflow to trigger |
triggers[].description | string | no | Description of when/why this workflow is triggered |
triggers[].passContext | string[] | no | Context variable names the dispatching agent relays to the child workflow. The server does not copy them — a child session's bag starts from the child workflow's own declared defaults, nothing more. |
outcome | string[] | no | Expected outcomes when activity completes successfully. Advisory — the server does not reconcile them against activity_manifest outcomes. |
required | boolean | no | Whether this activity is required in the workflow Default: true |
rules | string[] | no | Activity-level rules and constraints that agents must follow |
artifactPrefix | string | no | Numeric prefix for artifact filenames, inferred from the activity filename (e.g., "02" from 02-design-philosophy.yaml). Server-computed — do not set in definition files. |
condition.schema.json
Condition expression schema
One of 4 variants: simple, and, or, not.
session-file.schema.json
Server-managed session file (session.
Top-level fields
| Field | Type | Required | Description |
|---|---|---|---|
schemaVersion | 1 | yes | - |
sessionIndex | string | yes | - |
workflowId | string | yes | - |
workflowVersion | string | yes | - |
agentId | string | yes | - |
seq | integer | yes | - |
ts | integer | yes | - |
startedAt | string | yes | - |
currentActivity | string | no | Default: "" |
currentTechnique | string | no | Default: "" |
exit | string | no | Name of the exit the previous activity took. Default: "" |
activeCheckpoint | object | no | - |
variables | object | no | Default: {} |
completedActivities | string[] | no | Default: [] |
checkpointResponses | object | no | Default: {} |
history | object[] | no | Default: [] |
history[].timestamp | string | yes | - |
history[].type | "workflow_started" | "workflow_completed" | "workflow_aborted" | "workflow_triggered" | "workflow_returned" | "workflow_suspended" | "activity_entered" | "activity_exited" | "activity_skipped" | "step_started" | "step_completed" | "checkpoint_reached" | "checkpoint_response" | "checkpoint_replayed" | "decision_reached" | "decision_branch_taken" | "loop_started" | "loop_iteration" | "loop_completed" | "loop_break" | "variable_set" | "error" | "technique_fetched" | "resource_fetched" | "technique_bundled" | "variables_seeded" | "activity_usage" | "activity_dispatched" | "activity_redelivered" | "batch_refused" | "activity_outcome" | "progress_published" | yes | - |
history[].activity | string | no | - |
history[].step | integer | no | - |
history[].checkpoint | string | no | - |
history[].decision | string | no | - |
history[].loop | string | no | - |
history[].data | object | no | - |
history[].error | object | no | - |
status | "running" | "completed" | "aborted" | no | Default: "running" |
triggeredWorkflows | object[] | no | Default: [] |
triggeredWorkflows[].workflowId | string | yes | - |
triggeredWorkflows[].sessionIndex | string | yes | - |
triggeredWorkflows[].triggeredAt | string | yes | - |
triggeredWorkflows[].triggeredFrom | object | yes | - |
triggeredWorkflows[].status | "running" | "completed" | "aborted" | "error" | yes | - |
triggeredWorkflows[].completedAt | string | no | - |
triggeredWorkflows[].returnedContext | object | no | - |
triggeredWorkflows[].state | session-file | no | - |
planningFolderPath | string | no | - |
repo | string | no | - |
contextMode | "persistent" | "fresh" | no | - |
deliveredContent | object | no | - |
declaredArtifacts | object[] | no | - |
declaredArtifacts[].id | string | yes | - |
declaredArtifacts[].name | string | yes | - |
declaredArtifacts[].path | string | no | - |
parentSession | session-file | no | - |
state.schema.json
Workflow state schema
Top-level fields
| Field | Type | Required | Description |
|---|---|---|---|
workflowId | string | yes | - |
workflowVersion | string | yes | - |
stateVersion | integer | no | Default: 1 |
startedAt | string | yes | - |
updatedAt | string | yes | - |
completedAt | string | no | - |
currentActivity | string | no | - |
currentStep | integer | no | - |
completedActivities | string[] | no | Default: [] |
completedSteps | object | no | Default: {} |
checkpointResponses | object | no | Default: {} |
activeLoops | object[] | no | Default: [] |
activeLoops[].activityId | string | yes | - |
activeLoops[].loopId | string | yes | - |
activeLoops[].currentIteration | integer | yes | - |
activeLoops[].totalItems | integer | no | - |
activeLoops[].currentItem | any | no | - |
activeLoops[].startedAt | string | yes | - |
variables | object | no | Default: {} |
history | object[] | no | Default: [] |
history[].timestamp | string | yes | - |
history[].type | "workflow_started" | "workflow_completed" | "workflow_aborted" | "workflow_triggered" | "workflow_returned" | "workflow_suspended" | "activity_entered" | "activity_exited" | "activity_skipped" | "step_started" | "step_completed" | "checkpoint_reached" | "checkpoint_response" | "checkpoint_replayed" | "decision_reached" | "decision_branch_taken" | "loop_started" | "loop_iteration" | "loop_completed" | "loop_break" | "variable_set" | "error" | "technique_fetched" | "resource_fetched" | "technique_bundled" | "variables_seeded" | "activity_usage" | "activity_dispatched" | "activity_redelivered" | "batch_refused" | "activity_outcome" | "progress_published" | yes | - |
history[].activity | string | no | - |
history[].step | integer | no | - |
history[].checkpoint | string | no | - |
history[].decision | string | no | - |
history[].loop | string | no | - |
history[].data | object | no | - |
history[].error | object | no | - |
status | "running" | "paused" | "suspended" | "completed" | "aborted" | "error" | no | Default: "running" |
parentWorkflow | object | no | - |
triggeredWorkflows | object[] | no | Default: [] |
triggeredWorkflows[].workflowId | string | yes | - |
triggeredWorkflows[].planningSlug | string | no | - |
triggeredWorkflows[].sessionIndex | string | no | - |
triggeredWorkflows[].triggeredAt | string | yes | - |
triggeredWorkflows[].triggeredFrom | object | yes | - |
triggeredWorkflows[].status | "running" | "completed" | "aborted" | "error" | yes | - |
triggeredWorkflows[].completedAt | string | no | - |
triggeredWorkflows[].returnedContext | object | no | - |
lastError | object | no | - |
technique.schema.json
Technique definition schema for workflow-server
Top-level fields
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | Unique identifier for the technique |
version | string | yes | Semantic version of the technique |
capability | string | yes | What this technique enables agents to do |
provenance_note | string | no | Delivery-only, server-populated on a step-bound get_technique: states the output delivery mechanics that the source:/destination: annotations rely on. Never authored in technique markdown. |
rules | rulesDefinition | no | - |
inputs | inputsDefinition | no | - |
inherited_inputs | inheritedInputs | no | - |
protocol | protocolDefinition | no | - |
outputs | outputsDefinition | no | - |
inherited_outputs | inheritedOutputs | no | - |
workflow.schema.json
Workflow definition schema
Top-level fields
| Field | Type | Required | Description |
|---|---|---|---|
$schema | string | no | - |
id | string | yes | Unique workflow identifier |
version | string | yes | Semantic version |
title | string | yes | Human-readable workflow title |
description | string | no | Detailed workflow description |
author | string | no | Author metadata; not read by the server. |
tags | string[] | no | - |
rules | object | no | Workflow rules partitioned by audience: workflow (orchestrator-only) and activity (inherited by every activity, injected into get_activity). A rule is plain text; text two workflows both need belongs in the conduct technique whose audience it binds. |
fragments | object | no | Shared checkpoint bodies, declared once and imported by ref ([workflow::]name) from a kind:checkpoint step — this workflow's or another's. Resolved at load; agents always receive materialized content. |
variables | object[] | no | The variables this workflow file owns: facts about the session and policy spanning activities. A variable an activity writes is declared by that activity, under its own variables.writes, and contributed here when the activity joins this workflow's graph — get_workflow renders the whole set, and two declarations of one name that disagree on type or default fail the load. The session variable bag is seeded from each declaration's defaultValue at session creation; thereafter the server writes it through checkpoint setVariable effects and through the worker outputs an orchestrator relays as next_activity's variables_changed. |
variables[].name | string | "requirements" | "features" | "exclusions" | "dimensions" | "tasks" | "results" | "submodules" | "paths" | "fields" | "filters" | "stats" | "effects" | "substitutions" | "findings" | "assumptions" | "subsystems" | "transitions" | "options" | "branches" | "agents" | "changes" | "failures" | "items" | "files" | "gaps" | "outcomes" | "body" | "query" | "repo" | "owner" | "number" | "title" | "branch" | "diff" | "limit" | "name" | "sha" | "url" | "head" | "base" | "ref" | "labels" | "path" | "cursor" | "cql" | "jql" | "description" | "assignee" | "depth" | "direction" | "summary" | "state" | "target" | "adr" | "type" | "mode" | "kind" | yes | Qualified snake_case noun phrase (>=2 words, AP-60), or an enumerated bare-word exemption. |
variables[].type | "string" | "number" | "boolean" | "array" | "object" | yes | Declared type. The server validates checkpoint setVariable values against it, warn-only: a mismatch is stored as written and surfaced in _meta.validation and on the variable_set history event. Agents honor it for their own writes. |
variables[].description | string | no | - |
variables[].values | string[] | no | The complete set of values a string variable admits. The server validates writes against it warn-only, as it does the declared type. |
variables[].defaultValue | any | no | Initial value the server seeds into the session variable bag at session creation (start_session fresh sessions and dispatch_child children), recorded as one variables_seeded history event. Do not gate a defaulted variable with exists/notExists — seeding makes the gate constant (check:variable-model enforces this). |
variables[].required | boolean | no | Authoring metadata; the server does not check that the variable is ever set. Default: false |
techniques | object | no | Workflow techniques partitioned by audience: workflow (orchestrator, bundled into get_workflow) and activity (inherited by every activity, injected into get_activity). |
initialActivity | string | no | ID of the first activity to execute. Required for sequential workflows, optional when all activities are independent entry points. |
graph | object | no | The workflow's shape: for each activity, where each of its exits leads. This is the single home for the routing — an activity names outcomes, the workflow names destinations, so a borrowed activity sits in this graph without its lending workflow having a say. Omitted only by a workflow whose activities declare no exits. |
activities | object[] | no | Activities that comprise this workflow. An activity whose exits the graph binds sits in a sequence; one declaring no exits is terminal. Omitted in definition files where activities are separate files. |
activities[].id | string | yes | Unique identifier for the activity |
activities[].version | string | yes | Semantic version of the activity |
activities[].name | string | yes | Human-readable activity name |
activities[].description | string | no | Detailed description of the activity |
activities[].variables | object | no | The session variables this activity reads and writes. Its writes are declarations contributed to the including workflow's variable set; its reads are the names it needs that workflow to supply. |
activities[].techniques | string[] | no | Activity-wide technique references (:: paths); bundled into get_activity. |
activities[].bundleTechniques | object | no | Opt-in hybrid bundling: get_activity inlines each step technique whose composed wire form is at most maxChars and whose gate answers true at activity open; larger ones, and those whose gate has no answer yet, remain lazy-fetched via get_technique. Bundled deliveries are recorded as technique_bundled history events and satisfy the manifest fidelity check. |
activities[].steps | (technique | action | checkpoint | loop)[] | no | Ordered, kind-tagged execution steps for this activity |
activities[].exits | object[] | no | Named outcomes of this activity, one of which it takes when its steps end. Each is bound to a destination in the workflow's graph; an unbound exit fails the workflow load. Omitted on an activity that is terminal by omission. |
activities[].exits[].id | string | yes | Outcome name, unique within the activity. Kebab-case, in the activity's vocabulary — never an activity id. |
activities[].exits[].label | string | no | Human-readable statement of the outcome. |
activities[].exits[].when | string | no | Inline boolean expression selecting this exit, evaluated agent-side against the variable bag in the when dialect the step gates use. Omitted on an exit only a checkpoint option selects, and on the default exit. |
activities[].exits[].isDefault | true | no | The outcome when no when matched and no checkpoint option selected an exit — including a checkpoint dismissed because its condition was not met. Declared exactly once on an activity with two or more exits; isDefault: false is redundant and rejected. |
activities[].exits[].immediate | true | no | Selecting this exit at a checkpoint ends the step sequence there: the remaining steps do not run and the step-manifest check accounts for them. Declared for the aborts, where the tail would otherwise run against the user's decision. Without it an exit is recorded when chosen and taken when the sequence ends. immediate: false is redundant and rejected. |
activities[].triggers | object[] | no | Workflows the orchestrator dispatches from this activity (via dispatch_child with an explicit workflow_id); the server does not act on trigger declarations. |
activities[].triggers[].workflow | string | yes | ID of the workflow to trigger |
activities[].triggers[].description | string | no | Description of when/why this workflow is triggered |
activities[].triggers[].passContext | string[] | no | Context variable names the dispatching agent relays to the child workflow. The server does not copy them — a child session's bag starts from the child workflow's own declared defaults, nothing more. |
activities[].outcome | string[] | no | Expected outcomes when activity completes successfully. Advisory — the server does not reconcile them against activity_manifest outcomes. |
activities[].required | boolean | no | Whether this activity is required in the workflow Default: true |
activities[].rules | string[] | no | Activity-level rules and constraints that agents must follow |
activities[].artifactPrefix | string | no | Numeric prefix for artifact filenames, inferred from the activity filename (e.g., "02" from 02-design-philosophy.yaml). Server-computed — do not set in definition files. |