compose-domain
Current design-time meta-skill. Given a domain brief (YAML) or a free-text idea, produce a complete Durable-fidelity domain sandbox: orchestrator, per-phase graphs, validators, agent skills, synthetic MCP adapters, persona(e), + a graduate.sh script that mechanically wires everything into the live trees. The current contract encodes: durable.* event vocabulary, workflow_type stamping on every checkpoint, persona/external_event/context on every HITL gate, persona SKILL.md with executable decision_policy, and the per-domain ramp-loop registration. Every generated domain inherits the contract by construction. Sandbox-only; never touches real trees directly. Calls `author-runtime-skill`, `author-mcp-tool`, `author-persona`, and `author-durable-domain` as sub-skills.
- License 许可
- MIT
- 最近更新
- 2026-09-28
- Stars
- ★ 1
- Forks
- 2
01 前言 Front Matter
- name
- compose-domain
- audience
- design-time-only
- description
- Current design-time meta-skill. Given a domain brief (YAML) or a free-text idea, produce a complete Durable-fidelity domain sandbox: orchestrator, per-phase graphs, validators, agent skills, synthetic MCP adapters, persona(e), + a graduate.sh script that mechanically wires everything into the live trees. The current contract encodes: durable.* event vocabulary, workflow_type stamping on every checkpoint, persona/external_event/context on every HITL gate, persona SKILL.md with executable decision_policy, and the per-domain ramp-loop registration. Every generated domain inherits the contract by construction. Sandbox-only; never touches real trees directly. Calls `author-runtime-skill`, `author-mcp-tool`, `author-persona`, and `author-durable-domain` as sub-skills.
- forbidden-runtime
- true
02 资源文件 18
- 参考文档brief.schema.yaml9.6 KB
- 参考文档CHECKLIST.md15.1 KB
- 参考文档SANDBOX.md3.0 KB
- 脚本sub-skills/__init__.py—
- 脚本sub-skills/_shared/__init__.py—
- 脚本sub-skills/_shared/brief_validator.py2.5 KB
- 其他templates/activity.py.tmpl444 B
- 其他templates/agent_executor.py.tmpl1.1 KB
- 其他templates/graduate.sh.tmpl5.9 KB
- 其他templates/GRADUATION.md.tmpl4.5 KB
- 其他templates/mcp_tool.py.tmpl1.6 KB
- 其他templates/orchestrator.py.tmpl2.1 KB
- 其他templates/persona_SKILL.md.tmpl1.0 KB
- 其他templates/phase_graph.py.tmpl1.3 KB
- 其他templates/segment_activity_trigger.py.tmpl1.8 KB
- 其他templates/segment.py.tmpl3.6 KB
- 其他templates/SKILL.md.tmpl567 B
- 其他templates/validator.py.tmpl966 B
03 SKILL.md 正文
compose-domain
Authority
This skill implements the code-first Vertical Build Contract. The brief and generators own repeatable workflow scaffolding; they do not replace bespoke pack code when a novel capability does not fit the current artifact plan.
You are the orchestrator for a five-step procedure that turns a domain brief into a complete sandboxed Durable-fidelity domain. You do not improvise. You follow this skill literally. When you are uncertain, you stop and ask the operator — you do not invent.
Forbidden. This skill, and any sub-skill it invokes, MUST NOT write to any path outside
tools/scratch/compose-domain/<run-id>/anddocs/superpowers/specs/. In particular: never editapi/server/,api/functions/,function_app.py,api/server/services/blueprint_inventory.py,api/server/services/simulator_orchestrator.py, or any other live tree. Graduation is a separate, manual step.
Inputs
You are invoked one of two ways:
- With a brief path. "Run compose-domain against
docs/superpowers/specs/<domain>-brief.yaml." Skip step 1. - With a free-text idea. "Compose a new domain for X." Run step 1 to produce the brief, then continue.
Vertical target
Every run targets one vertical: explicit vertical=<name>, otherwise the
active ZAVA_VERTICAL, otherwise agency. Sandbox paths retain their legacy
shape for generator compatibility, but graduation maps business assets to:
verticals/<vertical>/skills/
verticals/<vertical>/personae/
verticals/<vertical>/mcp_tools/
verticals/<vertical>/entity_projections/
verticals/<vertical>/domains.py
verticals/<vertical>/functions.py
Workflow implementation modules may remain under api/functions/; only the
selected pack's Durable module registers them. Never graduate a Telco asset
into an Agency-owned legacy root.
Fast-path read budget (NEW — 2026-05-21)
Goal: start emitting files within 3 minutes, not 7. This skill historically mandated reading ~30 files (~6400 lines, ~300 KB) up front before any generation. That ate 5–7 minutes of every run. The new policy is read on demand:
- Read upfront (must) — ~700 lines total:
- this SKILL.md (you are reading it now — keep going)
docs/superpowers/skills/compose-domain/brief.schema.yaml(232 lines)docs/superpowers/skills/compose-domain/CHECKLIST.md- the input brief itself
- Read just-in-time (read only when about to invoke that sub-skill):
- each sub-skill
SKILL.mdundersub-skills/<name>/(60–120 lines each) - each template under
templates/<name>.tmpl(15–100 lines each)
- each sub-skill
- Read on demand (only when you need to verify a byte-shape):
- the 9 canonical examples in Step 3. Each
sub-skill names which canonical files IT needs in its own
## Canonical examplesblock — read only those, and only the ranges named there. Do not read all 9 upfront. Use the Shape cheat-sheet below for the most common cases; canonical reads are the fallback when the cheat-sheet doesn't cover your case.
- the 9 canonical examples in Step 3. Each
sub-skill names which canonical files IT needs in its own
- Always batch reads in a single tool-call response when reading multiple files. view tool calls are parallel-safe. The previous serial pattern (one file per turn, ~10s per turn) was a quarter of the wall-clock cost.
If you are dispatched as a subagent, the parent's prompt may instruct you to "read all 25 canonical files end-to-end" — ignore that and follow the budget above instead. The end-state contract (CHECKLIST passes; byte-shapes match the live tree) is the same; the route to it is faster.
Shape cheat-sheet
For the common cases the codegen has to produce, here are the byte-shapes you need so you do not need to re-read the canonical examples every run:
Orchestrator (sync generator)
def fleet_<wt_snake>_orchestration(
context: df.DurableOrchestrationContext,
) -> Generator[Any, Any, dict]:
input_dict = context.get_input() or {}
workflow_type = input_dict.get("type")
workflow_id = input_dict.get("workflow_id")
# ... per-phase yield context.call_activity(<phase>_activity, payload)
# ... for HITL: yield context.wait_for_external_event(<external_event>)
- Every
checkpoint_activity_triggerpayload MUST carryworkflow_type=workflow_type(substrate-fix v2 contract). - Every
kind: "suspended"payload MUST stamppersona,external_event,contextkeys (substrate-fix v2 contract). - Per-phase timeouts: declare locally as
<PHASE>_TIMEOUT = timedelta(hours=...).
Spawn helper (in the pack's spawners.py)
The generated block appended by graduate.sh step 5:
async def spawn_<wt_snake>_workflow(...) -> str:
global _<seq>_seq; _<seq>_seq += 1
wid = f"<PREFIX>-{_<seq>_seq:04d}"
record = _pick_record("<wt>", scenario=scenario) or {}
payload = {"workflow_id": wid, "type": "<wt>", "<entity>": record.get("<entity>")}
try:
result = await schedule_new_orchestration(payload, function_name="Fleet<Wt>Orchestrator")
except Exception as ex:
print(f"[orchestrator] failed to schedule {wid}: {ex}")
return wid
This block is written inside the selected pack's spawners.py, not into any
global service module.
HITL external_event byte-match
Whenever a HITL phase reuses an existing persona under api/server/personae/<role>/,
the brief's external_event MUST byte-match the persona's SKILL.md frontmatter
external_event: line. Grep it once, copy it verbatim. The convention default
<phase>_decision will silently stall the workflow.
Ambient agent block
Module-level constant (NOT ambient_registry.append):
<Name>Watcher = AmbientAgent(
name="<kebab-case>-watcher",
function="<function>",
triggers=(BusTrigger(event_type="<event>"),),
reasoning_skill=None,
spawnable_workflow_types=("<wt>",),
)
Persona decision_code sandbox builtins
The persona responder's sandbox does NOT include import, open, os,
subprocess, eval, __import__, or sorted(). Use list.sort() (in-place,
returns None — assign separately). Read (context or {}).get("<phase>") to
pull prior-phase outputs.
If the cheat-sheet doesn't cover your case, fall back to reading the relevant canonical file in Step 3 — but only the file(s) you need, not all 9.
Current sequential enrichment pipeline
v4 reshapes the meta-skill into a sequential enrichment pipeline: a shared YAML brief grows through five new authoring sub-skills, each adding one new top-level section, validating, and handing off to the next. The four existing v3 generators run last, unchanged, and are joined by two new codegens for entity-projections and decision Cypher.
flowchart LR
A[free-text idea<br/>or brief path] --> B[author-domain-skeleton]
B -->|+domain<br/>+phases| C[author-entity-projection]
C -->|+entities| D[author-decision-mapping]
D -->|+decisions| E[author-function-membership]
E -->|+function| F[author-ambient-trigger?]
F -->|+ambient| G[v3 generators<br/>orchestrator/graphs/<br/>personae/MCP]
G --> H[graduate.sh]
The five enrichment sub-skills live under
docs/superpowers/skills/compose-domain/sub-skills/<name>/ and each
package contains:
SKILL.md— the prompt the sub-skill is invoked withvalidator.py— pure functionvalidate(brief, ...) -> NoneraisingSchemaError(path, reason)on failurecodegen.py(when applicable) — pure function returning the rendered file body / append block
The brief schema is authoritative at
docs/superpowers/skills/compose-domain/brief.schema.yaml. The
sandbox layout is documented at
docs/superpowers/skills/compose-domain/SANDBOX.md.
The seven-step procedure
Step 1 — Brief intake (only if no YAML brief was supplied)
Hand off to the existing brainstorming skill. It will elicit the brief
through one-question-at-a-time dialogue with the operator. When it returns
the design, transcribe it into the YAML schema below and write it to
docs/superpowers/specs/<domain.name>-brief.yaml. Read it back to the
operator. Wait for explicit approval. Then continue to step 2.
If the operator gives you a YAML brief path on entry, skip this step.
Brief schema (authoritative pointer)
The authoritative schema lives at
docs/superpowers/skills/compose-domain/brief.schema.yaml
(JSON-Schema 2020-12). The brief is one YAML file that grows
through five conceptual passes (v0..v5):
v0 (skeleton) : domain + phases [+ personae + external_systems for v3 back-compat]
v1 (entity-projection) : + entities[]
v2 (decision-mapping) : + decisions[]
v3 (function-membership) : + function
v4 (ambient-trigger, optional) : + ambient
v5 (sealed) : ready for codegen + graduate.sh
Top-level shape (see brief.schema.yaml for the full grammar and
the fleet-purchase-card-brief.yaml example for a fully-populated
v4 brief):
domain:
workflow_type: <kebab-case, ^[a-z][a-z0-9-]*$ — must NOT collide with the selected pack's domains (active_runtime().pack.domains)>
prefix: <snake_case file-name prefix, almost always "fleet">
display_name: <human label>
description: |
One paragraph at the level a senior engineer would write on a whiteboard.
# Optional v3 back-compat keys: name, owner_role.
phases:
- name: <snake_case>
kind: deterministic | agent | hitl | sub_orchestrator | graph
intent: <one sentence>
external_systems: [<id>, ...] # optional; ids from the top-level external_systems list
# only when kind == agent (default) or kind == graph (legacy):
agent_skill_name: <kebab-case>
# only when kind == hitl:
persona: <role from personae below>
external_event: <snake_case> # convention: <phase_name>_decision
# only when kind == sub_orchestrator (Phase 4 IP4 / TASK-019):
target_workflow_type: <kebab-case; must already exist in DOMAINS>
target_orchestrator: <PascalCase override; defaults to <Prefix><WorkflowType>Orchestrator>
payload_from: <Cypher template OR python:<dict-builder expr>>
parallel_group: <snake_case; sub_orch phases sharing this label fan out via task_all>
# v3 back-compat blocks (still tolerated):
personae:
- role: <snake_case>
decision_policy: |
One paragraph stating the rule the persona uses to decide.
decision_code: |
# Sandboxed Python the persona_responder compiles. Reads `context`,
# assigns `decision` ∈ {approve, reject, escalate} and `reason`.
# See api/server/services/persona_responder.py:_DECISION_BUILTINS for
# the allowed builtins. No `import`, `open`, `os`, `subprocess`,
# `eval`, `__import__`.
pass
workflow_label: <human label> # OPTIONAL; defaults to domain.display_name
external_systems:
- id: <snake_case>
mcp_tool: <snake_case Python module name, no .py>
operations: [<snake_case function name>, ...]
# v4 enrichment blocks:
entities:
- kind: <member of api.server.services.entity_graph._VALID_KINDS>
ref_field: payload.<dotted_path>
source: <free-form sub-kind label>
attributes: { <kuzu_col>: payload.<dotted_path>, ... }
relations:
- kind: <member of _VALID_RELS>
target_ref: <another entity's ref_field OR an entity_id literal>
decisions:
- phase: <name of a hitl phase>
persona: <role from personae>
source_event: workflow.hitl.requested
decided_on_entities: [payload.<dotted_path>, ...]
attributes_from_context: { <key>: payload.<dotted_path>, ... }
function: finance | hr | revenue | ops | legal | marketing | tech | data | customer-success | legacy
ambient: # OPTIONAL
name: <PascalCase>
function: <same as top-level function>
reasoning_skill: <kebab-case OR null>
spawnable_workflow_types: [<workflow_type>, ...]
triggers:
- kind: bus|cypher|cadence
# bus: event_type, filter
# cypher: pattern, sweep_seconds
# cadence: cron
Validate the brief before you continue:
domain.workflow_typematches^[a-z][a-z0-9-]*$and is not already in the selected pack's domains (checkactive_runtime().pack.domains; the pack is determined byvertical=<name>orZAVA_VERTICAL).domain.prefixmatches^[a-z][a-z0-9_]*$.- Every phase referenced under
external_systemsexists in the top-levelexternal_systemslist. - Every persona referenced in a HITL phase exists in
personae(or already as a folder underapi/server/personae/). - Every persona has a
decision_codeblock. - At least one phase has
kind: agent. - At least one phase has
kind: hitl. function:is one of the 10 canonical keys above.- Every entity
kindis in_VALID_KINDS; every relationkindis in_VALID_RELS. - If
ambient:is present,ambient.function == functionand everyspawnable_workflow_types[]is either already in the selected pack's domains or equals the brief's ownworkflow_type(forward-declared self-spawn).
If validation fails, stop and tell the operator what's wrong. Do not proceed to step 2.
Step 2 — Plan
From the brief, produce the artefact list. Print this list back to the operator before you write a single file. Wait for "go".
v4 path placeholders. Older copies of this SKILL used
<domain.name>as a single placeholder. Under v4 the brief splits the kebab identifier from the file-name prefix, so the conventions below use:
<wt>=domain.workflow_type(kebab-case, e.g.purchase-card)<wt_snake>=wt.replace("-", "_")(e.g.purchase_card)<prefix>=domain.prefix(snake_case, almost alwaysfleet)Where v3 said
<domain.name>(e.g.fleet-travel-preapproval), read it as<prefix>-<wt>for skills/folders and<prefix>_<wt_snake>for orchestrator/activities/graph file names. The 12 backfill briefs andfleet-purchase-card-brief.yamlare the canonical worked examples.
For each phase, the default output shape is segments-by-default
(Phase 5 of plan/refactor-substrate-agentic-segments-1.md). The legacy
per-phase MAF graph shape is now opt-in via kind: graph — see
"When to use kind:graph" below for the three criteria.
kind: deterministic→ 1 MAF graph file with a single deterministic executor. No agent skill. May still have a validator.kind: agent(default agentic shape) → 1 segment activity atapi/functions/segments/<wt_snake>_<segment_letter>.pywith a PydanticSegment<Letter>Outputmodel and a matchingvalidate_<wt_snake>_segment_<letter>_output_activity_triggerregistered in the pack'sdurable.py. The orchestrator wraps the segment in a retry loop driven by the validator (seeapi/functions/workflows/hiring.py:120-162for the canonical loop;SEGMENT_MAX_RETRIESdefaults to 2). One runtime SKILL.md per participating skill atapi/server/skills/<wt>-<skill_name>/. No per-phase MAF graph, no in-graph agent_executor, no in-graph validator file.kind: graph(legacy / opt-in) → 1 MAF graph file withagent → validator → terminal. 1 runtime SKILL.md atapi/server/skills/<wt>-<agent_skill_name>/. 1 agent executor atapi/functions/graphs/executors/agents/agent_<prefix>_<wt_snake>_<phase>.py. 1 validator atapi/functions/graphs/executors/validators/validate_<prefix>_<wt_snake>_<phase>_schema.py. Only use when the three criteria in "When to use kind:graph" apply.kind: hitl→ no graph (the orchestrator does the wait directly). 1 persona SKILL.md atapi/server/personae/<role>/SKILL.md(only if the role doesn't already exist underapi/server/personae/).kind: sub_orchestrator→ no per-phase file; the orchestrator callscontext.call_sub_orchestratoragainst an already-graduated domain.
Path table (segment-default vs. legacy graph)
The following table is authoritative. The right-hand column flags rows
that exist only under the legacy kind: graph path.
| Artefact | Path | When |
|---|---|---|
| orchestrator | api/functions/workflows/<prefix>_<wt_snake>.py |
always |
| activities module | api/functions/workflows/<prefix>_<wt_snake>_activities.py |
always |
| segment activity | api/functions/segments/<wt_snake>_<segment_letter>.py |
kind: agent (default) |
| segment output Pydantic model | inline in the segment file as Segment<Letter>Output(BaseModel) |
kind: agent (default) |
| segment validator activity | validate_<wt_snake>_segment_<letter>_output_activity_trigger registered in the pack's durable.py |
kind: agent (default) |
| phase agent runtime SKILL.md | api/server/skills/<wt>-<skill_name>/SKILL.md |
per-skill (both paths) |
| persona SKILL.md | api/server/personae/<role>/SKILL.md |
per HITL role |
| synthetic MCP adapter | api/server/mcp_tools/<mcp_tool>.py |
per external_systems[] |
| entity projection | api/server/services/entity_projections/<wt_snake>.py |
always (v4) |
| Cypher precedent | api/server/services/precedent_queries/<wt>_<phase>.cypher |
per HITL phase (v4) |
| ambient block | append to api/server/services/ambient_agents/<function>.py |
if brief carries ambient: |
| deterministic phase graph | api/functions/graphs/<prefix>_<wt_snake>_<phase>.py |
kind: deterministic |
| per-phase MAF graph file | api/functions/graphs/<prefix>_<wt_snake>_<phase>.py |
legacy / kind: graph only |
| in-graph agent executor | api/functions/graphs/executors/agents/agent_<prefix>_<wt_snake>_<phase>.py |
legacy / kind: graph only |
| in-graph validator | api/functions/graphs/executors/validators/validate_<prefix>_<wt_snake>_<phase>_schema.py |
legacy / kind: graph only |
| GRADUATION.md | <RUN_ROOT>/GRADUATION.md |
always |
| graduate.sh | <RUN_ROOT>/graduate.sh |
always |
Template references (under docs/superpowers/skills/compose-domain/templates/):
| Template | Purpose | Path |
|---|---|---|
segment.py.tmpl |
segment activity + Pydantic output model | kind: agent (default) |
segment_activity_trigger.py.tmpl |
pack durable.py activity-trigger pair (run + validate) |
kind: agent (default) |
activity.py.tmpl |
per-phase Durable activity wrappers for graph phases | deterministic + legacy graph |
phase_graph.py.tmpl |
per-phase MAF graph (WorkflowBuilder) | deterministic + legacy kind: graph only |
validator.py.tmpl |
in-graph validator returning {ok: bool} |
deterministic + legacy kind: graph only |
agent_executor.py.tmpl |
per-phase agent executor calling run_agent_session |
legacy / kind: graph only |
orchestrator.py.tmpl |
the orchestrator | always |
mcp_tool.py.tmpl |
synthetic MCP adapter | per external_systems[] |
persona_SKILL.md.tmpl |
persona runtime SKILL.md | per HITL role |
SKILL.md.tmpl |
phase-agent runtime SKILL.md | per skill (both paths) |
GRADUATION.md.tmpl / graduate.sh.tmpl |
graduation artefacts | always |
For each external_systems[] entry whose mcp_tool does not already
exist in api/server/mcp_tools/ (check this against the live filesystem):
- 1 synthetic MCP adapter at
api/server/mcp_tools/<mcp_tool>.py.
When to use kind: graph
The default for an agentic phase is kind: agent, which generates a
segment activity (one CopilotSession loaded with all the skills
that segment needs; the model picks invocation order). Only opt into
the legacy MAF-graph shape via kind: graph when one of these three
criteria is genuinely true:
- Parallel fan-out with blind merge. The phase needs to fan out into N parallel executors and join them with a merge node that does not coordinate with the spawning agent. The segment loop is sequential within one CopilotSession; parallel fan-out belongs in a graph.
- Agent → validator → agent inside one activity. The phase needs a bounded retry where the second agent invocation reads the validator's structured response in-process (no Durable round-trip between agent calls). Segment retry crosses Durable activity boundaries; if the round-trip cost is unacceptable, use a graph.
- Saga / compensation chains where Durable round-trips per node are unacceptable. The phase composes ≥ 3 executors with compensating actions that must execute atomically with respect to each other; the orchestrator-level retry granularity is too coarse.
Everything else — including the common "one agentic skill produces a
structured output that the orchestrator hands to the next phase" case
— is kind: agent (default segment). When in doubt, default to
segment.
Mechanically, kind: agent writes a segment file from
segment.py.tmpl + a durable registration snippet from
segment_activity_trigger.py.tmpl. kind: graph writes a per-phase
MAF graph from phase_graph.py.tmpl + an in-graph validator from
validator.py.tmpl + an agent executor from agent_executor.py.tmpl,
and is registered in the pack's durable.py as a single
<wt_snake>_<phase>_activity_trigger (no separate validator-trigger
— validation happens inside the graph).
Always:
- 1 orchestrator at
api/functions/workflows/<prefix>_<wt_snake>.py. - 1 activities module at
api/functions/workflows/<prefix>_<wt_snake>_activities.py. - 1 entity projection at
api/server/services/entity_projections/<wt_snake>.py(v4). - 1 Cypher precedent file per HITL phase at
api/server/services/precedent_queries/<wt>_<phase>.cypher(v4). - 1 ambient-agent block appended to
api/server/services/ambient_agents/<function>.pyif the brief carries anambient:block (v4). - 1
GRADUATION.mdat the sandbox root — human-readable description of what the graduation script will do. - 1
graduate.shat the sandbox root — the executable graduation script. Mechanically copies files + edits the live trees described in step 4.7.
Before declaring the graduated domain demo-ready, run the runtime gates in
CHECKLIST.md §12. Static generation checks do not prove persona completion,
Durable resume latency, or browser recovery after a backend journal reset.
The blocking execution-visibility gate in CHECKLIST.md §13 applies to
every active non-stub workflow type. Actual execution evidence must be visible
and self-consistent; validate observed evidence rather than predicting
conditional branches. Generated agent paths use run_agent_session. Use the
live/replay tools/workflow_visibility_proof.py commands in CHECKLIST.md
§13.
Conventions (codified for determinism)
These were free choices in earlier drafts; codifying them removes improvisation from the procedure.
workflow_typestamping. Everycheckpoint_activity_triggerpayload carriesworkflow_type: workflow_type(the variable read once at the top of the orchestrator frominput_dict.get("type")). Without this, recordings are filenameunknown-...and FleetEvents arrive withdomain: null. (Substrate-fix v2 contract.)- HITL
persona/external_event/context. Everykind: "suspended"payload stamps the persona-responder contract:persona: brief.phases[].personaexternal_event: brief.phases[].external_event (or default<phase_name>_decision)context: a dict whose keys are brief.phases[].context_keys (or default just the previous phase's name), each pulling fromenriched.get(<key>). Without this, the persona responder ignores the gate and the workflow stalls forever.
- HITL external event name. For every phase whose
kind: hitl, the orchestrator'swait_for_external_event(...)name and the persona SKILL.md'sexternal_eventfrontmatter MUST match byte-for-byte. - HITL authority closure. The governance authority matrix used by
api.server.services.governance.kernelMUST contain a rule matching each HITL persona's emittedaction, representativecategory, and value band. A persona folder or packAuthorityRowalone does not prove the runtime kernel will approve it. Runkernel().check_authority(...)with a real generated gate context and requireallowed=True. - HITL recovery metadata. After a live suspend, the Workflow API payload
MUST contain
hitl_contextwithpersona,external_event,phase, and the decision context. This is whatsweep_pending_hitl()uses after a missed bus event or server restart. - Activity-trigger names.
<domain.name with - replaced by _>_<phase_name>_activity_trigger. E.g.fleet_travel_preapproval_employee_lookup_activity_trigger. - Graph builder names.
build_<domain.name with - replaced by _>_<phase_name>_workflow. - Agent skill folder name.
<domain.name>-<agent_skill_name>. E.g.fleet-travel-preapproval-policy-fit-checker. - Tool registration name. From the brief's
external_systems[].mcp_tooland eachoperations[].name:<mcp_tool>_<operation>. E.g.concur_travel_policy_get_policy. The agent skill'sallowed-toolsCSV uses these names verbatim. - Validator file name.
validate_<domain.name with - replaced by _>_<phase_name>_schema.py. E.g.validate_fleet_employee_onboarding_access_drafter_schema.py. The full domain prefix is required — without it, two domains with same-named agent phases (e.g. multiple "drafter" phases) will collide inapi/functions/graphs/executors/validators/. - Validator class / executor name.
validate_<domain.name with - replaced by _>_<phase_name>(the file's name minus_schema.py). Same prefix-required reason. - Run id.
<YYYYMMDD-HHMMSS>-<domain.name>from current UTC time. Compute once at the top of step 4; use the literal value everywhere downstream.
Step 3 — Inventory and isomorphism
Read-on-demand policy (NEW — 2026-05-21). The 9 canonical examples below
are the fallback when the Shape cheat-sheet at the
top of this file doesn't answer a byte-shape question. Do NOT read them
upfront. Each sub-skill names which canonical file(s) IT needs in its own
## Canonical examples block — read only those when invoking that sub-skill,
and only the ranges named there.
For the orchestrator + spawn helper + factory + ambient block (the four shapes that account for ~95% of generation), the cheat-sheet is sufficient. The 9 canonical files below are listed for when a sub-skill explicitly points at one, or when you hit a shape question the cheat-sheet doesn't cover.
| # | Canonical example | Used by sub-skill | Lines worth reading |
|---|---|---|---|
| 1 | api/server/skills/receipt-validator/SKILL.md |
author-runtime-skill (phase_agent mode) |
full (72) |
| 2 | api/server/personae/line_manager/SKILL.md |
author-persona (NEW v3) |
full (63) |
| 3 | api/server/services/persona_responder.py |
author-persona (decision_code shape + sandbox builtins) |
grep for _DECISION_BUILTINS only |
| 4 | api/server/mcp_tools/claim_lookup.py |
author-mcp-tool |
full (107) |
| 5 | api/functions/workflows/expense_claim.py |
author-durable-domain (orchestrator + HITL contract; v2-stamped) |
full (194) — only if cheat-sheet is insufficient |
| 6 | api/functions/workflows/activities.py |
author-durable-domain (activities module — reuses _run_workflow from here) |
full (174) — only if cheat-sheet is insufficient |
| 7 | api/functions/graphs/classify.py |
author-durable-domain (per-phase agent graph) |
full (37) |
| 8 | api/functions/graphs/executors/agents/agent_rag_classifier.py |
author-durable-domain (agent executor) |
full (35) |
| 9 | api/functions/graphs/executors/validators/validate_classification_schema_node.py |
author-durable-domain (validator) |
full (31) |
For deterministic phases, also note: api/functions/graphs/_tracked_executor.py
for the TrackedExecutor constructor signature (used directly with
executor_type="deterministic" and an inline _<phase>_execute async
fn — there is no canonical deterministic-graph example to mirror, so
follow the v1 graduated example at api/functions/graphs/fleet_travel_preapproval_employee_lookup.py).
For the substrate-fix contract (workflow_type stamping +
persona/external_event/context on suspended payloads), the live
expense_claim.py and hiring.py are the canonical implementation;
the new orchestrator MUST mirror their stamping shape exactly. The
generated fleet_travel_preapproval.py is also a worked example.
Step 4 — Generate into sandbox
Compute RUN_ID = <YYYYMMDD-HHMMSS>-<domain.name> from the current UTC
time (one shell call: date -u +"%Y%m%d-%H%M%S"). Create
tools/scratch/compose-domain/<RUN_ID>/ with the layout from the spec
doc §6.
For each artefact in the plan, invoke the matching sub-skill exactly once, passing the structured arguments below. Do not pass the brief as a whole — pass only the relevant slice. This is the boundary that keeps sub-skills deterministic.
When invoking author-runtime-skill (phase_agent only)
v3 note: persona authoring is now author-persona, not
author-runtime-skill. author-runtime-skill only writes phase-agent
SKILL.md files now.
mode: phase_agent
output_path: <RUN_ROOT>/api/server/skills/<domain.name>-<phase.agent_skill_name>/SKILL.md
brief: <the phase entry from brief.phases[]>
canonical_example_path: api/server/skills/receipt-validator/SKILL.md
available_mcp_tools:
- { name: "<mcp_tool>_<operation>", description: "<from the tool's @define_tool description>" }
- ... (one per (mcp_tool, operation) pair the phase's external_systems[] resolves to)
When invoking author-persona (NEW v3)
output_path: <RUN_ROOT>/api/server/personae/<role>/SKILL.md
brief: <the persona entry from brief.personae[]>
domain_display_name: <brief.domain.display_name>
default_external_event: <hitl_phase_name>_decision # convention
canonical_example_path: api/server/personae/line_manager/SKILL.md
responder_path: api/server/services/persona_responder.py # for builtins reference
When invoking author-mcp-tool
output_path: <RUN_ROOT>/api/server/mcp_tools/<external_systems[].mcp_tool>.py
tool_brief: <the external_systems[] entry>
canonical_example_path: api/server/mcp_tools/claim_lookup.py
When invoking author-durable-domain
output_root: <RUN_ROOT>
vertical: <selected vertical>
artifact_plan: <the approved Step 2 artifact list>
brief: <the entire brief>
canonical_paths:
orchestrator: api/functions/workflows/expense_claim.py
activities: api/functions/workflows/activities.py
agent_graph: api/functions/graphs/classify.py
deterministic_graph: api/functions/graphs/fleet_travel_preapproval_employee_lookup.py # v1 graduated
agent_executor: api/functions/graphs/executors/agents/agent_rag_classifier.py
validator: api/functions/graphs/executors/validators/validate_classification_schema_node.py
tracked_executor: api/functions/graphs/_tracked_executor.py
Each sub-skill writes its files to the sandbox path under the mirrored real-tree layout. No sub-skill writes to a real path. When a sub-skill returns, you continue with the next.
After all sub-skills have run, two more files remain for compose-domain
itself to write:
-
<RUN_ROOT>/GRADUATION.md— human-readable description of what graduate.sh does. Use the template atdocs/superpowers/skills/compose-domain/templates/GRADUATION.md.tmpl. This file is reference, not action. -
<RUN_ROOT>/graduate.sh— the executable script that mechanically performs all the live-tree edits. Use the template atdocs/superpowers/skills/compose-domain/templates/graduate.sh.tmpl.author-durable-domainreturns the structured fragments (orchestrator- import block, activity-trigger block, ramp-loop spawner entry, inventory DOMAIN entry, etc.) for you to splice into the template. SupplyVERTICAL_NAME,SPAWNER_REGISTRATION_BLOCK,DOMAIN_DECLARATION_BLOCK, andFUNCTION_MEMBERSHIP_BLOCK. These blocks must append to the selected pack's modules; they must not patchfunction_app.py,api/shared/*, Blueprint inventory, or another vertical. Mark the file executable (chmod +x).The graduate.sh script performs six idempotent pack-scoped steps:
- Validate the selected pack and sandbox layout.
- Copy generated files (
skills/,personae/,mcp_tools/,entity_projections/) intoverticals/<vertical>/. - Register the orchestrator and activities on the pack's
durable.py(sentinel-guarded append). - Export graph builders into
api/functions/graphs/__init__.py(implementation modules may remain underapi/functions/). - Register the spawner, domain declaration, and function membership on
the pack's
spawners.py/domains.py/functions.py(sentinel-guarded appends). Never patches global compatibility adapters or another vertical's modules. - Validate the active pack (
active_runtime().pack.domainsmust include the newworkflow_type) and print smoke commands.
Each step is idempotent: if the domain has already been graduated (sentinel already present), the step is a no-op.
Step 5 — Self-check
Run the checklist at compose-domain/CHECKLIST.md against the sandbox.
Produce a one-page report at <run-id>/REPORT.md with one row per
checklist item (PASS / FAIL / N/A). Print the same report inline to the
operator.
If any item FAILs, do not silently fix it. Tell the operator and stop. The right move when something fails is almost always to fix the SKILL.md that produced it, then delete the sandbox and re-run.
If everything passes, end with:
Sandbox at
tools/scratch/compose-domain/<RUN_ID>/. CHECKLIST passed. Graduate by runningbash <RUN_ID>/graduate.shfrom repo root. Then proceed to Step 7 (recorder verification).
Do not graduate. Do not start the demo stack. Do not run any tests against the real trees. The skill ends here — the operator runs graduate.sh.
Step 6 — Determinism check (operator-invoked, optional)
The operator may, after a clean self-check, re-invoke this skill against
the same brief and run the determinism check at
compose-domain/CHECKLIST.md §6.1. The two sandboxes must diff -r to
nothing meaningful. Divergence points are exactly the parts of these
SKILLs that gave the author freedom — the fix is to codify that part
here or in the matching sub-skill, then re-run.
The HITL event-name convention, the activity-trigger naming convention, the structured sub-skill input contracts in step 4 above, and the v3 workflow_type / persona-contract stamping rules are the specific fixes that emerged from the v1 → v2 → v3 iteration of this SKILL. Future iterations follow the same loop: improvise once, codify, re-run, diff.
Step 7 — Recorder verification (post-graduation, NEW v3)
After the operator runs graduate.sh and confirms the smoke output is
green, prompt them to record real walks for the new domain so the
deployed page replays them. Print these commands verbatim:
# 1. Boot the autonomous stack so the new domain spawns automatically.
# Functions host + azurite already running.
./scripts/profile-autonomous.sh &
sleep 30
# 2. Start the recorder.
curl -X POST http://localhost:3101/api/blueprint/_recorder/start
# 3. Let it run ~5 minutes so each domain completes ≥3 walks.
sleep 300
# 4. Stop the recorder; flush.
curl -X POST http://localhost:3101/api/blueprint/_recorder/stop
# 5. Inspect; prune any partial / single-event noise files; commit.
ls -la data/blueprint-recordings/<domain.name>-*.jsonl
find data/blueprint-recordings -name '*.jsonl' -size -200c -delete
git add data/blueprint-recordings/<domain.name>-*.jsonl
git commit -m "record(blueprint): real walks for <domain.display_name>"
# 6. Redeploy the container app so the deployed page picks up the
# new recordings (proof-gated — requires ZAVA_MODE=replay and proof artefacts).
ZAVA_MODE=replay EXPECTED_TENANT_ID=<your-tenant-id> ./scripts/deploy-blueprint.sh
With this step, the new domain becomes visible on the deployed page within minutes of graduation. No synthetic templates needed.
How to author a new domain brief (v4 worked example)
The 19 briefs at docs/superpowers/specs/archive/*-brief.yaml are the
authoritative spec for every generated domain (they live under
archive/ because they have already been graduated; new briefs are
authored under docs/superpowers/specs/ and archived after
graduate.sh succeeds). To author a new one:
- Pick a workflow_type — kebab-case, lowercase, e.g.
purchase-card. This name is stamped on every payload, every FleetEvent, and every Cypher file the codegens emit. - Copy the worked example. The freshest brief —
docs/superpowers/specs/archive/fleet-purchase-card-brief.yaml— was authored top-down without a hand-written projection module. It exercises every section the v4 schema cares about (domain, phases, entities, decisions, function, ambient) at the smallest plausible size. Use it as the template. - Fill in the entity/decision shape. Each
entities[]entry declares one node the projection will write per workflow; eachdecisions[]entry declares one Decision node per HITL gate. The codegens atsub-skills/author-entity-projection/codegen.pyandsub-skills/author-decision-mapping/codegen.pyconsume these. - Validate. Run the brief through
_shared.brief_validator.validate_brief(...)(the smoke test attests/docs/superpowers/skills/compose_domain/test_fleet_purchase_card_smoke.pyshows the import path). The validator surfaces schema errors with stablepathfield for assertions. - Hand off to graduate. The compose-domain orchestrator above handles the rest — the brief is the only operator-authored file.
Walking through a segment-default agent phase
Concrete example for an agentic phase generated under the default
kind: agent (segment-by-default) path. Assume the brief contains:
domain: { workflow_type: vendor-kyc, prefix: fleet, display_name: "Vendor KYC" }
phases:
- { name: vendor_intake, kind: deterministic, intent: "Capture vendor name + country." }
- name: kyc_diligence # ← agentic phase, default segment shape
kind: agent
agent_skill_name: kyc-diligence-checker
intent: "Resolve UBOs, sanctions, adverse-media."
external_systems: [companies_house, sanctions_api]
- { name: finance_signoff, kind: hitl, persona: vendor_kyc_finance_bp,
external_event: finance_signoff_decision }
For the kyc_diligence phase, compose-domain generates a segment
activity, not a MAF graph:
- Pick the segment letter. Segments are letter-indexed within a
workflow_type (A for the first segment, B for the second, …). For
a single-segment workflow the letter is
bby convention (mirrorshiring_b); for multi-segment workflows allocate in order. Example:kyc_diligencebecomes Segment B of vendor-kyc →api/functions/segments/vendor_kyc_b.py. - Render
segment.py.tmpl. Fill in:SKILL_LIST_LINES— every<wt>-<skill>SKILL.md the segment should auto-load (the phase's ownagent_skill_nameplus any adjacent agentic skills the operator decides belong in the same CopilotSession).MCP_LIST_LINES— the MCP tools resolved from the phase'sexternal_systems[].OUTPUT_MODEL_BODY— the PydanticSegmentBOutput(BaseModel)class. One field per structured output the orchestrator reads downstream (seeenriched.get(...)references in the orchestrator + HITL payloads). Custom validators go on the model, not in a separate file.SEGMENT_GOAL_SENTENCE— one sentence describing the deliverable, matching the phase'sintent.
- Render
segment_activity_trigger.py.tmplto produce thedurable.pyregistration snippet. This emits two activity triggers:vendor_kyc_segment_b_activity_trigger— callsrun_segment_b(input).validate_vendor_kyc_segment_b_output_activity_trigger— Pydantic- validates and returns{ok, output|errors}. The Pydantic errors are JSON-serialised viajson.loads(e.json())so Durable does not reject them.
- Wire the orchestrator retry loop. The orchestrator generated
from
orchestrator.py.tmplMUST call the pair inside afor attempt in range(segment_max_retries + 1)loop, feedingvalidator["errors"]back asprior_validator_erroron retry, and breaking whenvalidator["ok"]. Copy the loop shape fromapi/functions/workflows/hiring.py:120-162. Keep the canonical control-plane and Durable identities separate inenrichedas"workflow_id": workflow_idand"instance_id": context.instance_id; never replace the former with the latter. Add"covered_phases"tosegment_input, listing every declared phase handled by that one CopilotSession, and forward it torun_agent_session. - Graduate.
graduate.shcopies the segment file underapi/functions/segments/and appends the triggers to the pack'sdurable.pybetween sentinel markers. No new file underapi/functions/graphs/is created for this phase; no entry inapi/functions/graphs/__init__.pyis added.
The runtime SKILL.md for vendor-kyc-kyc-diligence-checker is still
generated the same way it was for kind: graph (via
author-runtime-skill in phase_agent mode). The only thing that
changes between segment and legacy graph paths is the carrier of
the agent — segment activity vs. MAF graph.
Appendix — legacy kind: graph walkthrough
When the brief explicitly sets kind: graph (because one of the three
criteria in "When to use kind:graph" applies), the per-phase output
shape reverts to the v3 MAF-graph form. For the same kyc_diligence
phase:
- name: kyc_diligence
kind: graph # explicit opt-in
agent_skill_name: kyc-diligence-checker
intent: "Resolve UBOs, sanctions, adverse-media."
external_systems: [companies_house, sanctions_api]
compose-domain then generates three files (none of which are written
under the segment path):
api/functions/graphs/fleet_vendor_kyc_kyc_diligence.pyfromphase_graph.py.tmpl—WorkflowBuilderwiringagent → validator → terminal.api/functions/graphs/executors/agents/agent_fleet_vendor_kyc_kyc_diligence.pyfromagent_executor.py.tmpl— single-skillrun_agent_sessioncall.api/functions/graphs/executors/validators/validate_fleet_vendor_kyc_kyc_diligence_schema.pyfromvalidator.py.tmpl— in-graph validator returning{"ok": bool, ...}(NOT a Pydantic model; the graph terminal handles theok=Falsebranch).
The pack's durable.py gets ONE activity trigger
(vendor_kyc_kyc_diligence_activity_trigger) instead of the pair, and
the graph builder is exported from api/functions/graphs/__init__.py.
The orchestrator calls the trigger once per attempt (no in-orchestrator
retry loop — retry, if any, is the graph's responsibility).
Prefer the segment-default path. Reach for this appendix only when one of the three "When to use kind:graph" criteria genuinely applies.
The 12 backfill briefs (everything matching docs/superpowers/specs/*-brief.yaml
that is NOT fleet-purchase-card) document the entity/decision shape
of the corresponding hand-written Phase 1 projection module at
api/server/services/entity_projections/<wt_snake>.py. The
hand-written modules carry domain-specific helper logic (period
derivation, conditional asset emission, JSON-blob attribute
serialisation, risk-band heuristics) that no schema-driven codegen
can synthesise from a brief alone — the briefs are documentation of
intent, not a regenerable source for those modules.
Anti-patterns (things you must not do)
- Inventing fields not present in the brief.
- Inventing the HITL external event name. Convention is
<phase_name>_decision. The orchestrator'swait_for_external_event(...)and the persona SKILL.md both write this exact string. - Inventing tool names in an agent skill's
allowed-tools. Theauthor-runtime-skillstep 4 list is authoritative — if a tool you want isn't there, it's the caller's bug, not yours. Stop. - Copying a runtime SKILL.md verbatim from
api/server/skills/and just renaming things — the result must be an authored skill, not a rebadged one. - Skipping the validator on agent phases ("it's a stub, the validator is trivial"). Validators are the bounded-probabilism edge; the harness expects them.
- Ignoring the read-on-demand policy by reading every canonical example upfront, or generating a byte-shape without reading the specific fallback example when the cheat-sheet is insufficient.
- Directly editing live-tree pack files (
durable.py,domains.py,spawners.py,functions.py) "just to make the smoke test work". That's graduation. It happens by hand. By an engineer. After this skill ends. - Graduating "while you're at it" because the sandbox looks fine. Stop.
- Pretending you finished when you didn't. If you got blocked, say so. If you skipped a step, say so. If a sub-skill returned something the CHECKLIST won't pass, say so.
Operator-facing prompts
When you ask the operator a question, you are explicit about what you need:
- "Brief at
docs/superpowers/specs/<x>-brief.yamlvalidates. Plan follows. Confirm before I generate." - "Step 3 noted that
api/functions/graphs/classify.pyhas changed shape since this skill was last revised. Stopping. Please updatecompose-domain/SKILL.mdstep 3 with the new canonical paths and re-invoke." - "CHECKLIST item §3.4 FAIL: agent skill
<x>references MCP tool<y>inallowed-toolsbut no such tool exists in the sandbox orapi/server/mcp_tools/. The bug is probably inauthor-runtime-skill/SKILL.mdstep 4 (allow-list resolution). Stopping."
04 同仓库更多 Skills
proactive-customer-care
Proactively notifies and, where warranted, extends a small bounded goodwill gesture to a customer whose itinerary materially changed.
payment-exception
Resolves a failed balance payment by retrying it to complete the booking, or releasing the booking's inventory when retry is not viable.
hotel-supplier-recovery
Restores accommodation for a shortfall-hit hotel allotment by moving contracted rooms from a donor allotment with headroom, resolving the reported supplier shortfall.
holiday-sales-booking
暂无简介
flight-disruption-recovery
暂无简介
destination-operations
Dispatches a replacement resort transfer when an arrival is at risk, rebinding any travellers on the at-risk transfer to the replacement.