Notation
Skill(name) / Skill(name, args) = load ~/.codex/skills/{name}/SKILL.md or .codex/skills/{name}/SKILL.md(project overrides global), args fills the target SKILL.md <context> block's input parameter slots. This is an internal call between skills,not a CLI command. Strictly forbidden to translate as Bash("maestro {name} {args}")。
Valid CLI subcommands are limited to structured operations:maestro ralph next、maestro ralph complete、maestro ralph retry、maestro delegate、maestro explore , etc.
Mutual invocation with Skill(maestro-ralph) forms a self-perpetuating work loop.
Session: .workflow/.maestro/{session_id}/status.json — single source of truth for the workflow. session_id format ralph-{YYYYMMDD-HHmmss}(created by Skill(maestro-ralph), adaptive chain) or maestro-{YYYYMMDD-HHmmss}(created by Skill(maestro), static chain). Both types are advanced by this skill; when [session-id] is omitted, the latest status=="running"is used. For the schema, see Skill(maestro-ralph) 's Session Schema.
Parse:
-y / --yes → auto = true
Remaining → session_id (if matches maestro-* or ralph-*)
Also read session.auto_mode from status.json — if true, treat as -y.
session_id requirement: Once resolved (from args or auto-discovery in A_LOCATE_SESSION), session_id MUST be passed to ALL maestro ralph next|complete|retry CLI calls via --session <session_id>. This prevents accidental cross-session operations when multiple sessions exist.
Step kinds:
| Kind | Identifier | Execution | Flow after |
|---|---|---|---|
| decision step | step.decision non-empty |
Skill(maestro-ralph) |
Execution ends here |
| execute step | step.decision == null |
Bash("maestro ralph next") → inline-execute according to its stdout → Bash("maestro ralph complete N --status ...") |
Self-invoke next |
HARD RULES:
- execute step:uniformly load via
maestro ralph nextCLI. The CLI is responsible for reading command_path (codex SKILL.md), parsing<required_reading>+<deferred_reading>, assembling the prompt, and writingstep.load.*+active_step_index+step.status="running". Do not manually Read + parse required_reading in the session again - decision step: A_EXEC_DECISION directly invokes handoff via
Skill(maestro-ralph)to ralph for evaluation (does not go through the CLI) command_pathis written by ralph in A_BUILD_STEPS into status.json (pre-validated viamaestro ralph skills --platform codex; if missing → ralph next returns E006/E007 and refuses to execute)- At the end of each step, you must call
maestro ralph complete N --status <S>ormaestro ralph retry N. STATUS has only 4 valid values:DONE | DONE_WITH_CONCERNS | NEEDS_RETRY | BLOCKED - Platform:
session.platform == "codex"; the ralph next CLI automatically resolves SKILL.md by platform (no extra parameters needed)
<state_machine>
S_LOCATE: → S_RESOLVE_ARGS WHEN: pending step found DO: A_LOCATE_SESSION → S_COMPLETE WHEN: no pending steps → S_FALLBACK WHEN: no running session
S_RESOLVE_ARGS: → S_LOAD_CONTEXT DO: A_RESOLVE_ARGS
S_LOAD_CONTEXT: → S_EXECUTE DO: A_LOAD_STEP_CONTEXT
S_EXECUTE: → END WHEN: step.decision != null DO: A_EXEC_DECISION → S_POST_ANALYZE WHEN: step.decision == null + execution succeeded (DONE|DONE_WITH_CONCERNS) DO: A_EXEC_STEP → S_COMPLETE WHEN: step.decision == null + ralph next exit code 2 (all steps completed) → S_HANDLE_FAIL WHEN: step.decision == null + ralph next exit code 1|3 OR ralph complete with NEEDS_RETRY|BLOCKED DO: A_EXEC_STEP
S_POST_ANALYZE: → S_POST_EXEC WHEN: drift_score == ALIGNED|MINOR_DRIFT DO: A_POST_ANALYZE_DRIFT → S_POST_EXEC WHEN: drift_score == MAJOR_DRIFT DO: A_POST_ANALYZE_DRIFT (Record drift caveat as DONE_WITH_CONCERNS, proceed without loop to prevent agent stall)
S_POST_EXEC: → S_LOCATE DO: Bash("maestro ralph complete ...") + Skill(maestro-ralph-execute) NOTE: recursion loop; can be externalized to runner to avoid nesting stack issues.
S_HANDLE_FAIL: → S_LOCATE WHEN: auto + not retried DO: A_RETRY → END WHEN: auto + retried DO: A_PAUSE_SESSION → S_LOCATE WHEN: interactive + user selects retry DO: A_RETRY → S_LOCATE WHEN: interactive + user selects skip DO: A_SKIP_STEP → END WHEN: interactive + user selects abort DO: A_PAUSE_SESSION
S_COMPLETE: → END DO: A_COMPLETE_SESSION
S_FALLBACK: → END DO: display "No running session. Create one using Skill(maestro) or Skill(maestro-ralph)."
A_LOCATE_SESSION
- If session_id provided → load
.workflow/.maestro/{session_id}/status.json - Else: scan
.workflow/.maestro/*/status.json, filterstatus == "running", sort DESC, take first - Extract: session_id, source, steps[], phase, milestone, intent, auto_mode, context, cli_tool, platform, active_step_index
- Identify next pending step index: scan
steps[]in order, find first entry withstatus == "pending"→ store asnext_step_index. This index is passed to A_RESOLVE_ARGS for placeholder enrichment and to A_EXEC_STEP/A_EXEC_DECISION for display. The actual step activation (writingactive_step_index) is still done bymaestro ralph nextCLI — A_LOCATE_SESSION only reads the index without writing it.
A_RESOLVE_ARGS
Placeholder substitution:
| Placeholder | Source |
|---|---|
{phase} |
session.phase |
{milestone} |
session.milestone |
{intent} |
session.intent |
{description} |
session.intent (alias) |
{scratch_dir} |
session.context.scratch_dir or latest artifact path |
{plan_dir} |
session.context.plan_dir |
{analysis_dir} |
session.context.analysis_dir |
{issue_id} |
session.context.issue_id |
{milestone_num} |
session.context.milestone_num |
Per-skill enrichment (when args empty or minimal):
| Skill | Required context | Source |
|---|---|---|
| maestro-brainstorm | topic | "{intent}" |
| maestro-roadmap | description | "{intent}" |
| maestro-analyze | milestone or topic | {milestone} or "{intent}" |
| maestro-plan | milestone, --from, or --dir | see --from auto-injection below |
| maestro-execute | phase or --dir | see --from auto-injection below |
| quality-debug | gap context | Read previous step's error/gap |
| quality-* | phase | {phase} |
--from auto-injection (artifact chaining):
Steps cannot know prior artifact IDs in advance during the build phase. A_RESOLVE_ARGS looks them up from state.json at runtime and injects explicit references, connecting the analyze→plan→execute data pipeline:
Read state.json.artifacts(含 milestone_history 内归档 artifacts)
→ filter by milestone={session.milestone} (+ phase={session.phase} for execute-step lookups) + status=="completed"
plan step(含 {milestone} 占位符,args 无 --from 且无 --dir):
1. 查同 milestone 最新 completed type=="analyze" artifact → id = ANL-xxx
2. 命中 → args 追加 --from analyze:{id}
3. 写 step.source_artifact_ref = "analyze:{id}"
execute step(含 {phase} 占位符,args 无 --dir):
1. 查同 phase+milestone 最新 completed type=="plan" artifact → id = PLN-xxx, path = scratch/...
2. 命中 → args 追加 --dir .workflow/scratch/{path}
3. 写 step.source_artifact_ref = "plan:{id}"
Fallback: query returns no result → do not inject, handled by the command's own discovery logic. Existing --from or --dir steps are not overwritten.
Goal context injection:
When step.goal_ref is non-empty and session.task_decomposition exists:
goal = session.task_decomposition.find(g => g.id == step.goal_ref)
if goal:
goal_snippet = { id: goal.id, goal: goal.goal, done_when: goal.done_when,
boundary: goal.boundary, evidence: goal.evidence }
→ 传递给 A_EXEC_STEP 用于 inline execution 前注入(见 step 2 goal context pre-injection)
Auto mode propagation: If auto == true or session.auto_mode == true, append -y (or appropriate yes-flag) to step.args (if not already present) before persisting, ensuring child skills run in non-interactive auto mode.
Write enriched args + source_artifact_ref back to status.json.
A_LOAD_STEP_CONTEXT
Load prior outputs and findings, and inject context for inline execution.
-
Previous step output — read the previous completed step's
completion_summary+completion_caveats+completion_decisions+completion_deferred -
Artifacts — per
session.context, Read each path one by one, extracting content relevant to the current step:current stage what to load Source plan analysis conclusions + scope_verdict {context.analysis_dir}/conclusions.jsonexecute task list + wave assignments {context.plan_dir}/TASK-*.jsonreview changed files + verification results {context.scratch_dir}/verification.jsontest review findings review.jsondebug error traces + failing test details previous step's completion_evidencebrainstorm grill report {context.grill_id}report -
Explore if needed — the artifact points to a code location but lacks context →
maestro exploresupplement (only for execute/debug/test and when there are file path references) -
Accumulated signals — iterate over ALL completed steps → aggregate caveats + deferred
The loaded content enters the session context, and subsequent inline execution automatically benefits.
A_EXEC_DECISION
- Mark step running, write status.json
- Display:
[{index}/{total}] ◆ {step.decision} Retry: {retry}/{max} Skill(maestro-ralph)— directly invoke ralph evaluation + handoff- Execution ends here
A_EXEC_STEP
-
Load —
Bash("maestro ralph next --session {session_id}")- Exit code 0 → inline-execute according to stdout
- Exit code 2 → all steps completed, transition to S_COMPLETE
- Exit code 3 → active_step_index is already occupied
- Exit code 1 → pause session
-
Goal context pre-injection:
- GUARD:
ralph_protocol_version >= "2"→ skip (session_anchor already contains goal context) - WHEN
ralph_protocol_version < "2"or missing ANDstep.goal_refnon-empty → prepend at the top of stdout:
<goal_context> Sub-goal: {goal.id} — {goal.goal} Done when: {goal.done_when} Boundary: {goal.boundary} Evidence target: {goal.evidence} Execution criteria: {session.execution_criteria joined by '; '} </goal_context> - GUARD:
-
Inline execution — Execute per stdout; Read deferred_reading on demand
-
Complete (all calls MUST include
--session {session_id}):Bash("maestro ralph complete N --session {session_id} --status DONE --summary \"...\" [--evidence <path>] [--decisions \"...\"] [--caveats \"...\"] [--deferred \"...\"]")Bash("maestro ralph complete N --session {session_id} --status DONE_WITH_CONCERNS --summary \"...\" --concerns \"...\"")Bash("maestro ralph retry N --session {session_id}")Bash("maestro ralph complete N --session {session_id} --status BLOCKED --reason \"...\"")
Flag Rule Example --summaryMUST. Start with a verb, ≤100 characters "实现搜索 API 分页,新增 3 端点"--decisionsSHOULD. One decision per entry, may appear multiple times "选择 ELK 而非 dagre"--caveatsSHOULD. Subsequent steps need to pay attention "e2e 未覆盖新端点"--deferredSHOULD. Deferred work, may appear multiple times "性能优化留到 review 后" -
Propagate context signals — Key signals (
PHASE: N/scratch_dir: path/BLP-xxx) written tostatus.json.context
After completion S_LOCATE triggers Skill(maestro-ralph-execute) direct self-invocation.
A_POST_ANALYZE_DRIFT
After execution completes and before calling ralph complete, analyze the degree of deviation between the artifacts and the goal and automatically correct it.
1. Collect comparison baselines:
| Baseline source | Value |
|---|---|
step.goal_ref |
Sub-goal goal_ref association |
session.boundary_contract |
Boundary protocol (e.g. in_scope, out_of_scope ranges) |
2. Read artifact summary:
Build the artifact profile from the summary + decisions + artifacts already extracted by A_EXTRACT_STEP_SIGNALS (step 4a).
3. Comparative scoring (structure and Scope/Contract validation only; semantic quality is left to post-*):
| Dimension | Check |
|---|---|
| Completeness | Whether the expected artifact types are all present (e.g. the plan stage should have plan.json, the execute stage should have the corresponding summaries), structure validation, schema consistency |
| Boundary match | Whether the deliverables and modified files are within boundary_contract.in_scope and do not touch out_of_scope |
drift_score:
ALIGNED— All structure and scope validations passedMINOR_DRIFT— Non-core structural or scope deviations occurred (can be noted in caveats)MAJOR_DRIFT— Core deliverables missing or severely out of boundary range (triggers one retry)
4. Correction actions:
| drift_score | Action |
|---|---|
| ALIGNED | Proceed normally to S_POST_EXEC |
| MINOR_DRIFT | Append the deviation items to completion_caveats, complete normally |
| MAJOR_DRIFT + not retried | Write the deviation analysis to step.drift_correction, return to S_EXECUTE and rerun (A_LOAD_STEP_CONTEXT automatically loads drift_correction as correction context) |
| MAJOR_DRIFT + already retried | Write the deviation items to caveats + concerns, complete with DONE_WITH_CONCERNS, and let the subsequent decision node adjudicate |
5. Write: step.drift_score, step.drift_correction
A_RETRY
Bash("maestro ralph retry N --session {session_id}")— CLI setsstep.retried = true,step.status = "pending",step.completion_confirmed = false, clearsactive_step_index- Display:
[{index}/{total}] ↻ {step.skill} retry
A_SKIP_STEP
Skip execution step — manually edit status.json: set that step status to "skipped",completion_confirmed to false, and clear active_step_index(if it points to this step).
(No CLI subcommand is provided; skipping is a non-standard operation, to avoid misuse by automation.)
A_PAUSE_SESSION
Usually triggered by ralph complete N --status BLOCKED --reason "..." , the CLI has written session.status = "paused". In manual pause scenarios, edit status.json directly.
Display: [{index}/{total}] ✗ {step.skill} 失败,会话已暂停。Skill(maestro-ralph, continue) 恢复。
A_COMPLETE_SESSION
- Validation: all steps
completion_confirmed == true(except skipped); when task_decomposition exists, validatetask_decomposition_all_done == true - If any validation fails → do not mark completed, return to S_LOCATE or pause
session.status = "completed", write status.json- Display completion report:
Icons:============================================================ SESSION COMPLETE ============================================================ Session: {session_id} [{source}] Steps: {completed}/{total} confirmed: {confirmed}/{completed} [✓] 0. maestro-plan 1 [global] [✓] 1. maestro-execute 1 [project] [✓] 2. quality-review 1 [global] [✓] 3. ◆ post-review [decision] ... ============================================================✓confirmed,—skipped,✗failed,◆decision
</state_machine>
Error Codes
| Code | Severity | Description | Recovery |
|---|---|---|---|
| E001 | error | No running session found | Suggest Skill(maestro) or Skill(maestro-ralph) |
| E006 | error | command_path missing/unreachable for execution step | ralph next rejects; edit status.json or rebuild |
| E007 | error | required_reading referenced file missing | ralph next rejects; CLI stderr lists the missing paths |
| E008 | error | ralph complete idx ≠ active_step_index |
Edit status.json to fix consistency |
| E009 | error | ralph complete step.status ≠ running |
Duplicate complete or illegal jump; edit status.json |
| E010 | error | status.json schema corrupted | ralph check show the specific corrupted field |
| W001 | warning | Step completed with concerns | Log and continue |
| W005 | warning | active_step_index points to an already completed step | ralph next continue after automatic cleanup |
| W007 | warning | step.skill ≠ SKILL.md frontmatter.name | warn but do not block |
Success Criteria
- Session discovery covers maestro-* and ralph-*
-
-yparsed from args or session.auto_mode; when auto=true, pass through-yto skill args - Placeholders resolved; per-skill enrichment correct
- Decision node (
step.decision != null) goes throughSkill(maestro-ralph)direct handoff (do not call ralph next CLI) - executing step loaded via
Bash("maestro ralph next"); CLI returns the assembled prompt + completion protocol - required_reading is automatically loaded by the CLI and assembled into the prompt; if missing → CLI exit code 1, pause session
-
<deferred_reading>recorded by the CLI tostep.load.deferred_files, read on demand during execution - at the end of each step, must call
maestro ralph complete N --status <S>ormaestro ralph retry N - STATUS enum only
DONE | DONE_WITH_CONCERNS | NEEDS_RETRY | BLOCKED - active_step_index consistency is maintained by the CLI; E008/E009 exit directly, do not advance silently
- step.completion_evidence passed in via
--evidenceand recorded - Context signals are explicitly written back to status.json.context by the executing step (not embedded scanning in ralph-execute)
- Auto mode: pause after one retry; interactive provides retry/skip/abort
- self-invocation continues until all completion_confirmed or paused
- only handle sessions where session.platform == "codex"
- --from auto-injection: when a milestone-level plan step runs, look up the latest completed analyze artifact for the same milestone from state.json → inject
--from analyze:{id}, writesource_artifact_ref - --from auto-injection: when a phase-level execute step runs, look up the latest completed plan artifact for the same phase+milestone → inject
--dir, writesource_artifact_ref - Goal context injection:
ralph_protocol_version < "2"→ prerequisite<goal_context>block;>= "2"→ skip (session_anchor override) - Goal context includes sub-goal description, done_when, boundary, evidence, execution_criteria
- steps that already have
--fromor--dirare not overwritten by auto-injection -
--summaryis MUST for DONE/DONE_WITH_CONCERNS (starts with a verb, ≤100 characters) -
--decisions/--caveats/--deferredis SHOULD; fill in if there are key decisions/notes/deferred work - structured summary is written to status.json by the CLI, session_anchor automatically aggregates and injects it into downstream steps