Auto-generated mirror. Canonical sources:
skills/canopy-runtime/references/ops.md(index) and the per-feature slice files underskills/canopy-runtime/references/ops/. Edits go to the canonical files; this page is regenerated byscripts/sync-runtime-docs.py.
Framework Primitives — Index
Control-flow and interaction primitives available in every skill tree. Sliced into feature groups so a skill loads only what it uses.
Notation: << input source or options, >> captured output or displayed fields, | item separator.
Slice index
| Slice file | Primitives | Always loaded |
|---|---|---|
ops/core.md |
IF, ELSE_IF, ELSE, END, BREAK |
✓ |
ops/interaction.md |
ASK, SHOW_PLAN |
|
ops/control-flow.md |
SWITCH, CASE, DEFAULT, FOR_EACH |
|
ops/parallel.md |
PARALLEL |
|
ops/subagent.md |
Subagent dispatch — marker + bold call-site (no new primitive) | |
ops/explore.md |
EXPLORE + ## Agent soft-compat |
|
ops/verify.md |
VERIFY_EXPECTED |
Loading rules
The runtime loads slices on demand based on the skill’s manifest:
- Always loaded:
ops/core.md(universal control flow — every non-trivial tree uses it). - Loaded per
metadata.canopy-features: when the skill declarescanopy-features: [interaction, parallel], the runtime additionally loadsops/interaction.mdandops/parallel.md. - Manifest absent (back-compat): load all slices. The skill is treated as feature-unknown, so the full primitive surface is loaded conservatively.
/canopy validatewarns;/canopy improveproposes adding the manifest.
Primitives are never overridden by skill-local or project ops.
Slice values (for metadata.canopy-features)
core is implicit-always-loaded — never list it in the manifest. Other valid values:
interactioncontrol-flowparallelsubagentexploreverify
/canopy validate enforces drift between declared features and tree usage (warning here; vscode error in the follow-up extension PR).
Core Primitives — IF / ELSE_IF / ELSE / END / BREAK
Universal control flow. Always loaded by the runtime regardless of the skill’s canopy-features manifest — every non-trivial tree uses these.
Notation: << input source or options, >> captured output or displayed fields, | item separator.
IF << condition
IF << condition
├── then-branch
[ELSE_IF << condition2
├── branch2]
[ELSE
└── else-branch]
Evaluate condition against step context.
Execute first matching branch; remaining branches skipped.
Branches may be op calls or natural language.
ELSE_IF << condition
Continues an IF or ELSE_IF chain.
Evaluated only if all prior conditions were false.
Branches may be op calls or natural language.
ELSE
Closes an IF or ELSE_IF chain.
Executed only if all prior conditions were false.
Branch may be an op call or natural language.
BREAK
Exit the current loop (FOR_EACH) or current op immediately.
Inside FOR_EACH: stops iteration and resumes at the next sibling after the loop.
Outside a loop: exits the current op and returns to the caller’s next node.
Does not halt the skill — execution resumes at the next sibling in the calling tree.
Use for early exit from iteration or optional branches within an op where remaining steps are not needed.
END [message]
Halt the entire skill execution immediately.
Display <message> to the user if provided.
Use for fatal conditions and guard checks that make further execution invalid.
Interaction Primitives — ASK / SHOW_PLAN
User-interaction primitives. Loaded when the skill’s manifest declares canopy-features: [..., interaction, ...].
Notation: << input source or options, >> captured output or displayed fields, | item separator.
ASK <question> << option1 | option2 [| …]
Present <question> with the listed options.
Do not proceed past this step until the user responds.
ASK may also be used in free-form mode without a |-separated option list — the runtime renders the question and accepts whatever the user types as the answer.
SHOW_PLAN >> field1 | field2 | …
Present a structured plan showing all listed fields before any changes are made.
Control-Flow Primitives — SWITCH / CASE / DEFAULT / FOR_EACH
Multi-way branching and iteration primitives. Loaded when the skill’s manifest declares canopy-features: [..., control-flow, ...].
Notation: << input source or options, >> captured output or displayed fields, | item separator.
SWITCH << expression
SWITCH << expression
├── CASE << value1
│ └── branch1
[├── CASE << value2
│ └── branch2]
[└── DEFAULT
└── default-branch]
Evaluate expression once against step context.
Match its value against each CASE in order; execute the first matching branch and skip the rest.
DEFAULT executes only if no CASE matched.
Branches may be op calls or natural language.
Use when branching on a single expression against multiple discrete values.
CASE << value
A branch within a SWITCH block.
Evaluated only if no prior CASE in the same SWITCH has matched.
Executed when the SWITCH expression equals value.
Branch may be an op call or natural language.
DEFAULT
Closes a SWITCH block.
Executed only if no CASE in the block matched.
Branch may be an op call or natural language.
FOR_EACH << item in collection
FOR_EACH << item in collection
├── body-step-1
├── body-step-2
[└── IF << exit condition
└── BREAK]
Bind item to each element of collection in turn and execute the body once per element.
If collection is empty, the body is skipped entirely.
BREAK inside the body exits the loop immediately; execution resumes at the next sibling after FOR_EACH. (BREAK lives in core.md.)
Body steps may be op calls or natural language.
Parallel Primitive — PARALLEL
Heterogeneous parallel-subagent fan-out. Loaded when the skill’s manifest declares canopy-features: [..., parallel, ...].
Notation: << input source or options, >> captured output or displayed fields, | item separator.
PARALLEL
PARALLEL
├── child-step-1
├── child-step-2
└── child-step-3
Heterogeneous parallel block.
Emit children as parallel subagent invocations in a single agent turn; each child runs in its own context window.
PARALLEL itself takes no input and produces no aggregate output — the parent merges children’s named bindings via subsequent tree nodes (e.g., a custom MERGE_* op).
Children may be op calls, prose subagent invocations, or EXPLORE; each child binds its result via its own >>.
Marker-based children (preferred): when a child is **OP_NAME** << ... >> ... (bold around the op name) and the resolved op definition carries > **Subagent.** Output contract: <schema>, the runtime dispatches the op’s body as a subagent with the bound << values as inputs and binds the schema-shaped result. Plain (un-bold) op-call children run inline. See subagent.md for the full contract.
Failure semantics: Promise.allSettled — a single child failure does not abort siblings; downstream nodes branch on outcomes via IF.
Use for ≥2 independent fan-out tasks with no ordering dependencies between them.
For data-parallel iteration over a list, use sequential FOR_EACH — PARALLEL_FOR_EACH is not yet specified.
Platform-specific emission rules: see runtime-claude.md and runtime-copilot.md.
A skill that uses PARALLEL with marker-based children should declare both features in its manifest:
metadata:
canopy-features: [parallel, subagent]
Subagent Dispatch — Markers + Bold Call-Sites
Per-op subagent dispatch model. Not a primitive — the existing op-call contract (<< inputs >> outputs) IS the subagent contract; the marker decides dispatch. Loaded when the skill’s manifest declares canopy-features: [..., subagent, ...].
Notation: << input source or options, >> captured output or displayed fields, | item separator.
Op definition marker
A subagent op’s definition (in references/ops.md or references/ops/<name>.md) carries a blockquote marker as the first content under its heading:
### REVIEW_ASPECT << aspect | file_paths >> findings
> **Subagent.** Output contract: `assets/schemas/aspect-findings-schema.json`
REVIEW_ASPECT << aspect | file_paths
├── Read `assets/constants/review-aspects.md` → § matching `aspect`
├── FOR_EACH << path in file_paths
│ └── read the file at `path`
└── apply criteria; return findings shaped per the contract
The marker may be expanded with input descriptions (narrative bullets — for primitive types/enums) or with Input contract: <schema-path> (for complex inputs):
> **Subagent.**
> **Inputs:**
> - `aspect` — enum: `"security"`, `"performance"`, `"style"`, `"correctness"`
> - `file_paths` — list of file paths (strings)
>
> **Output contract:** `assets/schemas/aspect-findings-schema.json`
Call-site marker
Calls to a subagent-marked op use bold around the op name in tree notation:
* PARALLEL
* **REVIEW_ASPECT** << "security" | context.file_paths >> security_findings
* **REVIEW_ASPECT** << "performance" | context.file_paths >> perf_findings
Plain (un-bold) OP_NAME << ... >> ... always means inline. Bold means dispatch out-of-context. The two markers (op-def + call-site) must be consistent — vscode flags drift.
Strict contract for subagent ops
A subagent op’s body may use:
- Names declared in its
<<signature - Static skill assets via path (
assets/constants/...,assets/templates/...,assets/policies/...)
A subagent op’s body MUST NOT use:
context.<name>where<name>is not in the signature- Bindings produced by prior tree nodes that weren’t passed via
<< - Other ambient parent state
If the op’s body legitimately needs ambient state, drop the marker — keep it as an inline op. The strict contract is what makes out-of-context dispatch viable.
Composition with PARALLEL
PARALLEL (see parallel.md) is a structural block. When its children are bold-marked op calls, the runtime fans them out as parallel subagent invocations — the canonical multi-source explore / multi-aspect review pattern. Plain children of PARALLEL run inline, sequentially within the same agent turn. Mixing is allowed.
Skills using marker-based children inside PARALLEL should declare both parallel and subagent in their manifest.
Contracts on subagent ops
The Output contract: reference inside the > **Subagent.** blockquote and the optional Input contract: reference share their syntax and semantics with universal op contracts — see ../skill-resources.md → “Op contracts (universal input/output schemas)”. The subagent marker is the dispatch flag; the contract markers are independent and apply to inline ops too.
Bare contract markers — > **Input contract:** \
Explore Primitive — EXPLORE + ## Agent Soft-Compat
Pre-canopy-S2 sugar for a single-element subagent that gathers context. Loaded when the skill’s manifest declares canopy-features: [..., explore, ...].
Notation: << input source or options, >> captured output or displayed fields, | item separator.
EXPLORE >> context
The first tree node when ## Agent declares an **explore** subagent.
EXPLORE is not a free-standing primitive — it only has meaning paired with a ## Agent section. The runtime treats this shape as syntactic sugar for an implicit single-element marked subagent op named EXPLORE:
- Launch an Explore subagent with the task described in the
## Agentbody. - Do NOT inline-read files yourself — the subagent handles all file access.
- Output contract is
assets/schemas/explore-schema.json(or legacyschemas/explore-schema.json). - First tree node must be
EXPLORE >> context(or another>>name; the binding sets the context variable).
Skills authored after canopy v0.20.0 should prefer the explicit subagent dispatch form (see subagent.md) — declare a real op (e.g. EXPLORE_TARGET) with a > **Subagent.** marker and call it as **EXPLORE_TARGET** >> context. The legacy ## Agent + EXPLORE shape continues to work for backward compatibility; /canopy improve proposes migration when it encounters the legacy form.
## Agent body shapes (legacy / soft-compat)
Three shapes the runtime accepts under ## Agent:
Shape A — minimal:
### Agent
**explore** — read all files under `$ARGUMENTS` and return a context object.
Shape B — bullet sub-tasks:
### Agent
**explore** — gather review context.
Sub-tasks:
- Read all files under `$ARGUMENTS`
- Detect lint/type-check config files
Shape C — op reference:
### Agent
**explore** — execute EXPLORE_TARGET.
Shape (C) resolves EXPLORE_TARGET via the standard op lookup chain and dispatches its body as the subagent task.
Hard removal of the legacy ## Agent path is deferred to a pre-1.0 cleanup. Until then, this slice loads only when the skill’s manifest declares explore (or has no manifest, so the runtime falls back to load-everything for back-compat).
Verify Primitive — VERIFY_EXPECTED
Post-execution state-check primitive. Loaded when the skill’s manifest declares canopy-features: [..., verify, ...].
Notation: << input source or options, >> captured output or displayed fields, | item separator.
VERIFY_EXPECTED << assets/verify/verify-expected.md
Check current state against expected outcomes defined in assets/verify/verify-expected.md (or verify/verify-expected.md for skills using the legacy flat layout).
VERIFY_EXPECTED reads the referenced checklist file as a list of - [ ] items, evaluates each against the current working state (filesystem, captured outputs, environment), and reports pass/fail per item.
Non-passing items are surfaced to the user in the response. Whether a non-passing item halts the skill is a per-skill decision documented in the checklist itself; the primitive merely reports.
The standard layout path is assets/verify/<file>.md; the legacy flat layout uses verify/<file>.md at skill root. Both are accepted.