@tcanaud/playbook 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,143 @@
1
+ # /playbook.resume — Resume Interrupted Playbook Session
2
+
3
+ **Input**: None — this command takes no arguments. It auto-detects the active session.
4
+
5
+ You are the **Playbook Supervisor** resuming an interrupted session. Your job is to find the last active session, determine where it left off, and continue execution from the correct step.
6
+
7
+ ## 1. Find Repository Root
8
+
9
+ Run `git rev-parse --show-toplevel` to find the repository root. All paths are relative to this root.
10
+
11
+ ## 2. Scan for In-Progress Sessions
12
+
13
+ Scan `.playbooks/sessions/*/session.yaml` for sessions with `status: "in_progress"`.
14
+
15
+ Read each `session.yaml` and check the `status` field.
16
+
17
+ **If no in-progress sessions found**:
18
+ > No active playbook session found. Start a new one with `/playbook.run {playbook} {feature}`.
19
+
20
+ Stop execution.
21
+
22
+ **If multiple in-progress sessions found**:
23
+ - Pick the most recent by session ID (the timestamp prefix `YYYYMMDD` sorts chronologically, then the 3-char suffix breaks ties alphabetically)
24
+ - Report which session was selected
25
+
26
+ **If exactly one found**: Use that session.
27
+
28
+ ## 3. Load Session Context
29
+
30
+ From the selected `session.yaml`, extract:
31
+ - `session_id` — the session identifier
32
+ - `playbook` — the playbook name
33
+ - `feature` — the feature branch name
34
+ - `args` — the resolved arguments
35
+ - `current_step` — the step that was in progress when interrupted
36
+
37
+ Report:
38
+ > Resuming session `{session_id}` — playbook `{playbook}`, feature `{feature}`
39
+
40
+ ## 4. Read the Playbook
41
+
42
+ Read the playbook YAML from `.playbooks/playbooks/{playbook}.yaml`.
43
+
44
+ If the playbook file no longer exists, report error and stop:
45
+ > Playbook `{playbook}` not found. Cannot resume session `{session_id}`.
46
+
47
+ Parse the playbook to get the full step list. Resolve argument interpolation using the session's `args`.
48
+
49
+ ## 5. Read the Journal
50
+
51
+ Read `.playbooks/sessions/{session_id}/journal.yaml` to determine execution state.
52
+
53
+ For each step in the playbook, check the journal:
54
+ - **Step has journal entry with `status: "done"`**: Skip — already completed
55
+ - **Step has journal entry with `status: "skipped"`**: Skip — was intentionally skipped
56
+ - **Step has journal entry with `status: "failed"`**: This is where we stopped — evaluate what to do
57
+ - **Step has journal entry with `status: "in_progress"`**: This step was interrupted — check postconditions
58
+ - **Step has no journal entry**: This step hasn't been attempted yet
59
+
60
+ ## 6. Determine Resume Point
61
+
62
+ ### If the last step has `status: "in_progress"`:
63
+
64
+ Check its **postconditions**:
65
+
66
+ | Condition | Check |
67
+ |-----------|-------|
68
+ | `spec_exists` | File exists: `specs/{feature}/spec.md` |
69
+ | `plan_exists` | File exists: `specs/{feature}/plan.md` |
70
+ | `tasks_exists` | File exists: `specs/{feature}/tasks.md` |
71
+ | `agreement_exists` | File exists: `.agreements/{feature}/agreement.yaml` |
72
+ | `agreement_pass` | File `.agreements/{feature}/check-report.md` contains `verdict: PASS` |
73
+ | `qa_plan_exists` | File exists: `.qa/{feature}/test-plan.md` OR `.qa/{feature}/_index.yaml` |
74
+ | `qa_verdict_pass` | File `.qa/{feature}/verdict.yaml` contains `verdict: PASS` |
75
+ | `pr_created` | Run `gh pr list --head "{feature}" --json number --jq 'length'` — result > 0 |
76
+
77
+ **If ALL postconditions pass**: The step actually completed before the crash. Update its journal entry to `done`, compute duration, and advance to the next step.
78
+
79
+ **If ANY postcondition fails**: The step did not complete. Re-run it from scratch.
80
+
81
+ ### If the last step has `status: "failed"`:
82
+
83
+ Report the failure and ask the user:
84
+ > Step `{step_id}` previously failed with error: "{error}". Retry this step? (yes/skip/abort)
85
+
86
+ ### If there's no in-progress or failed step:
87
+
88
+ Find the first step with no journal entry. That's the resume point.
89
+
90
+ ## 7. Report Resume Status
91
+
92
+ Display a summary before continuing:
93
+
94
+ ```
95
+ Session: {session_id}
96
+ Playbook: {playbook} ({description})
97
+ Feature: {feature}
98
+
99
+ Progress:
100
+ {step_id}: done (auto) — {duration}s
101
+ {step_id}: done (gate) — {duration}s
102
+ {step_id}: in_progress → resuming
103
+ {step_id}: pending
104
+ ...
105
+
106
+ Resuming from step: {step_id}
107
+ ```
108
+
109
+ ## 8. Continue Execution
110
+
111
+ Resume the orchestration loop using the exact same logic as `/playbook.run`:
112
+
113
+ For each remaining step (from the resume point):
114
+
115
+ 1. **Check preconditions** — evaluate each condition
116
+ 2. **Evaluate autonomy level** — auto, gate_on_breaking, gate_always, skip
117
+ 3. **Delegate via Task subagent** — fresh context per step
118
+ 4. **Check postconditions** — verify artifacts exist
119
+ 5. **Handle escalation triggers** — promote auto to gate if trigger fires
120
+ 6. **Apply error policy** — stop, retry_once, gate
121
+ 7. **Write journal entry** — record step outcome with all audit fields
122
+ 8. **Advance** — move to next step
123
+
124
+ Update `session.yaml` `current_step` before each step execution.
125
+
126
+ ## 9. Completion
127
+
128
+ When all remaining steps are done (or session is failed/aborted):
129
+
130
+ 1. Update `session.yaml`:
131
+ - `status`: `completed` | `failed` | `aborted`
132
+ - `completed_at`: current ISO 8601 timestamp
133
+ - `current_step`: empty
134
+
135
+ 2. Report final summary with full journal overview.
136
+
137
+ ## Rules
138
+
139
+ - **No arguments required**: Auto-detect everything from the filesystem
140
+ - **No duplicate execution**: Never re-run a step that has `status: "done"` in the journal
141
+ - **Postcondition-based recovery**: Use postcondition checks to determine if an interrupted step actually completed
142
+ - **Same orchestration logic**: The execution loop is identical to `/playbook.run` — same conditions, same gates, same error policies
143
+ - **Journal continuity**: New journal entries are appended — never overwrite existing entries (except updating in_progress → done for recovered steps)
@@ -0,0 +1,214 @@
1
+ # /playbook.run — Playbook Supervisor
2
+
3
+ **Input**: `$ARGUMENTS` — `{playbook} {feature}` (e.g., `auto-feature 012-playbook-supervisor`)
4
+
5
+ You are the **Playbook Supervisor**. You orchestrate a sequence of workflow steps defined in a YAML playbook, delegating each step to a Task subagent with fresh context. You are NOT an executor — you are the orchestrator. You use the same slash commands as manual execution. No bypass, no shortcut.
6
+
7
+ ## 1. Parse Arguments
8
+
9
+ Extract from `$ARGUMENTS`:
10
+ - `PLAYBOOK` — first word (playbook name, e.g., `auto-feature`)
11
+ - `FEATURE` — second word (feature branch name, e.g., `012-playbook-supervisor`)
12
+
13
+ If either is missing, ask the user: "Usage: /playbook.run {playbook} {feature}"
14
+
15
+ ## 2. Read Playbook
16
+
17
+ Read the playbook YAML from `.playbooks/playbooks/{PLAYBOOK}.yaml`.
18
+
19
+ If the file does not exist, report error and stop:
20
+ > Playbook `{PLAYBOOK}` not found at `.playbooks/playbooks/{PLAYBOOK}.yaml`
21
+
22
+ Parse the playbook manually — extract:
23
+ - `name`, `description`, `version`
24
+ - `args[]` — declared arguments with names and required flags
25
+ - `steps[]` — ordered list of step definitions
26
+
27
+ Resolve argument interpolation: replace all `{{feature}}` references in step `args` with the actual `FEATURE` value. Do the same for any other declared args.
28
+
29
+ Validate that all required args are provided. If a required arg is missing, ask the user.
30
+
31
+ ## 3. Session Management
32
+
33
+ ### Check for existing session
34
+
35
+ Scan `.playbooks/sessions/*/session.yaml` for a session where:
36
+ - `playbook` matches `PLAYBOOK`
37
+ - `feature` matches `FEATURE`
38
+ - `status` is `in_progress`
39
+
40
+ **If found**: Resume that session (skip to step 5 with the existing session).
41
+
42
+ ### Create new session
43
+
44
+ If no existing session found:
45
+
46
+ 1. Generate session ID: `{YYYYMMDD}-{3char}` (e.g., `20260219-a7k`) where 3char is random lowercase alphanumeric
47
+ 2. Create directory `.playbooks/sessions/{id}/`
48
+ 3. Write `session.yaml`:
49
+ ```yaml
50
+ session_id: "{id}"
51
+ playbook: "{PLAYBOOK}"
52
+ feature: "{FEATURE}"
53
+ args:
54
+ feature: "{FEATURE}"
55
+ status: "in_progress"
56
+ started_at: "{ISO 8601 now}"
57
+ completed_at: ""
58
+ current_step: ""
59
+ worktree: ""
60
+ ```
61
+ 4. Write `journal.yaml`:
62
+ ```yaml
63
+ entries: []
64
+ ```
65
+ 5. Report: `Session {id} created for playbook {PLAYBOOK}`
66
+
67
+ ## 4. Pre-flight Validation
68
+
69
+ Before executing any steps, verify:
70
+ - All slash commands referenced in steps exist (check `.claude/commands/` for the command files, or trust that they are available as skills)
71
+ - Report any missing commands and stop
72
+
73
+ ## 5. Orchestration Loop
74
+
75
+ For each step in the playbook (in order):
76
+
77
+ ### 5a. Check Preconditions
78
+
79
+ For each condition in the step's `preconditions[]`, evaluate:
80
+
81
+ | Condition | Check |
82
+ |-----------|-------|
83
+ | `spec_exists` | File exists: `specs/{FEATURE}/spec.md` |
84
+ | `plan_exists` | File exists: `specs/{FEATURE}/plan.md` |
85
+ | `tasks_exists` | File exists: `specs/{FEATURE}/tasks.md` |
86
+ | `agreement_exists` | File exists: `.agreements/{FEATURE}/agreement.yaml` |
87
+ | `agreement_pass` | File `.agreements/{FEATURE}/check-report.md` contains `verdict: PASS` |
88
+ | `qa_plan_exists` | File exists: `.qa/{FEATURE}/test-plan.md` OR `.qa/{FEATURE}/_index.yaml` |
89
+ | `qa_verdict_pass` | File `.qa/{FEATURE}/verdict.yaml` contains `verdict: PASS` |
90
+ | `pr_created` | Run `gh pr list --head "{FEATURE}" --json number --jq 'length'` — result > 0 |
91
+
92
+ If ANY precondition fails:
93
+ - Report which precondition failed and what artifact is missing
94
+ - **Do NOT proceed with this step** — halt and explain what needs to happen first
95
+ - If a previous step should have produced this artifact, investigate why it didn't
96
+
97
+ ### 5b. Evaluate Autonomy Level
98
+
99
+ | Autonomy | Behavior |
100
+ |----------|----------|
101
+ | `auto` | Execute without asking. Proceed directly to delegation. |
102
+ | `gate_on_breaking` | Check if a breaking change is detected (for agreement checks). If breaking: halt and ask. If not: proceed like auto. |
103
+ | `gate_always` | Always halt. Present context and ask before proceeding. |
104
+ | `skip` | Do not execute. Log as skipped. Move to next step. |
105
+
106
+ **Gate Protocol** (when halting):
107
+ 1. Present a clear summary: step name, command, what it will do
108
+ 2. Ask: "Proceed with step '{id}' ({command})? (yes/no/abort)"
109
+ 3. Wait for user response
110
+ 4. If "yes" or "continue": proceed with delegation
111
+ 5. If "no" or "skip": log as skipped, move to next step
112
+ 6. If "abort": mark session as aborted, stop execution
113
+
114
+ ### 5c. Delegate to Task Subagent
115
+
116
+ Record the step start time.
117
+
118
+ Update `session.yaml`: set `current_step` to the step ID.
119
+
120
+ Use the **Task tool** to delegate the step:
121
+ - Launch a subagent with `subagent_type: "general-purpose"`
122
+ - The prompt MUST include:
123
+ - The slash command to execute (e.g., "Execute /speckit.plan")
124
+ - The arguments (with resolved interpolation)
125
+ - The feature context
126
+ - Instruction to use the Skill tool to invoke the slash command
127
+ - Each subagent gets **fresh context** — no accumulated state from previous steps
128
+
129
+ **Parallel phases**: If multiple steps share the same `parallel_group`, launch ALL of them in a single message using multiple Task tool calls. Wait for all to complete before continuing.
130
+
131
+ ### 5d. Check Postconditions
132
+
133
+ After the subagent completes, evaluate each condition in `postconditions[]` using the same checks as preconditions (table in 5a).
134
+
135
+ If ALL postconditions pass: mark step as **done**.
136
+
137
+ If ANY postcondition fails: check escalation triggers.
138
+
139
+ ### 5e. Handle Escalation Triggers
140
+
141
+ If a postcondition failed AND the step has escalation triggers:
142
+
143
+ | Trigger | Fires When |
144
+ |---------|-----------|
145
+ | `postcondition_fail` | Any postcondition check fails |
146
+ | `verdict_fail` | QA verdict file contains FAIL |
147
+ | `agreement_breaking` | Agreement check found breaking changes |
148
+ | `subagent_error` | The Task subagent returned an error |
149
+
150
+ If a trigger fires on an `auto` step: **promote to gate**. Present the failure to the user and ask for a decision.
151
+
152
+ ### 5f. Apply Error Policy
153
+
154
+ If the step failed (postcondition fail, subagent error):
155
+
156
+ | Policy | Behavior |
157
+ |--------|----------|
158
+ | `stop` | Mark session as failed. Stop all execution. Report the failure. |
159
+ | `retry_once` | Re-execute the step ONE time. If it fails again, apply `stop`. |
160
+ | `gate` | Escalate to the user. Present the failure context. Ask: "Fix and continue, or abort?" |
161
+
162
+ ### 5g. Write Journal Entry
163
+
164
+ After each step (whether done, failed, or skipped), append a journal entry to `journal.yaml`:
165
+
166
+ ```yaml
167
+ - step_id: "{id}"
168
+ status: "done" # done | failed | skipped
169
+ decision: "auto" # auto | gate | escalated | skipped
170
+ started_at: "{ISO 8601}"
171
+ completed_at: "{ISO 8601}"
172
+ duration_seconds: {N}
173
+ trigger: "" # escalation trigger if any
174
+ human_response: "" # user's response at gate if any
175
+ error: "" # error message if failed
176
+ ```
177
+
178
+ Only include `trigger`, `human_response`, and `error` fields when they have values.
179
+
180
+ ### 5h. Advance to Next Step
181
+
182
+ Move to the next step in the playbook and repeat from 5a.
183
+
184
+ ## 6. Completion
185
+
186
+ When all steps are done (or the session is failed/aborted):
187
+
188
+ 1. Update `session.yaml`:
189
+ - `status`: `completed` (all done) | `failed` (step failed with stop) | `aborted` (user aborted)
190
+ - `completed_at`: current ISO 8601 timestamp
191
+ - `current_step`: empty
192
+
193
+ 2. Report final summary:
194
+ ```
195
+ Playbook {PLAYBOOK} — {status}
196
+
197
+ Steps: {done}/{total}
198
+ Duration: {total duration}
199
+
200
+ Journal: .playbooks/sessions/{id}/journal.yaml
201
+
202
+ Step results:
203
+ {step_id}: {status} ({decision}) — {duration}s
204
+ ...
205
+ ```
206
+
207
+ ## Rules
208
+
209
+ - **Same commands as manual**: You execute the same slash commands a developer would type manually. No bypass.
210
+ - **Fresh context per step**: Each Task subagent starts clean. No state leaks between steps.
211
+ - **Journal is the truth**: Every decision, every gate response, every error is recorded in the journal.
212
+ - **Deterministic behavior**: Autonomy levels, conditions, error policies are a fixed vocabulary. Follow them exactly.
213
+ - **No invention**: Do not add steps, skip conditions, or modify the playbook at runtime.
214
+ - **Idempotent resume**: If this command is re-run with the same playbook and feature, it finds the existing session and resumes.
@@ -0,0 +1,15 @@
1
+ # Playbook Index
2
+ # Auto-generated by @tcanaud/playbook init/update
3
+ # Lists all available playbooks in this project.
4
+
5
+ generated: "{{TIMESTAMP}}"
6
+
7
+ playbooks:
8
+ - name: "auto-feature"
9
+ file: "playbooks/auto-feature.yaml"
10
+ description: "Full feature workflow from plan to PR"
11
+ steps: 8
12
+ - name: "auto-validate"
13
+ file: "playbooks/auto-validate.yaml"
14
+ description: "QA validation: plan and run"
15
+ steps: 2
@@ -0,0 +1,88 @@
1
+ # Playbook Template
2
+ # Copy this file and customize it for your workflow.
3
+ # Validate with: npx @tcanaud/playbook check <file>
4
+ #
5
+ # ── Schema Reference ────────────────────────────────────
6
+ #
7
+ # Top-level fields (all required):
8
+ # name: Unique identifier [a-z0-9-]+
9
+ # description: Human-readable purpose
10
+ # version: Schema version (e.g., "1.0")
11
+ #
12
+ # args (required, may be empty array):
13
+ # - name: Argument name, referenced as {{name}} in step args
14
+ # description: Purpose of the argument
15
+ # required: true | false
16
+ #
17
+ # steps (required, min 1):
18
+ # - id: Unique within playbook [a-z0-9-]+
19
+ # command: Slash command to execute (e.g., "/speckit.plan")
20
+ # args: Optional — supports {{arg}} interpolation
21
+ # autonomy: Decision mode (see below)
22
+ # preconditions: Optional list of artifact checks (see below)
23
+ # postconditions: Optional list of artifact checks (see below)
24
+ # error_policy: Behavior on failure (see below)
25
+ # escalation_triggers: Optional list of triggers (see below)
26
+ # parallel_group: Optional — steps with same group run concurrently
27
+ #
28
+ # ── Autonomy Levels ─────────────────────────────────────
29
+ # auto Execute without human interaction
30
+ # gate_on_breaking Gate only when a breaking change is detected
31
+ # gate_always Always halt for human decision
32
+ # skip Skip execution, log as skipped
33
+ #
34
+ # ── Error Policies ──────────────────────────────────────
35
+ # stop Halt all execution, mark session as failed
36
+ # retry_once Re-execute once; if still fails, stop
37
+ # gate Escalate to human decision with failure context
38
+ #
39
+ # ── Escalation Triggers ────────────────────────────────
40
+ # postcondition_fail Any postcondition fails after step execution
41
+ # verdict_fail QA verdict file contains FAIL
42
+ # agreement_breaking Agreement check detects breaking changes
43
+ # subagent_error Task subagent returns error or crashes
44
+ #
45
+ # ── Conditions (Pre/Post) ──────────────────────────────
46
+ # spec_exists specs/{feature}/spec.md exists
47
+ # plan_exists specs/{feature}/plan.md exists
48
+ # tasks_exists specs/{feature}/tasks.md exists
49
+ # agreement_exists .agreements/{feature}/agreement.yaml exists
50
+ # agreement_pass .agreements/{feature}/check-report.md verdict: PASS
51
+ # qa_plan_exists .qa/{feature}/test-plan.md exists
52
+ # qa_verdict_pass .qa/{feature}/verdict.md verdict: PASS
53
+ # pr_created gh pr list --head {branch} returns non-empty
54
+ #
55
+ # ════════════════════════════════════════════════════════
56
+
57
+ name: "my-workflow"
58
+ description: "Describe your workflow here"
59
+ version: "1.0"
60
+
61
+ args:
62
+ - name: "feature"
63
+ description: "Feature branch name"
64
+ required: true
65
+
66
+ steps:
67
+ - id: "step-1"
68
+ command: "/speckit.plan"
69
+ args: ""
70
+ autonomy: "auto"
71
+ preconditions:
72
+ - "spec_exists"
73
+ postconditions:
74
+ - "plan_exists"
75
+ error_policy: "stop"
76
+ escalation_triggers: []
77
+
78
+ # Add more steps below following the same structure.
79
+ # Use parallel_group to run steps concurrently:
80
+ #
81
+ # - id: "step-a"
82
+ # command: "/some.command"
83
+ # parallel_group: "phase-2"
84
+ # ...
85
+ # - id: "step-b"
86
+ # command: "/other.command"
87
+ # parallel_group: "phase-2"
88
+ # ...
@@ -0,0 +1,100 @@
1
+ name: "auto-feature"
2
+ description: "Full feature workflow from plan to PR"
3
+ version: "1.0"
4
+
5
+ args:
6
+ - name: "feature"
7
+ description: "Feature branch name (e.g., 012-playbook-supervisor)"
8
+ required: true
9
+
10
+ steps:
11
+ - id: "plan"
12
+ command: "/speckit.plan"
13
+ args: ""
14
+ autonomy: "auto"
15
+ preconditions:
16
+ - "spec_exists"
17
+ postconditions:
18
+ - "plan_exists"
19
+ error_policy: "stop"
20
+ escalation_triggers: []
21
+
22
+ - id: "tasks"
23
+ command: "/speckit.tasks"
24
+ args: ""
25
+ autonomy: "auto"
26
+ preconditions:
27
+ - "plan_exists"
28
+ postconditions:
29
+ - "tasks_exists"
30
+ error_policy: "stop"
31
+ escalation_triggers: []
32
+
33
+ - id: "agreement"
34
+ command: "/agreement.create"
35
+ args: "{{feature}}"
36
+ autonomy: "auto"
37
+ preconditions:
38
+ - "tasks_exists"
39
+ postconditions:
40
+ - "agreement_exists"
41
+ error_policy: "gate"
42
+ escalation_triggers:
43
+ - "subagent_error"
44
+
45
+ - id: "implement"
46
+ command: "/speckit.implement"
47
+ args: ""
48
+ autonomy: "auto"
49
+ preconditions:
50
+ - "agreement_exists"
51
+ postconditions: []
52
+ error_policy: "retry_once"
53
+ escalation_triggers:
54
+ - "postcondition_fail"
55
+ - "subagent_error"
56
+
57
+ - id: "agreement-check"
58
+ command: "/agreement.check"
59
+ args: "{{feature}}"
60
+ autonomy: "gate_on_breaking"
61
+ preconditions: []
62
+ postconditions:
63
+ - "agreement_pass"
64
+ error_policy: "gate"
65
+ escalation_triggers:
66
+ - "agreement_breaking"
67
+
68
+ - id: "qa-plan"
69
+ command: "/qa.plan"
70
+ args: "{{feature}}"
71
+ autonomy: "auto"
72
+ preconditions:
73
+ - "agreement_pass"
74
+ postconditions:
75
+ - "qa_plan_exists"
76
+ error_policy: "stop"
77
+ escalation_triggers: []
78
+
79
+ - id: "qa-run"
80
+ command: "/qa.run"
81
+ args: "{{feature}}"
82
+ autonomy: "auto"
83
+ preconditions:
84
+ - "qa_plan_exists"
85
+ postconditions:
86
+ - "qa_verdict_pass"
87
+ error_policy: "gate"
88
+ escalation_triggers:
89
+ - "verdict_fail"
90
+
91
+ - id: "pr"
92
+ command: "/feature.pr"
93
+ args: "{{feature}}"
94
+ autonomy: "gate_always"
95
+ preconditions:
96
+ - "qa_verdict_pass"
97
+ postconditions:
98
+ - "pr_created"
99
+ error_policy: "stop"
100
+ escalation_triggers: []
@@ -0,0 +1,31 @@
1
+ name: "auto-validate"
2
+ description: "QA validation: plan and run"
3
+ version: "1.0"
4
+
5
+ args:
6
+ - name: "feature"
7
+ description: "Feature branch name (e.g., 012-playbook-supervisor)"
8
+ required: true
9
+
10
+ steps:
11
+ - id: "qa-plan"
12
+ command: "/qa.plan"
13
+ args: "{{feature}}"
14
+ autonomy: "auto"
15
+ preconditions:
16
+ - "spec_exists"
17
+ postconditions:
18
+ - "qa_plan_exists"
19
+ error_policy: "stop"
20
+ escalation_triggers: []
21
+
22
+ - id: "qa-run"
23
+ command: "/qa.run"
24
+ args: "{{feature}}"
25
+ autonomy: "auto"
26
+ preconditions:
27
+ - "qa_plan_exists"
28
+ postconditions:
29
+ - "qa_verdict_pass"
30
+ error_policy: "stop"
31
+ escalation_triggers: []