Imported from veegee82/agent-workflow-protocol (
skill/SKILL.md). Install upstream withnpx skills add veegee82/agent-workflow-protocol --skill skill. Copyright stays with the author.
AWP Workflow Builder
See also — Authoritative non-normative docs: docs/README.md (concept map), docs/overview.md, docs/layer-model.md · Normative spec: spec/versions/1.0/spec.md, spec/versions/1.0/validation-rules.md, spec/versions/1.0/compliance.md · Per-layer references consumed by this skill: architecture, compliance-levels, spec-summary, validation-rules, tools-reference · Runtime contracts a generated workflow must satisfy: docs/runtime.md (budget envelope, completion gate chain, R17 agent contract), docs/validation.md, docs/critique.md, docs/evaluation.md · Sync contract: CLAUDE.md §Skill Synchronization — every change to runtime, models, or features MUST update this file and templates/
AWP 7-Layer Model
AWP organizes a workflow into seven protocol layers. Each layer answers one question:
You start at the bottom. Layer 0 (manifest) and Layer 1 (agent identity) are always required. Everything above is opt-in.
Autonomy Levels
Autonomy levels measure HOW AUTONOMOUS the workflow is, not WHAT FEATURES it has. Communication, memory, and observability are cross-cutting features available at any level.
| Level | Name | Description |
|---|---|---|
| A0 | Prescribed | Static DAG, predefined agents, fixed tools. Minimum viable workflow. |
| A1 | Adaptive | Conditional execution, loops, fan-out, multi-agent DAG. |
| A2 | Delegating | Manager spawns workers dynamically (delegation loop). Budget required. |
| A3 | Self-Tooling | Agents create tools and skills at runtime. Safety envelope required. |
| A4 | Self-Organizing | Recursive delegation, budget distribution. Observability required. |
Cross-cutting features (any level): Communication, Memory, Observability, Security.
Platform Features
| Feature | Config Location | Description |
|---|---|---|
| Agent DAG | workflow.awp.yaml graph |
Directed acyclic graph of agents with depends_on edges. |
| State Sharing | graph[].share_output | Fields from an agent's output available to dependents. |
| Execution Modes | execution.mode | sequential, parallel, or conditional execution. |
| MCP Tools | agent.awp.yaml tools | Tool calling via the MCP registry (web, file, shell, etc.). |
| Message Bus | communication.bus | In-memory message passing between agents. |
| Memory | memory.tiers | Long-term (MEMORY.md) and working (daily logs) memory. |
| Skills | workflow skills/ | Markdown knowledge injected into agent system prompts. |
| Preprocessor | agent workflow/preprocessor/ | Data extraction and feature engineering before LLM call. |
| Vision | agent.awp.yaml vision | Image processing via base64-encoded data URLs. |
| Archetypes & Recipes | runtime, no YAML | Six generic tool archetypes (compute / fetch / parse / transform / render / probe). The manager plans capabilities as reuse_or_generate: "synthesize" with archetype_id + recipe_params, the runtime synthesises a deterministic handler, and successful instantiations are auto-captured as content-addressed Recipes under ~/.awp/recipes/ (Quarantined → Probationary → Trusted) for replay-gated reuse on future runs. Replaces the old hand-rolled pattern library as the primary path for new tools — see R31 below. |
Orchestration Engines
AWP provides two orchestration engines. The choice determines how agents coordinate:
DAG Engine (default, A0-A1): Static graph of agents. Dependencies defined in YAML. Topological execution.
orchestration:
engine: dag
graph:
- id: planner
agent: planner
- id: researcher
agent: researcher
depends_on: [planner]
Delegation Loop Engine (A2-A4): A manager agent dynamically spawns ephemeral workers. Workers receive generated instructions, skills, and tool configurations. The loop iterates until the manager declares completion or budget is exhausted.
orchestration:
engine: delegation_loop
delegation_loop:
manager: agents/manager
models:
manager: null # --manager-model CLI flag
worker: null # --worker-model CLI flag
budget:
max_loops: 10
max_total_workers: 20
max_wall_time: 300
max_depth: 2 # Recursive submanager depth cap (default 2)
max_concurrent_submanagers: 3 # Max submanagers running at once
max_total_submanagers_per_run: 6 # Hard cap on submanagers per run
max_workers_per_iteration: 6 # Per-iteration fan-out cap (default 6)
max_rejected_completions: 2 # Completion-retry circuit breaker (default 2)
worker_policy:
enforced:
sandbox: {type: subprocess, max_memory_mb: 512}
forbidden_tools: [shell.execute, file.write_outside_workspace]
manager_controlled:
- instructions
- skills
- tools_allowed
- output_contract
- codemode.enabled
- codemode.tool_creation
- temperature # Manager sets per-worker LLM temperature
# NOTE: shell.execute is forbidden — workers MUST use code.execute instead.
# For non-codemode terminal access, use terminal.execute (sudo-free shell).
# The manager should include code.execute in tools_allowed for codemode workers.
termination:
enabled: true
window: 3
min_confidence_delta: 0.05
validation:
deterministic: {always: true}
llm: {enabled: true, skip_when_confidence_above: 0.95}
history:
rolling_summary: true
full_results_window: 3
logging:
format: dual
persist_artifacts: true
# Sibling-coordination blackboard (default: true). When enabled,
# every manager run gets an append-only JSONL board and workers
# receive the `board.post` / `board.read` run-scoped tools.
blackboard_enabled: true
# Hierarchical Context Digest (HCD). Per-level deterministic summary
# of each manager iteration, injected into the next prompt as
# ## MY DIGEST + ## CHILDREN DIGESTS so deep delegation graphs
# (depth >=3) keep context without overflowing the prompt.
digest_enabled: true
digest_mode: deterministic # "deterministic" only; "llm" reserved
digest_max_depth: 1 # children inlined in the prompt
# Auto-Curation (Baustein 4). When true, a deterministic curator
# writes reusable knowledge (tool recipes, cross-confirmed facts,
# failed-delegation antipatterns) into <workflow_dir>/memory/ at
# run end, and the next run's root manager is primed with a
# `## PRIOR RUN MEMORY` block on its first iteration.
auto_curation_enabled: true
# LLM Call Tracing. When enabled, every LLM API call (manager + workers)
# is persisted as llm_trace/call_NNN.json with full messages, response,
# token usage, and latency. Disabled by default to avoid I/O overhead.
trace_enabled: false
# Optional selective-forget blacklist for submanager state inheritance.
# Keys listed here are stripped before being passed to child runs.
# forbidden_inheritance_keys: [secret_token, raw_dump]
Key concepts:
- Delegation Envelope: Manager generates instructions + skills + tools config + temperature for each worker
- Budget System: Hard limits on loops, workers, tokens, wall time. Required at A2+. Includes
max_workers_per_iteration(default 6) — a per-DELEGATE fan-out cap. Over-cap dispatches are trimmed pre-spawn and the overflow is surfaced to the manager viastate["_deferred_workers"]so it must merge subtasks or dispatch in a later iteration. - Terminal Status Contract: Every run ends with exactly one of
{complete, partial, failed, aborted}. Cap-forced exits (defect_category_cap,plan_loop,forced_convergence,max_total_tokens,max_total_workers,max_wall_time,max_loops) are alwayspartial— nevercomplete. Hard errors arefailed. Signal-driven or abrupt process exits areaborted. Therun.completeevent +run_completion.jsonare emitted on every exit path via atry/except/finally+SIGTERM/SIGINThandler finalizer. - Safety Envelope: Immutable security constraints the manager cannot override. Required at A3+.
- Two-Tier Validation: Deterministic (schema, confidence) + LLM semantic (does result address task?)
- Stall Detection: Auto-stop when confidence stops improving. Also includes
worker-level tool-call repeat-loop detection: if a worker emits 3 identical
tool calls in a row, the runner forces a final round with
tool_choice="none"so the worker completes gracefully instead of looping forever on a broken tool. - Dual Logging: JSON (machines) + Markdown (humans) in workspace/runs/
- Fan-Out: Multiple workers per iteration, executed in parallel
- Recursive Delegation (A4): Workers can be auto-promoted to submanagers that own their own delegation loop. Promotion is decided by a deterministic complexity scorer (subtask word length, presence of keywords like "research"/"validate", deliverable count, declared priority) — only subtasks scoring ≥3 are promoted, with bonuses for collective fan-outs and a 50% promotion cap so the parent budget cannot be blown.
- Budget Reservation Model (A4): When a submanager is spawned, capacity is
pre-charged against the parent budget via
allocate_child(fraction), so concurrent siblings see a shrinking pool and the no-over-commit invariant always holds.reclaim_child()refunds unused capacity when the sub-run finishes. This is what gives A4 its termination guarantees even under parallel recursive delegation. - Submanager state inheritance (A4): Submanagers inherit the parent's
full state dict by default (children are no longer "born blind").
Precedence when resolving the inherited slice:
- Explicit per-envelope
inherited_state_keyswhitelist wins (legacy). - Otherwise, inherit all keys except those in
forbidden_inheritance_keys(per-envelope or atdelegation_loop.forbidden_inheritance_keysin the workflow config — addforbidden_inheritance_keys: [secret_token, ...]underdelegation_loopto strip sensitive/oversized keys globally). - If neither is set, the full parent state is passed through.
- Explicit per-envelope
- Sibling coordination via blackboard (A2-A4): Every manager run owns
a run-scoped append-only JSONL board at
<workspace>/blackboard/<manager_run_id>.jsonl. Workers get two builtin tools —board.post(topic,payload) andboard.read(topic?,since?) — to broadcast partial findings, dead ends, and de-duplication hints to their siblings. Before every manager iteration, new entries are injected into the manager prompt as a## SIBLING SIGNALSblock (silent when empty). Submanagers get their OWN blackboard (different run id) and never share signals with the parent. Controlled bydelegation_loop.blackboard_enabled(defaulttrue). Workers do NOT need to listboard.post/board.readintools_allowed— the runtime injects them automatically when the feature is on. - Hierarchical Context Digest (A2-A4): Every manager run owns a
per-level digest that compresses each iteration into a compact,
deterministic record (goal, key_facts from confidence>=0.8 workers,
open_questions from confidence<0.7 workers, confidence_trend, child
digest SHAs). Digests live content-addressed at
<workspace>/runs/<run_id>/digest/<sha>.json. Before every manager iteration the runner injects a## MY DIGESTblock (this level's current digest) and a## CHILDREN DIGESTSblock (up todigest_max_depthinlined submanager digests); deeper layers stay reachable via the run-scopeddigest.fetchtool. When the digest is active the rolling history detail window auto-caps at 3 iterations so the prompt spend flows into the structured digest. Submanagers receive the parent's current digest sha via the reserved__parent_digest_shainherited-state key, and their final digest sha flows back to the parent and is folded into its next digest'schild_digest_hashes. Controlled bydelegation_loop.digest_enabled(defaulttrue),digest_mode("deterministic"only;"llm"raises NotImplementedError), anddigest_max_depth(default1). Workers do NOT need to listdigest.fetchintools_allowed— the runtime injects it automatically when the feature is on. - Auto-Curation & Prior-Run Memory (A2-A4): When
delegation_loop.auto_curation_enabledis true (default), a deterministic Curator runs at the end of every root-manager run and writes reusable knowledge into<workflow_dir>/memory/:memory/tools/<recipe>.md— recipes for every dynamic tool created this run, deduped byname + content_hash(spec); same name with a new hash appends a## v{n}section.memory/facts/YYYY-MM-DD.md— cross-confirmed key facts that appeared in>=2digests across the run's digest hierarchy.memory/antipatterns/<sha>.md— redundant delegation signatures, worker errors, and worker confidence<0.3. On the next run,Curator.read_prior_memory(workflow_dir)reads these three directories and the runner injects a compact## PRIOR RUN MEMORYblock (capped ~3000 chars) into the root manager's very first prompt. Submanagers do NOT receive the block directly — they inherit priors via the parent digest sha to avoid amplifying prompt cost with depth. Setauto_curation_enabled: falseto disable both writeback and priming.
- Content-aware redundancy guard (A2-A4): The delegation signature used
to veto duplicate dispatches now hashes worker instructions together
with a canonical JSON of the context the envelope references (
context,input_context, or the set ofinherited_state_keys). Identical instructions run against different input contexts are no longer falsely flagged as redundant. Envelopes that carry no context hash identically to the legacy signature, so existing workflows are unaffected. - Submanager output merging (A4): Each submanager writes into its own
output/<sub_run_id>/sandbox under the parent workflow dir. On completion the parent runner merges those files back into the parent_output_dir; name collisions are renamed<submanager_name>__<filename>. The merged filenames are attached to the child result as_merged_files. - Completion gates: before accepting a
COMPLETEdecision the runner enforces (1) a placeholder scanner overfinal_resultand text deliverables (TODO,XX%, template stubs likeyour/field_name), (2) a file-validator gate rejecting 1x1 PNGs and files< 512 B, (3) a deliverable-presence gate that refuses completion when the task text implies an artifact (image / pdf / csv / ...) and_output_diris empty, and (4) the critique-score gate (min_score_to_complete, default0.6). Any gate firing forces another iteration with a targeted repair hint in state. When a task-implied deliverable already exists on disk, the critic's narrative pessimism is overruled (ground-truth bypass). - Convergence detector: the loop force-completes with
reason: forced_convergencewhen confidence delta across the last two iterations is< 0.05or three consecutive iterations produce identicalkey_findings. A sorted instruction-hash signature detects redundant re-delegation and pushes the manager into DIAGNOSE instead of re-issuing the same subtasks.
When generating a delegation loop workflow:
- The manager agent gets a full agent.awp.yaml with SYSTEM_PROMPT.md
- Workers are ephemeral — no YAML files, configured by the manager at runtime
- The manager's system prompt must instruct it to use the DELEGATE/COMPLETE/FAIL decision format
Dynamic Tool Creation
Agents with Code Mode can create new MCP tools at runtime via sdk.tools.create().
CRITICAL: When generating a delegation loop workflow that uses Code Mode or dynamic tools, you MUST:
- Set
dynamic_tools.enabled: truein workflow.awp.yaml (otherwise tool creation silently fails) - Set
dynamic_tools.persist: trueto save generated tools as JSON files for debugging - Include
code.execute(NOTshell.execute) in the workers'tools_allowed—shell.executeis inforbidden_toolsby default and will be silently removed - Set
tool_creation: truein the codemode envelope (not justenabled: true)
Configuration in workflow.awp.yaml:
dynamic_tools:
enabled: true # MUST be true for tool creation to work
persist: true # Save tools as JSON in workspace/dynamic_tools/
max_total: 20
allowed_namespaces:
- scoring # compute only (default)
- analysis # compute only (default)
- name: api_client # grant network access
capabilities: [compute, network]
network_allowlist: [api.example.com] # optional host restriction
- name: data_proc # grant filesystem access
capabilities: [compute, filesystem]
code_review: true # Log all generated code for debugging
Namespace Capabilities (NC1-NC3): Each namespace can be granted additional capabilities beyond pure computation. Plain string entries default to compute only. Capability objects can grant:
compute: Pure Python (always implicit)network: Unlocksrequests,httpx,urllib,http,socketfilesystem: Unlockspathlib,glob,shutil,tempfile
Always denied (cannot be unlocked): os, subprocess, sys, ctypes, importlib, signal, multiprocessing.
In agent.awp.yaml:
capabilities:
codemode:
enabled: true
tool_creation: true
tool_creation_namespace: scoring
max_tools: 10
In the delegation loop, the manager can enable tool creation for workers:
{
"codemode": {
"enabled": true,
"tool_creation": true,
"tool_creation_namespace": "scoring"
}
}
Tools with API Key Access (required_secrets):
Dynamic tools can declare required_secrets to access API keys from the workflow's secrets store.
Available secret key names (not values) are shown to the worker automatically.
The secrets are injected as a _secrets dict variable in the sandbox:
{
"name": "dynamic.api_fetch",
"description": "Fetch data from external API",
"required_secrets": ["API_KEY"],
"parameters": {"type": "object", "properties": {"url": {"type": "string"}}},
"code": "import urllib.request, json\ndef handler(*, url):\n api_key = _secrets.get('API_KEY', '')\n req = urllib.request.Request(url, headers={'Authorization': f'Bearer {api_key}'})\n resp = urllib.request.urlopen(req, timeout=10)\n return {'ok': True, 'status': 200, 'data': json.loads(resp.read()), 'error': None}"
}
File Output from Dynamic Tools and code.execute:
Generated tool code and code.execute calls have access to two pre-defined path variables:
_workspace_dir— path to workspace/ (intermediate files)_output_dir— path to output/ (final deliverables: charts, CSVs, reports)
Use open() (builtin) and string concatenation for paths. Do NOT import os or pathlib.
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
def handler(*, data, filename):
plt.figure()
plt.plot(data)
plt.savefig(_output_dir + "/" + filename, dpi=150)
plt.close()
return {"ok": True, "status": 200, "data": {"file": _output_dir + "/" + filename}, "error": None}
Tools are persisted in workspace/runs/{run_id}/artifacts/tools/ and workspace/dynamic_tools/. Each persisted tool JSON contains: name, description, parameters, code, required_secrets, provenance (creator, timestamp).
Code Execution in Workers
Workers with codemode.enabled: true should use the code.execute tool for running Python code.
Do NOT use shell.execute — it is in forbidden_tools by default.
The manager should include code.execute in the delegation envelope tools_allowed:
{
"tools_allowed": ["code.execute", "file.read", "file.write"],
"codemode": {"enabled": true}
}
In code.execute, the variables _workspace_dir and _output_dir are automatically available.
The runtime also auto-injects a small standard preamble into every code.execute snippet so common modules do not need to be imported in every call:
- Pre-imported modules:
json,pathlib,re,math,datetime, plusos/sys/builtins(aliased as_os,_sys,_builtins) - Pre-injected helpers:
_workspace_dir,_output_dir,_secrets,_ensure_dir(),_output_file(),_input_file(),_list_files(),_verify_png() - Text-mode
open(path, "w")is auto-upgraded to binary mode if the caller writesbytes(preventsTypeError: write() argument must be str, not bytesfrom LLM-written snippets).
Note: within a single worker, code.execute calls now share a warm, persistent Python subprocess by default — variables, imports, and helper functions defined in one call ARE still live in the next. Heavy imports (numpy, pandas, matplotlib) are paid once per worker, not once per call. Passing state via files under _workspace_dir is still correct (and required for state shared BETWEEN workers), but generated workflows no longer need to reload DataFrames or re-import modules inside every snippet. Each worker has its own namespace; a crash inside the warm subprocess triggers an automatic restart with a silent history replay so the namespace feels preserved.
Repair workers continue the prior worker's context. When the runtime dispatches a worker whose id ends in _repair, _retry, _vN, _strict, _final, _runN, or _subtask_N, it re-enters the original worker's warm namespace and prepends a REPAIR MODE block to the worker's system prompt. Generated workflows MUST NOT assume a repair worker starts from a blank state; reload or re-import only when strictly necessary. The manager can force a clean slate per-dispatch via envelope field fresh_worker: true — do not add this flag by default, it defeats the α-fix and wastes tokens.
Auto-emergent tools. When N=3 distinct workers execute the same shape of code.execute snippet (same AST skeleton, differing only in literals / identifier names), the runtime auto-synthesizes a generalized tool via DynamicToolFactory, persists it at shared/dynamic_tools/dynamic.induced_<hash6>.json, and exposes it through tool.list for later workers. N=3 is a hardcoded constant — no config knob. Generated workflows should NOT fight induction: do not suppress code.execute recording, do not normalize worker ids to reduce diversity, and do not assume tool.list returns only LLM-authored tools. Induced tools satisfy rules DT1-DT8 exactly like explicit tool.create output.
Dynamic Skill Generation
In the delegation loop, the manager generates domain-specific skills (Markdown) for each worker. Each dynamically generated skill MUST follow the same structure as project skills:
{
"skills": [
"# Market Analysis\n\n## Purpose\nEvaluate market opportunity using quantitative frameworks.\n\n## Concepts\n- **TAM**: Total addressable market — the full revenue opportunity.\n- **SAM**: Serviceable addressable market — the segment you can reach.\n- **SOM**: Serviceable obtainable market — the realistic short-term capture.\n\n## Rules\n1. Always calculate all three tiers (TAM → SAM → SOM).\n2. State the source and year for every market-size figure.\n3. Express SOM as a percentage of SAM with justification.\n\n## Procedure\n1. Define the market boundaries.\n2. Calculate TAM from industry reports.\n3. Narrow to SAM based on geographic and segment filters.\n4. Estimate SOM based on competitive positioning.\n\n## Examples\n### Example 1: SaaS CRM\n**Input:** Global CRM market, mid-market segment, NA region\n**Output:** TAM $65B, SAM $12B, SOM $180M (1.5% — new entrant)\n"
]
}
Required sections in every dynamic skill: Purpose, Concepts, Rules. Optional sections: Procedure (for multi-step tasks), Examples (when correct application is non-obvious).
Skills are persisted in workspace/runs/{run_id}/artifacts/skills/.
STRICT RULES
These rules define validation requirements for AWP workflows. Rules marked (recommended for Python) apply to the Python reference implementation but may be adapted for other platforms.
- R1:
workflow.nameMUST match the workflow directory name. - R2: All agent IDs MUST be
snake_case(lowercase letters, digits, underscores). - R3 (recommended for Python): Every
agent.pySHOULD define a class namedAgentthat extendsStandaloneAgent(for standalone runtime) orAWPAgent(for other platforms). - R4 (recommended for Python): The
Agent.nameproperty MUST return the same string as the agent ID in the graph. - R5: Every agent in the graph MUST have a corresponding directory under
agents/. - R6: Every agent directory MUST contain
agent.awp.yamlandagent.py. - R7: Every agent MUST have
workflow/instructions/SYSTEM_PROMPT.md. - R8: Every agent MUST have
workflow/prompt/00_INTRO.md. - R9: Every agent MUST have
workflow/output_schema/output_schema.json. - R10: Every agent MUST have
workflow/output_schema_desc/output_schema_desc.json. - R11:
depends_onMUST only reference agent names defined in the same graph. - R12: The agent graph MUST be a DAG (no cycles).
- R13:
share_outputfields MUST match keys in the agent's output schema. - R14: Tool names in
tools.allowedMUST reference registered MCP tools. When tool implementation mode is enabled, built-in tools MUST have generated implementations inmcp/. When disabled, built-in tools are assumed to be provided by the target runtime. - R15: If
tools.executeis false,tools.allowedMUST be empty or omitted. - R16:
execution.modeMUST be one of:sequential,parallel,conditional. - R17: All output schemas MUST include a
confidencefield (number, 0.0-1.0). - R18: All
output_schema.jsonfiles MUST be valid JSON Schema draft-07 with"type": "object"at the root. - R31 (delegation loop, runtime-enforced): Manager PLAN decisions MUST include a non-empty
tool_manifestper subtask. Each entry declares a capability and one of three modes:reuse(setpattern_idfrom the seeded pattern table),synthesize(setarchetype_id∈ {compute, fetch, parse, transform, render, probe} +recipe_paramsmatching the archetype's required params — PREFERRED for new tools), orgenerate(last resort, requires anassumptionslist). Workers instantiating archetype-based tools MUST forwardarchetype_id+recipe_paramsviadynamic.create_toolmeta so the runtime can build the deterministic skeleton and auto-capture the recipe.
Workflow Generation Phases
Phase 0: Intelligent Task Analysis
CRITICAL: Before asking any questions, analyze the user's task description and silently determine the optimal architecture. This analysis drives which questions you ask and which defaults you recommend. Do NOT present this analysis to the user — use it to make smart recommendations in Phase 1.
Step 0a: Pattern Detection
Read the task description and classify it into the best-fit design pattern:
| Signal in task description | Recommended Pattern | Autonomy |
|---|---|---|
| "pipeline", "step by step", "then", sequential process | Pipeline | A0-A1 |
| "analyze multiple", "compare", "parallel", batch items | Fan-Out / Fan-In | A1 |
| "if ... then", "depending on", "triage", "route" | Conditional Branching | A1 |
| "research", "investigate", "deep dive", open-ended | Manager-Worker | A2 |
| "score", "evaluate", "rate", configurable criteria | Tool Builder | A3 |
| "complex", "multi-faceted", "comprehensive", many dimensions | Self-Organizing Team | A4 |
Step 0b: Autonomy Level Detection
Apply the minimum autonomy principle — start at A0 and only increase if the task demands it:
Is the number of steps known upfront?
YES → Are there conditional branches or parallel paths?
NO → A0 Prescribed (simple pipeline)
YES → A1 Adaptive (DAG with conditions)
NO → Does the task need runtime tool/skill creation?
NO → A2 Delegating (delegation loop)
YES → Is the task multi-dimensional with sub-teams?
NO → A3 Self-Tooling (tool creation)
YES → A4 Self-Organizing (recursive delegation)
Step 0c: Engine Selection
| Autonomy | Engine | Rationale |
|---|---|---|
| A0-A1 | dag |
Known steps, predictable flow |
| A2-A4 | delegation_loop |
Steps emerge at runtime |
| Mixed | DAG with embedded delegation_loop node | Predictable outer, adaptive inner |
Step 0d: Capability Planning
Based on the task, pre-plan:
- Agents — How many? What roles? (Fewer is better — merge roles that don't justify separation)
- Tools — Which MCP tools? (Only what's needed — don't add tools "just in case")
- Skills — Does the task need domain knowledge? (Generate skills only for specialized domains)
- Memory — Is cross-session persistence needed? (Most tasks don't need it)
- Code Mode — Does any agent need >5 tool calls? (If yes, Code Mode saves tokens)
- Budget — For A2+: estimate loops, workers, wall time from task complexity
Carry this analysis into Phase 1 — it determines your recommendations.
Phase 1: Requirements Gathering (Interactive Questionnaire)
IMPORTANT: Before generating anything, you MUST present the user with a structured questionnaire. Do NOT skip this phase. Even if the user gave a detailed description, there are always decisions that need clarification. Present ALL questions at once in a single message so the user can answer them together.
For every question: provide concrete suggestions based on what the user already told you,
mark one as the recommended default (with ← recommended), and always
include an "Other" option so the user can specify something not listed.
If the user already answered a question clearly in their initial request, pre-fill the
answer and mark it with ✓ (from your description) — but still show it so the user
can correct it.
Present the following questionnaire:
1. Workflow Basics
1.1 Name: What should the workflow be called?
Suggestions:
{suggest 2-3 snake_case names based on user's description}Other: ___
1.2 Description: What should the workflow do in one sentence?
Suggestion:
{1-sentence summary based on user's description}Other: ___
1.3 Prompt Language: In which language should the system prompts and outputs be?
a) English ← recommended b) Other: ___
2. Agents & Roles
2.1 Which agents should the workflow have? Each agent has a clearly defined role.
Suggestions (based on your description): {list each suggested agent with id, role name, and 1-line description}
Should agents be added, removed, or renamed? Other: ___
2.2 Execution Order: How should the agents be executed?
a) Sequential (one after another in fixed order) ← recommended b) Parallel (independent agents simultaneously) c) Conditional (agents are skipped depending on results) d) Other: ___
2.3 Data Flow: Which data does each agent pass to the next?
Suggestion: {show suggested data flow: agent_a → [fields] → agent_b → [fields] → agent_c}
Changes? Other: ___
3. LLM Configuration
Note: LLM models are not specified in the workflow. They are configured at startup via the Run-Wizard (
awp run) or the environment variableLLM_MODEL. This allows the user to switch models at any time without modifying the workflow.
3.1 Temperature: How creative should the agents respond?
a) Low (0.1) — factual, precise ← recommended for analysis/research b) Medium (0.3) — balanced c) High (0.7) — creative, variable d) Different per agent (please specify) e) Other: ___
4. Tools, Code Mode & Capabilities
4.1 Which tools do the agents need?
Suggestions per agent: {for each agent, list suggested tools with brief explanation, e.g.:}
{agent_id}:web.search(web search),memory.write(save results){agent_id}: no tools (pure LLM agent)Changes? Other: ___
Note: Advanced tool-calling options (
tool_choice,parallel_calls) can be configured per agent inagent.awp.yamlundercapabilities.tools. Defaults are sensible for most workflows — only adjust when needed.
4.2 Generate tool implementations? Should working implementations
be generated for the tools (e.g., web.search with DuckDuckGo, memory.* with
file storage)? Without this, tools are only placeholders that an AWP runtime must provide.
a) Yes — generate all used tools as MCP implementations ← recommended for Standalone b) No — only tool declarations, runtime provides them ← recommended for AWP Runtime c) Only implement specific tools (please specify) d) Other: ___
4.3 Code Mode (Alternative Tool Execution)? Instead of calling tools individually, the agent writes code against a typed SDK. Reduces token consumption and LLM roundtrips when using many tools.
a) No — classic tool calls ← recommended for simple workflows b) Yes — agent writes TypeScript against SDK ← recommended for >5 tools c) Yes — agent writes Python against SDK d) Other: ___
4b. API Keys & Secrets
4b.1 Do the tools need API keys or credentials? Secrets are provided via
secrets.yaml (gitignored) and securely injected into tools — the LLM
never sees them.
Suggestions based on the selected tools: {for each tool that typically needs API keys, e.g.:}
web.search: Optional — DuckDuckGo (free, no key) or premium API (Google, Bing, SearXNG)http.request: Depends on target API — Bearer Token, API Key, etc.- Custom tools: please list keys
a) No API keys needed ← recommended for getting started b) Yes — the following keys are needed: ___ c) Other: ___
5. Output Format & Schemas
5.1 Output format of the agents:
a) JSON (structured, machine-readable) ← recommended b) Markdown (free text, human-readable) c) Mixed (some JSON, some Markdown — please specify) d) Other: ___
5.2 Which fields should each agent output?
Suggestions: {for each agent, list suggested output fields with types} (Note:
confidence(0.0-1.0) is automatically added — AWP required field.)Changes? Other: ___
6. Memory & Persistence
6.1 Should the workflow have long-term memory? (Store results across sessions)
a) No — each run is independent ← recommended for simple workflows b) Yes — MEMORY.md for cross-session insights c) Yes — with daily logs and MEMORY.md ← recommended for recurring tasks d) Other: ___
7. Skills & Domain Knowledge
7.1 Does the workflow need specific domain knowledge? (Injected as SKILL.md into prompts)
a) No b) Yes — please describe topic/domain: ___ c) Suggestion:
{suggest a skill based on user's domain, e.g.: "industry-regulations"}d) Other: ___
8. Output Directory & Project Structure
8.1 Where should the workflow be saved?
a)
{suggest path based on context, e.g.: ~/projects/{workflow_name}/}b) Current directory c) Other: ___
9. Target Platform
9.1 Where should the workflow run?
a) Standalone (Python) — local execution with
awp-agents← recommended for getting started b) Cloudflare Workers — serverless Edge deployment (TypeScript) c) Other: ___
10. Autonomy Level
10.1 Which AWP Autonomy Level?
a) A0 Prescribed — static DAG, fixed agents and tools ← recommended for getting started b) A1 Adaptive — conditions, loops, fan-out ← recommended for most workflows c) A2 Delegating — manager spawns workers dynamically (budget required) d) A3 Self-Tooling — agents create tools at runtime (safety envelope required) e) A4 Self-Organizing — recursive delegation, budget distribution f) Other: ___
Note: Communication, Memory, Observability, and Security are features that can be used at any level.
11. Other
11.1 Are there any additional requirements, constraints, or requests?
e.g., timeouts, error handling, security requirements, special data sources, target audience for output, ...
11b. Orchestration Engine (if A2+ selected)
Which Orchestration Engine?
a) DAG — Static graph, fixed agents ← for A0-A1
b) Delegation Loop — Manager spawns workers dynamically ← recommended for A2+
c) Hybrid — DAG with embedded Delegation Loop
If Delegation Loop:
- Budget: Max Loops? [10] Max Workers? [20] Max Wall Time? [300s]
- Context Budget: Total chars? [64000] Min per entry? [4000] Preview chars? [2000]
(Auto-detect divides total budget equally among workers. Large results spill to
workspace/context/ files with inline preview. Tune up for data-heavy workflows.)
- Safety Envelope active? [Yes, required from A3]
- LLM Validation? [Yes / No]
- Stall Detection? [Yes, recommended]
After receiving answers: Analyze the responses, resolve any conflicts, and proceed to Phase 2. If answers are ambiguous or contradictory, ask targeted follow-up questions (but not another full questionnaire). If the user says "defaults" or "passt so", use all recommended defaults.
Phase 2: Workflow-Plan (From Abstract to Concrete)
IMPORTANT: Before generating any files, you MUST create a structured workflow plan and present it to the user for confirmation. This plan bridges the gap between the abstract idea and the concrete implementation. It ensures that the user understands exactly what will be built before a single file is created.
The plan follows a top-down refinement -- starting with the high-level goal and progressively adding detail until every file, field, and dependency is specified.
Present the plan as a single, structured document:
Step 1: Goal Statement (Abstract)
Summarize the workflow's purpose in 2-3 sentences. What problem does it solve? What is the expected input and output? This is the "elevator pitch" for the workflow.
Goal: {what the workflow does, in plain language} Input: {what the user provides to start the workflow} Output: {what the user gets at the end}
Step 2: Agent Roles & Responsibilities (Conceptual)
For each agent, describe its role in non-technical terms. Focus on what it does, not how. Think of this as a team of people -- what is each person's job?
| Agent | Role | Receives from | Delivers to |
|---|---|---|---|
{id} |
{role in plain language} | {upstream agent or "user input"} | {downstream agent or "final output"} |
Step 3: Data Flow & Contracts (Architectural)
Now make the data flow concrete. Define what data moves between agents:
User Input
│
▼
[agent_a] ──── produces: {field_1, field_2, confidence}
│ shares: {field_1, field_2}
▼
[agent_b] ──── receives: {field_1, field_2}
│ produces: {field_3, field_4, confidence}
│ shares: {field_3}
▼
[agent_c] ──── receives: {field_3}
produces: {final_output, confidence}
For each shared field, specify the type and a one-line description.
Step 4: Tool & Capability Mapping (Technical)
Map each agent to its concrete capabilities:
| Agent | Tools | Memory | Skills | Reasoning |
|---|---|---|---|---|
{id} |
{tool.fqn}, ... |
{yes/no, tier} | {skill name or none} | {enabled/disabled} |
Step 5: File Manifest (Implementation)
List every file that will be generated, grouped by agent:
{workflow_name}/
workflow.awp.yaml
secrets.yaml.example (if secrets needed)
mcp/
{tool_file}.py ← {purpose}
skills/
{skill_name}/SKILL.md ← {purpose}
agents/
{agent_id}/
agent.awp.yaml
agent.py
workflow/
instructions/SYSTEM_PROMPT.md
prompt/00_INTRO.md
output_schema/output_schema.json
output_schema_desc/output_schema_desc.json
...
State the total file count and the target autonomy level.
Step 6: Validation Preview
List which of the 32 rules (R1-R32) apply and confirm they will be satisfied:
Autonomy Target: A{N} {Level Name} Applicable Rules: R1-R{max} (all satisfied by this plan, up to R30 if evaluation enabled) Special Considerations: {any edge cases, e.g., conditional execution, cyclic risk}
Step 6b: Delegation Loop Plan (if engine is delegation_loop)
If the orchestration engine is delegation_loop, the plan must include:
- Manager agent role and system prompt strategy
- Expected iteration flow (Phase 1: tool creation, Phase 2: analysis, Phase 3: synthesis)
- Budget allocation
- Worker types the manager will spawn (with example skills)
- Termination strategy
Step 7: Plan Validation Menu
After presenting the plan (Steps 1-6), you MUST present a dynamic validation menu
as a set of multiple-choice questions. Each question targets one key design decision
from the plan. For every question: pre-select the answer that matches your plan
(marked with →), provide 2-4 concrete alternatives, and always include a free-text
option. The user validates by confirming or correcting each point.
IMPORTANT: The questions must be specific to the generated plan -- not generic. Use actual agent names, field names, tool names, and values from the plan. The menu is a focused checklist, not a second questionnaire.
Plan Validation -- please check the following items:
V1. Agent Count and Roles
→ a) {N} Agents:
{agent_1}({role_1}),{agent_2}({role_2}), ... ← from the plan b) Add agent: e.g.,{suggested_extra_agent}({suggested_role}) c) Remove agent: which one? ___ d) Rename agent: which one? ___ e) Other: ___
V2. Execution Order
→ a) {mode from the plan}:
{agent_1}→{agent_2}→{agent_3}← from the plan b) {alternative_mode}: {concrete alternative, e.g., agent_1 + agent_2 parallel, then agent_3} c) Conditional: {suggest a condition, e.g., "agent_2 only if agent_1.confidence > 0.7"} d) Other: ___
V3. Data Flow Between Agents
→ a) As planned:
{agent_1}shares{field_1}, {field_2}→{agent_2}shares{field_3}→{agent_3}← from the plan b) Add field: which one, for which agent? ___ c) Remove field: which one? ___ d) Other: ___
V4. Tools Per Agent
One line for each agent: → a)
{agent_1}:{tool_1},{tool_2}← from the plan → b){agent_2}: no tools ← from the plan → c){agent_3}:{tool_3}← from the plan Changes? Add/remove tools? ___
V5. Output Fields Per Agent
Planned output fields for each agent: → a)
{agent_1}:{field_1}(string),{field_2}(array),confidence(number) ← from the plan → b){agent_2}:{field_3}(object),confidence(number) ← from the plan Change/add/remove fields? ___
V6. Autonomy Level
→ a) A{N} {Level Name} ← from the plan b) Lower: A{N-1} {Name} (removes: {what is dropped}) c) Higher: A{N+1} {Name} (adds: {what is gained}) d) Other: ___
V7. Memory & Persistence
→ a) {planned memory configuration, e.g., "No memory" or "MEMORY.md + daily logs"} ← from the plan b) {alternative, e.g., "Add memory: MEMORY.md for cross-session insights"} c) {alternative, e.g., "Daily logs only, no long-term memory"} d) Other: ___
V8. Code Mode
→ a) {planned Code Mode, e.g., "No — classic tool calls"} ← from the plan b) {alternative, e.g., "Yes — TypeScript Code Mode with SDK"} c) {alternative, e.g., "Yes — Python Code Mode with SDK"} d) Other: ___
V9. Target Platform
→ a) {planned platform, e.g., "Standalone (Python)"} ← from the plan b) {alternative, e.g., "Cloudflare Workers (TypeScript)"} c) Other: ___
V10. Tool Implementations
→ a) {planned mode, e.g., "Yes -- all tools as MCP implementations"} ← from the plan b) {alternative, e.g., "No -- declarations only, runtime provides them"} c) Only implement specific ones: which? ___ d) Other: ___
V11. Overall Assessment
→ a) Plan is correct -- please generate b) Adjust plan (please correct the affected items above) c) Discard plan and re-plan d) Questions about the plan: ___
After receiving validation answers:
- If V11 = a) (approved): proceed directly to Phase 3 (file generation).
- If V11 = b) (adjustments): apply the corrections from V1-V10, re-present only the changed sections of the plan (not the full plan), and show an updated validation menu with only the changed questions.
- If V11 = c) (discard): return to Phase 1 or Phase 2 Step 1.
- If V11 = d) (questions): answer the questions, then re-present V11.
Iterate until the user selects V11 = a). Do NOT generate any files until the plan is explicitly approved. The plan is the contract between AI and user.
Phase 3: Generate the Project
Generate files in this order:
Step 1: Workflow Manifest
Create {workflow_dir}/workflow.awp.yaml with:
projectsection (name, version, description).graphsection (all agents with depends_on and share_output).executionsection (mode, timeouts, error handling).statesection (persistence, sharing strategy).- Additional sections as needed:
memory,communication,observability,security(cross-cutting features, available at any autonomy level). - If quality scoring is desired, add
observability.evaluationwith metrics, thresholds, and optional retry policy. See the evaluation section below. loggingsection.settingssection (LLM models, runtime config).
Use the template at templates/workflow.awp.yaml as a starting point.
Step 2: Agent Configurations
For each agent, create {workflow_dir}/agents/{agent_id}/agent.awp.yaml with:
agentsection (name, description).llmsection (model, temperature, reasoning).toolssection (execute flag, max_calls, allowed list).preprocessor,vision,memory,debugsections as needed.
Use templates/agent.awp.yaml (minimal) or templates/agent-full.awp.yaml (full-featured).
Step 3: Agent Implementations (Platform-Specific)
For each agent, create {workflow_dir}/agents/{agent_id}/agent.py.
AWP is platform-agnostic. The agent.py file varies by target runtime.
Choose the appropriate adapter based on the target platform:
| Platform | Adapter | Generated Files |
|---|---|---|
| Standalone (awp-agents) | adapters/standalone.md |
agent.py (Python) |
| Cloudflare Workers | adapters/cloudflare-dynamic-workers.md |
src/index.ts, wrangler.toml (TypeScript) |
Default (Standalone): Use templates/agent.py which inherits from
awp.runtime.agent.StandaloneAgent. This makes every generated agent fully
functional out of the box — it can load its own config, build prompts, call
the LLM, handle tools, and enforce output contracts without any additional code.
Mandatory rules for generated agent.py (Standalone adapter):
- The
Agentclass MUST inherit fromStandaloneAgent(notAWPAgent). - The
__init__MUST accept optionalagent_dir,workflow_dir,llm, andtool_registryparameters with auto-detection defaults viaPath(__file__). - The agent MUST be instantiable with no arguments:
Agent()works standalone. - Do NOT override
run()with stub logic — the inheritedStandaloneAgent.run()provides the complete LLM pipeline. Only override when the agent needs custom pre-/post-processing. - Include commented-out override hooks (
run,_build_system_prompt,_build_user_message) so users know what they can customise.
Read the adapter file in skill/adapters/ for platform-specific instructions,
then generate agent.py accordingly. Third-party platforms can provide their
own adapter files following the same pattern.
Step 4: System Prompts
For each agent, create {workflow_dir}/agents/{agent_id}/workflow/instructions/SYSTEM_PROMPT.md:
- Clear role description.
- List of responsibilities.
- Available tools (if any) with usage instructions.
- Output format instructions referencing the output schema.
Use templates/SYSTEM_PROMPT.md as a starting point.
Step 5: Intro Prompts
For each agent, create {workflow_dir}/agents/{agent_id}/workflow/prompt/00_INTRO.md:
- Brief task introduction.
- Context about what input the agent receives.
Use templates/00_INTRO.md as a starting point.
Step 6: Output Schemas
For each agent, create:
{workflow_dir}/agents/{agent_id}/workflow/output_schema/output_schema.json-- JSON Schema draft-07.{workflow_dir}/agents/{agent_id}/workflow/output_schema_desc/output_schema_desc.json-- Human-readable field descriptions.
All schemas MUST have "type": "object" at root and include a confidence field. Use templates/output_schema.json and templates/output_schema_desc.json.
Step 7: Custom Tools (if needed)
If the workflow needs custom MCP tools, create {workflow_dir}/mcp/{tool_file}.py using the FastMCP pattern. See templates/mcp-tool.py.
Step 7b: Built-in Tool Implementations (if tool implementation mode is enabled)
When tool implementation mode is enabled, generate MCP implementations for every
built-in tool referenced in any agent's tools.allowed list that is not already
provided by an external runtime or custom tool. This ensures the workflow is
self-contained and can run without a full AWP runtime providing built-in tool stubs.
Process:
- Collect all unique tool FQNs from every agent's
tools.allowedacross the workflow. - For each tool FQN that belongs to a reserved namespace (
web,http,file,shell,agent,memory,arithmetic):- Generate a working MCP implementation in
{workflow_dir}/mcp/{namespace}_{action}.py. - Use the FastMCP pattern from
templates/mcp-tool.py. - Implement real logic (not stubs) appropriate to the tool's purpose.
- Match the parameter signature from
references/tools-reference.md.
- Generate a working MCP implementation in
- Tools that the user explicitly provides (e.g., as external MCP servers or custom
implementations already in
mcp/) are skipped — do not overwrite them.
Implementation guidelines per namespace:
| Tool | Implementation approach |
|---|---|
web.search |
Use httpx or requests to call a search API (e.g., DuckDuckGo, SearXNG, or a configurable endpoint). Return structured results. |
http.request |
Use httpx to make arbitrary HTTP requests with timeout and error handling. |
file.read / file.write / file.list |
Use Python pathlib with sandboxed path validation. |
shell.execute |
Use subprocess.run with timeout and cwd support. |
terminal.execute |
Like shell.execute but rejects any command containing sudo, pkexec, or doas. Use this for agents that need terminal access without privilege escalation. |
memory.write / memory.read / memory.search / memory.curate |
Use file-based storage in a {workflow_dir}/.memory/ directory. |
agent.send_message / agent.list_messages |
Use file-based message queue in {workflow_dir}/.messages/. |
arithmetic.* |
Direct Python arithmetic operations. |
digest.fetch |
Run-scoped Hierarchical Context Digest lookup (delegation loop only). digest.fetch(sha) returns the compact per-level digest at this SHA from the current manager run's DigestStore (<workspace>/runs/<run_id>/digest/<sha>.json). Used by workers to pull deeper layers of the digest hierarchy that are not inlined in the manager prompt. Cross-run access is refused. Auto-injected into worker tools_allowed when delegation_loop.digest_enabled is true (the default). |
board.post / board.read |
Run-scoped sibling-coordination blackboard (delegation loop only). Append-only JSONL at <workspace>/blackboard/<manager_run_id>.jsonl. board.post(topic, payload) appends an entry, board.read(topic?, since?) returns entries (optionally filtered). Siblings in the SAME manager run see each other's signals; other runs (and submanagers, which get their own board) cannot. Workers don't need to list these explicitly — the runtime injects them automatically when delegation_loop.blackboard_enabled is true (the default). |
Note: When tool implementation mode is disabled (the default), this step is
skipped entirely. Built-in tool FQNs in tools.allowed are assumed to be provided
by the target runtime, per the AWP specification ("runtimes SHOULD provide").
R14 compliance: When tool implementation mode is enabled, R14 ("tools.allowed MUST reference registered MCP tools") is satisfied by the generated implementations. When disabled, R14 compliance depends on the target runtime registering these tools.
Step 7c: Code Mode SDK & Skill (if Code Mode is enabled)
When an agent has capabilities.codemode.enabled: true:
-
Generate a typed SDK interface from the agent's
tools.allowed. Group methods by namespace (e.g.,sdk.web.search(),sdk.file.read()).TypeScript SDK template:
// AWP Code Mode SDK — TypeScript Interface // Auto-generated from capabilities.tools.allowed /** AWP Tool SDK for Code Mode execution. All methods return a standard AWP ToolResult. */ export interface AWPToolSDK { {{SDK_METHODS}} } /** Standard AWP tool result. */ export interface ToolResult { ok: boolean; status: number; data: Record<string, unknown>; error: string | null; } /** Execute function signature. The agent writes a function matching this signature. */ export type AgentExecuteFn = (sdk: AWPToolSDK) => Promise<Record<string, unknown>>; // ── Example SDK shape (when tools include web.*, file.*, memory.*) ── // // interface AWPToolSDK { // web: { // search(query: string, maxResults?: number): Promise<ToolResult>; // }; // file: { // read(path: string): Promise<ToolResult>; // write(path: string, content: string): Promise<ToolResult>; // list(directory: string): Promise<ToolResult>; // }; // memory: { // read(key: string): Promise<ToolResult>; // write(key: string, value: string): Promise<ToolResult>; // search(query: string): Promise<ToolResult>; // }; // }Python SDK template:
# AWP Code Mode SDK — Python Class # Auto-generated from capabilities.tools.allowed from typing import Any class ToolResult: """Standard AWP tool result.""" ok: bool status: int data: dict[str, Any] error: str | None class AWPToolSDK: """AWP Tool SDK for Code Mode execution. All methods return a standard AWP ToolResult.""" {{SDK_METHODS}} # ── Example SDK shape (when tools include web.*, file.*, memory.*) ── # # class AWPToolSDK: # class web: # async def search(query: str, max_results: int = 5) -> ToolResult: ... # # class file: # async def read(path: str) -> ToolResult: ... # async def write(path: str, content: str) -> ToolResult: ... # async def list(directory: str) -> ToolResult: ... # # class memory: # async def read(key: str) -> ToolResult: ... # async def write(key: str, value: str) -> ToolResult: ... # async def search(query: str) -> ToolResult: ... -
Generate a Code Mode skill using
templates/codemode-skill.md:- Replace
{{SDK_TYPE_DEFINITIONS}}with the generated SDK interface - Replace
{{SDK_METHOD_LIST}}with a list of available methods - Replace
{{OUTPUT_SCHEMA_FIELDS}}with the agent's output contract - Replace
{{LANGUAGE}}and{{CODE_EXAMPLE}}with appropriate examples
- Replace
-
Place the skill at
{agent}/workflow/skills/codemode.md(agent-level skill). -
Ensure the agent's
agent.awp.yamlhas:capabilities.codemode.enabled: truecapabilities.codemode.language: {typescript|python}capabilities.sandbox.typeset (notnone)
Step 7d: Delegation Loop Generation (if engine is delegation_loop)
When generating a delegation_loop workflow:
- Generate workflow.awp.yaml with
engine: delegation_loopand full delegation_loop config - Generate ONE manager agent directory (agents/manager/) with:
- agent.awp.yaml (tools disabled, JSON outpu
Truncated - read the full file at https://github.com/veegee82/agent-workflow-protocol/blob/4d1fba4b667dce1bebf33b9edf140706bb73286d/skill/SKILL.md.
