feat: add unified release workflow (develop/debug/verify/release)
Adds .claude/workflows/release.js — a single Workflow script covering the full Relicario release lifecycle: - develop (single: sequential agent pipeline; multi: PM/Dev kickoff generation) - debug: iterative fix loop up to 5 passes - verify: full cargo test/build/clippy sweep - release: CHANGELOG + tag, stops before push Adds docs/superpowers/RELEASE-WORKFLOW.md with invocation examples and phone-vs-PC patterns. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
375
.claude/workflows/release.js
Normal file
375
.claude/workflows/release.js
Normal file
@@ -0,0 +1,375 @@
|
|||||||
|
export const meta = {
|
||||||
|
name: 'release',
|
||||||
|
description: 'Relicario release lifecycle: develop features (single/multi-agent), iterate on debug, cut releases',
|
||||||
|
phases: [
|
||||||
|
{ title: 'Discover' },
|
||||||
|
{ title: 'Plan' },
|
||||||
|
{ title: 'Execute' },
|
||||||
|
{ title: 'Verify' },
|
||||||
|
{ title: 'Generate' },
|
||||||
|
{ title: 'Finalize' },
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Schemas ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
const MANIFEST_SCHEMA = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
plans: { type: 'array', items: { type: 'string' } },
|
||||||
|
taskCount: { type: 'number' },
|
||||||
|
domains: { type: 'array', items: { type: 'string' } },
|
||||||
|
},
|
||||||
|
required: ['plans', 'taskCount', 'domains'],
|
||||||
|
}
|
||||||
|
|
||||||
|
const TASK_LIST_SCHEMA = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
tasks: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
id: { type: 'string' },
|
||||||
|
description: { type: 'string' },
|
||||||
|
planPath: { type: 'string' },
|
||||||
|
techDomain: { type: 'string' },
|
||||||
|
},
|
||||||
|
required: ['id', 'description', 'planPath', 'techDomain'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ['tasks'],
|
||||||
|
}
|
||||||
|
|
||||||
|
const ASSIGNMENT_SCHEMA = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
devCount: { type: 'number' },
|
||||||
|
devs: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
letter: { type: 'string' },
|
||||||
|
scope: { type: 'string' },
|
||||||
|
tasks: { type: 'array', items: { type: 'string' } },
|
||||||
|
outOfScope: { type: 'array', items: { type: 'string' } },
|
||||||
|
techDomain: { type: 'string' },
|
||||||
|
planFiles: { type: 'array', items: { type: 'string' } },
|
||||||
|
},
|
||||||
|
required: ['letter', 'scope', 'tasks', 'outOfScope', 'techDomain', 'planFiles'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pmScope: { type: 'string' },
|
||||||
|
},
|
||||||
|
required: ['devCount', 'devs', 'pmScope'],
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEBUG_RESULT_SCHEMA = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
fixed: { type: 'boolean' },
|
||||||
|
summary: { type: 'string' },
|
||||||
|
remainingFailures: { type: 'string' },
|
||||||
|
},
|
||||||
|
required: ['fixed', 'summary'],
|
||||||
|
}
|
||||||
|
|
||||||
|
const VERIFY_RESULT_SCHEMA = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
allPass: { type: 'boolean' },
|
||||||
|
failures: { type: 'array', items: { type: 'string' } },
|
||||||
|
summary: { type: 'string' },
|
||||||
|
},
|
||||||
|
required: ['allPass', 'failures', 'summary'],
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Helpers ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
const REPO = '/home/alee/Sources/relicario'
|
||||||
|
const COORD_DIR = 'docs/superpowers/coordination'
|
||||||
|
|
||||||
|
function devRole(letter) {
|
||||||
|
return 'dev-' + letter.toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Routing ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
const action = (args && args.action) || 'develop'
|
||||||
|
const mode = (args && args.mode) || 'single'
|
||||||
|
const release = args && args.release
|
||||||
|
const context = args && args.context
|
||||||
|
|
||||||
|
// ── ACTION: develop ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
if (action === 'develop') {
|
||||||
|
if (!release) throw new Error('args.release is required for action=develop')
|
||||||
|
|
||||||
|
phase('Discover')
|
||||||
|
const manifest = await agent(
|
||||||
|
`Scan docs/superpowers/plans/ in ${REPO} for plan files belonging to release "${release}". ` +
|
||||||
|
`A plan file belongs if its filename contains the release label, or its opening lines reference it as its target release. ` +
|
||||||
|
`Read each matching file, count checkbox tasks (lines starting with - [ ]), and identify tech domains (rust, extension, docs, etc.). ` +
|
||||||
|
`Return: plans (relative paths from repo root), taskCount, domains.`,
|
||||||
|
{ schema: MANIFEST_SCHEMA, label: 'discover-plans', phase: 'Discover' }
|
||||||
|
)
|
||||||
|
|
||||||
|
log(`Found ${manifest.plans.length} plan(s), ${manifest.taskCount} tasks — domains: ${manifest.domains.join(', ')}`)
|
||||||
|
|
||||||
|
// ── SINGLE MODE ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
if (mode === 'single') {
|
||||||
|
|
||||||
|
phase('Plan')
|
||||||
|
const taskList = await agent(
|
||||||
|
`You are the PM for the ${release} release of Relicario at ${REPO}.\n` +
|
||||||
|
`Read these plan files:\n${manifest.plans.map(p => ' ' + p).join('\n')}\n\n` +
|
||||||
|
`Extract every checkbox task (- [ ] items) and order them to respect dependencies ` +
|
||||||
|
`(e.g. core Rust changes before WASM/CLI consumers, schema changes before UI). ` +
|
||||||
|
`For each task return: id (short slug like S1-step2), description (full step text), ` +
|
||||||
|
`planPath (which file it came from), techDomain (rust/extension/docs/cli/wasm).`,
|
||||||
|
{ schema: TASK_LIST_SCHEMA, label: 'pm-plan', phase: 'Plan' }
|
||||||
|
)
|
||||||
|
|
||||||
|
log(`PM ordered ${taskList.tasks.length} tasks for sequential execution`)
|
||||||
|
|
||||||
|
phase('Execute')
|
||||||
|
await pipeline(
|
||||||
|
taskList.tasks,
|
||||||
|
(task) => agent(
|
||||||
|
`You are a senior developer on the ${release} release of Relicario.\n` +
|
||||||
|
`Repo: ${REPO}\n\n` +
|
||||||
|
`IMPORTANT: cd into ${REPO} before any git or cargo commands.\n\n` +
|
||||||
|
`Your task (${task.id}): ${task.description}\n` +
|
||||||
|
`Plan file for full context: ${task.planPath}\n` +
|
||||||
|
`Tech domain: ${task.techDomain}\n\n` +
|
||||||
|
`Instructions:\n` +
|
||||||
|
`1. Read the plan file for context on this specific step.\n` +
|
||||||
|
`2. Implement ONLY this step — do not run ahead to the next one.\n` +
|
||||||
|
`3. Run the relevant tests after your change (cargo test -p <crate> for Rust; pnpm build for extension).\n` +
|
||||||
|
`4. Commit with a conventional commit message scoped to the change.\n` +
|
||||||
|
`5. Report: what you did, test result (pass/fail), any blockers.`,
|
||||||
|
{ label: task.id, phase: 'Execute' }
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
phase('Verify')
|
||||||
|
const verifyResult = await agent(
|
||||||
|
`Run the full Relicario test suite from ${REPO}. IMPORTANT: cd ${REPO} first.\n` +
|
||||||
|
`Commands:\n` +
|
||||||
|
` cargo test\n` +
|
||||||
|
` cargo build --all-targets\n` +
|
||||||
|
` cargo clippy -- -D warnings\n` +
|
||||||
|
`Report pass/fail for each command. List every failure with its error message.`,
|
||||||
|
{ schema: VERIFY_RESULT_SCHEMA, label: 'full-verify', phase: 'Verify' }
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!verifyResult.allPass) {
|
||||||
|
log(`Verify FAILED — ${verifyResult.failures.length} failure(s): ${verifyResult.failures.join(' | ')}`)
|
||||||
|
log(`Fix with: Workflow({name:"release", args:{action:"debug", context:"<paste failures>"}})`)
|
||||||
|
return { status: 'verify-failed', failures: verifyResult.failures, summary: verifyResult.summary }
|
||||||
|
}
|
||||||
|
|
||||||
|
phase('Finalize')
|
||||||
|
await agent(
|
||||||
|
`Update ${REPO}/STATUS.md to reflect the ${release} work that just completed.\n` +
|
||||||
|
`Mark any in-flight items as landed. Set what is now in flight next.\n` +
|
||||||
|
`Commit the STATUS.md update with message "docs: update STATUS for ${release} develop pass".`,
|
||||||
|
{ label: 'update-status', phase: 'Finalize' }
|
||||||
|
)
|
||||||
|
|
||||||
|
log(`Single-mode develop complete. Run action=release when ready to tag.`)
|
||||||
|
return { status: 'complete', mode: 'single', release }
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── MULTI MODE ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
phase('Plan')
|
||||||
|
const assignment = await agent(
|
||||||
|
`You are the PM for the ${release} release of Relicario at ${REPO}.\n` +
|
||||||
|
`Read these plan files:\n${manifest.plans.map(p => ' ' + p).join('\n')}\n\n` +
|
||||||
|
`Decide how many dev streams are needed (one per major domain or plan, max 3). ` +
|
||||||
|
`Minimize cross-dev dependencies. For each dev assign: ` +
|
||||||
|
`letter (A/B/C), scope summary (2 sentences), task IDs they own, ` +
|
||||||
|
`out-of-scope task IDs (owned by other devs), primary techDomain, and which planFiles they need to read. ` +
|
||||||
|
`Also write a 2-sentence pmScope describing your oversight and review duties.`,
|
||||||
|
{ schema: ASSIGNMENT_SCHEMA, label: 'pm-assign', phase: 'Plan' }
|
||||||
|
)
|
||||||
|
|
||||||
|
log(`PM assigned ${assignment.devCount} dev stream(s)`)
|
||||||
|
|
||||||
|
phase('Generate')
|
||||||
|
const allRoles = ['pm', ...assignment.devs.map(d => devRole(d.letter))].join(', ')
|
||||||
|
|
||||||
|
await parallel([
|
||||||
|
|
||||||
|
() => agent(
|
||||||
|
`Write a self-contained PM kickoff prompt to ${REPO}/${COORD_DIR}/${release}-pm-prompt.md.\n\n` +
|
||||||
|
`Release: ${release}\n` +
|
||||||
|
`PM scope: ${assignment.pmScope}\n` +
|
||||||
|
`Plans: ${manifest.plans.join(', ')}\n` +
|
||||||
|
`Dev roster:\n${assignment.devs.map(d => ` Dev-${d.letter}: ${d.scope}`).join('\n')}\n\n` +
|
||||||
|
`The file must include these sections in order:\n` +
|
||||||
|
`1. Role header ("You are the PM for the ${release} release of Relicario.")\n` +
|
||||||
|
`2. Working directory: ${REPO}\n` +
|
||||||
|
`3. Required reading: CLAUDE.md, all plan files listed above\n` +
|
||||||
|
`4. Authority: approve scope changes, review dev PRs, write CHANGELOG entry, drive doc updates, tag release (with user approval only)\n` +
|
||||||
|
`5. Boundaries: write NO feature code; NO destructive ops without user confirmation\n` +
|
||||||
|
`6. Relay server section: localhost:7331, your from="pm", tools: post_message/read_messages/list_pending, recipients: ${allRoles}. Include Python shim fallback.\n` +
|
||||||
|
`7. Dev roster with each dev letter, branch name (feature/${release}-dev-X), worktree path (${REPO}.dev-x), and scope\n` +
|
||||||
|
`8. Coordination protocol: DIRECTIVE block format, RELEASE STATUS rollup format\n` +
|
||||||
|
`9. PR review procedure (gh pr view / gh pr diff)\n` +
|
||||||
|
`10. Pre-tag checklist (all tests pass, CHANGELOG written, STATUS.md updated, all dev PRs merged)\n` +
|
||||||
|
`11. First action: read all required files, emit a RELEASE STATUS block confirming context absorbed, then check all dev inboxes\n` +
|
||||||
|
`Make every section concrete — the receiving Claude has zero prior context.`,
|
||||||
|
{ label: 'gen-pm', phase: 'Generate' }
|
||||||
|
),
|
||||||
|
|
||||||
|
...assignment.devs.map((dev) => () => agent(
|
||||||
|
`Write a self-contained Dev-${dev.letter} kickoff prompt to ${REPO}/${COORD_DIR}/${release}-dev-${dev.letter.toLowerCase()}-prompt.md.\n\n` +
|
||||||
|
`Release: ${release}\n` +
|
||||||
|
`Dev-${dev.letter} scope: ${dev.scope}\n` +
|
||||||
|
`Tasks owned: ${dev.tasks.join(', ')}\n` +
|
||||||
|
`Out of scope: ${dev.outOfScope.join(', ')}\n` +
|
||||||
|
`Tech domain: ${dev.techDomain}\n` +
|
||||||
|
`Plan files: ${dev.planFiles.join(', ')}\n\n` +
|
||||||
|
`The file must include these sections in order:\n` +
|
||||||
|
`1. Role header ("You are Dev-${dev.letter} for the ${release} release of Relicario.")\n` +
|
||||||
|
`2. Worktree setup commands (run these FIRST before anything else):\n` +
|
||||||
|
` git -C ${REPO} worktree add ${REPO}.dev-${dev.letter.toLowerCase()} -b feature/${release}-dev-${dev.letter.toLowerCase()}\n` +
|
||||||
|
` cd ${REPO}.dev-${dev.letter.toLowerCase()}\n` +
|
||||||
|
`3. Working directory after setup: ${REPO}.dev-${dev.letter.toLowerCase()}\n` +
|
||||||
|
`4. CRITICAL subagent rule: every subagent prompt MUST start with "cd ${REPO}.dev-${dev.letter.toLowerCase()} &&" — never rely on working-directory headers alone\n` +
|
||||||
|
`5. Required reading: CLAUDE.md, ${dev.planFiles.join(', ')}\n` +
|
||||||
|
`6. Execution mode: use superpowers:subagent-driven-development\n` +
|
||||||
|
`7. Scope: in-scope tasks (${dev.tasks.join(', ')}), out-of-scope (${dev.outOfScope.join(', ')})\n` +
|
||||||
|
`8. Hard rules from the plan (copy any HIGH-severity or acceptance-test constraints verbatim)\n` +
|
||||||
|
`9. Relay: localhost:7331, your from="${devRole(dev.letter)}", call read_messages before each task, post status/questions to "pm". Recipients: ${allRoles}. Include Python shim fallback.\n` +
|
||||||
|
`10. STATUS UPDATE format: Task / Status (COMPLETE|IN-PROGRESS|BLOCKED) / Notes (what + why) / Next — print locally AND post to pm via relay\n` +
|
||||||
|
`11. Final test commands for ${dev.techDomain}\n` +
|
||||||
|
`12. PR procedure: gh pr create targeting main, title "feat(${release}): Dev-${dev.letter} — <scope>"\n` +
|
||||||
|
`13. First action: run worktree setup, emit STATUS UPDATE "setup complete", start Task 1`,
|
||||||
|
{ label: `gen-dev-${dev.letter.toLowerCase()}`, phase: 'Generate' }
|
||||||
|
)),
|
||||||
|
|
||||||
|
])
|
||||||
|
|
||||||
|
log(`Generated ${assignment.devCount + 1} prompt files in ${COORD_DIR}/`)
|
||||||
|
log(``)
|
||||||
|
log(`Next steps:`)
|
||||||
|
log(` 1. cd ${REPO}/tools/relay && ./start.sh`)
|
||||||
|
log(` 2. Open ${assignment.devCount + 1} terminal windows`)
|
||||||
|
log(` 3. PM terminal → paste ${COORD_DIR}/${release}-pm-prompt.md`)
|
||||||
|
assignment.devs.forEach(dev => {
|
||||||
|
log(` Dev-${dev.letter} terminal → paste ${COORD_DIR}/${release}-dev-${dev.letter.toLowerCase()}-prompt.md`)
|
||||||
|
})
|
||||||
|
|
||||||
|
return { status: 'prompts-ready', devCount: assignment.devCount, coordDir: COORD_DIR }
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── ACTION: debug ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
if (action === 'debug') {
|
||||||
|
if (!context) throw new Error('args.context required for action=debug — describe the failure or paste test output')
|
||||||
|
|
||||||
|
let currentContext = context
|
||||||
|
const MAX_ITERATIONS = 5
|
||||||
|
|
||||||
|
for (let i = 1; i <= MAX_ITERATIONS; i++) {
|
||||||
|
phase(`Debug iteration ${i}`)
|
||||||
|
|
||||||
|
const result = await agent(
|
||||||
|
`You are debugging a failure in Relicario at ${REPO}. IMPORTANT: cd ${REPO} first.\n\n` +
|
||||||
|
`Failure context:\n${currentContext}\n\n` +
|
||||||
|
`Use systematic debugging:\n` +
|
||||||
|
`1. Form a specific hypothesis about the root cause.\n` +
|
||||||
|
`2. Read the relevant source files and tests.\n` +
|
||||||
|
`3. Implement the minimal fix — no unrelated changes.\n` +
|
||||||
|
`4. Run the failing test(s) to confirm they now pass.\n` +
|
||||||
|
`5. Run cargo test to confirm no regressions.\n` +
|
||||||
|
`6. Commit the fix if clean.\n\n` +
|
||||||
|
`Return fixed=true if all tests pass, fixed=false with remainingFailures if not.`,
|
||||||
|
{ schema: DEBUG_RESULT_SCHEMA, label: `debug-iter-${i}` }
|
||||||
|
)
|
||||||
|
|
||||||
|
log(`Iteration ${i}: ${result.summary}`)
|
||||||
|
|
||||||
|
if (result.fixed) {
|
||||||
|
log(`Fixed after ${i} iteration(s).`)
|
||||||
|
return { status: 'fixed', iterations: i, summary: result.summary }
|
||||||
|
}
|
||||||
|
|
||||||
|
currentContext = result.remainingFailures || currentContext
|
||||||
|
log(`Still failing — next iteration with updated context`)
|
||||||
|
}
|
||||||
|
|
||||||
|
log(`Reached max iterations (${MAX_ITERATIONS}). Manual intervention needed.`)
|
||||||
|
return { status: 'max-iterations', lastContext: currentContext }
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── ACTION: verify ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
if (action === 'verify') {
|
||||||
|
phase('Verify')
|
||||||
|
const result = await agent(
|
||||||
|
`Run the full Relicario test suite from ${REPO}. IMPORTANT: cd ${REPO} first.\n` +
|
||||||
|
` cargo test\n` +
|
||||||
|
` cargo build --all-targets\n` +
|
||||||
|
` cargo clippy -- -D warnings\n` +
|
||||||
|
`Report pass/fail for each. List every failure with its error text.`,
|
||||||
|
{ schema: VERIFY_RESULT_SCHEMA, label: 'verify' }
|
||||||
|
)
|
||||||
|
|
||||||
|
if (result.allPass) {
|
||||||
|
log(`All checks pass.`)
|
||||||
|
} else {
|
||||||
|
log(`FAILED: ${result.failures.join(' | ')}`)
|
||||||
|
log(`Fix with: Workflow({name:"release", args:{action:"debug", context:"<paste failures>"}})`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── ACTION: release ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
if (action === 'release') {
|
||||||
|
if (!release) throw new Error('args.release is required for action=release')
|
||||||
|
|
||||||
|
phase('Verify')
|
||||||
|
const verifyResult = await agent(
|
||||||
|
`Run the full Relicario test suite from ${REPO}. IMPORTANT: cd ${REPO} first.\n` +
|
||||||
|
` cargo test\n` +
|
||||||
|
` cargo build --all-targets\n` +
|
||||||
|
` cargo clippy -- -D warnings\n` +
|
||||||
|
`Report pass/fail. List failures.`,
|
||||||
|
{ schema: VERIFY_RESULT_SCHEMA, label: 'pre-release-verify' }
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!verifyResult.allPass) {
|
||||||
|
log(`Tests failing — cannot cut release. Fix first with action=debug.`)
|
||||||
|
return { status: 'blocked', failures: verifyResult.failures }
|
||||||
|
}
|
||||||
|
|
||||||
|
phase('Finalize')
|
||||||
|
await agent(
|
||||||
|
`Cut the ${release} release for Relicario at ${REPO}. IMPORTANT: cd ${REPO} first.\n\n` +
|
||||||
|
`Steps (in order):\n` +
|
||||||
|
`1. Run: git log $(git describe --tags --abbrev=0)..HEAD --oneline\n` +
|
||||||
|
` Use that output to write a ${release} section in CHANGELOG.md — user-facing language, grouped by type.\n` +
|
||||||
|
`2. Update STATUS.md: mark ${release} as released, set what is next.\n` +
|
||||||
|
`3. Update ROADMAP.md: check off the ${release} milestone.\n` +
|
||||||
|
`4. Commit those doc updates: git commit -m "release: ${release}"\n` +
|
||||||
|
`5. Create annotated tag: git tag -a ${release} -m "Release ${release}"\n` +
|
||||||
|
`6. STOP. Print the tag SHA and the push command, then ask the user to confirm before pushing.\n` +
|
||||||
|
` Do NOT run git push or git push --tags without explicit user confirmation.`,
|
||||||
|
{ label: 'cut-release', phase: 'Finalize' }
|
||||||
|
)
|
||||||
|
|
||||||
|
return { status: 'tagged', release, note: 'Confirm and push manually.' }
|
||||||
|
}
|
||||||
|
|
||||||
|
log(`Unknown action: "${action}". Valid: develop, debug, verify, release`)
|
||||||
|
return { status: 'error', action }
|
||||||
161
docs/superpowers/RELEASE-WORKFLOW.md
Normal file
161
docs/superpowers/RELEASE-WORKFLOW.md
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
# Release Workflow
|
||||||
|
|
||||||
|
Unified lifecycle workflow at `.claude/workflows/release.js`.
|
||||||
|
Invoke from any Claude Code session via the `Workflow` tool.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Actions at a glance
|
||||||
|
|
||||||
|
| Action | When | Mode |
|
||||||
|
|--------|------|------|
|
||||||
|
| `develop` | Implement plan tasks | `single` (phone/remote) or `multi` (PC, supervised) |
|
||||||
|
| `verify` | Check tests pass | — |
|
||||||
|
| `debug` | Fix a failing test or broken feature | — (always sequential) |
|
||||||
|
| `release` | Cut and tag a version | — |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Add features / implement a plan
|
||||||
|
|
||||||
|
### Single-agent (phone-friendly, fire-and-forget)
|
||||||
|
|
||||||
|
One agent works through all plan tasks sequentially. Kick off and check the progress tree later.
|
||||||
|
|
||||||
|
```js
|
||||||
|
Workflow({
|
||||||
|
name: 'release',
|
||||||
|
args: { action: 'develop', mode: 'single', release: 'v0.5.0' }
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
**What happens:**
|
||||||
|
1. Discovers all plan files matching `v0.5.0`
|
||||||
|
2. PM agent reads plans, orders tasks respecting dependencies
|
||||||
|
3. One dev agent per task runs sequentially
|
||||||
|
4. Full `cargo test` + `cargo build` + `cargo clippy` verify pass
|
||||||
|
5. Updates `STATUS.md`
|
||||||
|
|
||||||
|
### Multi-agent (PC, supervised by PM)
|
||||||
|
|
||||||
|
PM reads the plans, decides N dev streams, writes kickoff prompt files. You open the terminals.
|
||||||
|
|
||||||
|
```js
|
||||||
|
Workflow({
|
||||||
|
name: 'release',
|
||||||
|
args: { action: 'develop', mode: 'multi', release: 'v0.5.0' }
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
**What happens:**
|
||||||
|
1. Discovers plans
|
||||||
|
2. PM agent assigns tasks to N dev streams
|
||||||
|
3. Generates PM + N dev prompt files in `docs/superpowers/coordination/`
|
||||||
|
4. Prints terminal-open instructions
|
||||||
|
|
||||||
|
**Then you:**
|
||||||
|
```bash
|
||||||
|
cd tools/relay && ./start.sh # start relay server
|
||||||
|
# open N+1 terminal windows
|
||||||
|
# PM window: paste coordination/v0.5.0-pm-prompt.md
|
||||||
|
# Dev-A window: paste coordination/v0.5.0-dev-a-prompt.md
|
||||||
|
# Dev-B window: paste coordination/v0.5.0-dev-b-prompt.md
|
||||||
|
```
|
||||||
|
|
||||||
|
The PM supervises devs in real time via the relay. You watch all terminals.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Run tests only
|
||||||
|
|
||||||
|
```js
|
||||||
|
Workflow({ name: 'release', args: { action: 'verify' } })
|
||||||
|
```
|
||||||
|
|
||||||
|
Runs `cargo test`, `cargo build --all-targets`, `cargo clippy`. Returns pass/fail summary.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Debug iteration
|
||||||
|
|
||||||
|
After you find a broken test or unexpected behavior, hand the failure context to the debug action. It loops up to 5 times: hypothesize → read code → fix → verify → commit.
|
||||||
|
|
||||||
|
```js
|
||||||
|
Workflow({
|
||||||
|
name: 'release',
|
||||||
|
args: {
|
||||||
|
action: 'debug',
|
||||||
|
context: 'cargo test output:\n...<paste failing test output here>...'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns `{ status: "fixed", iterations: N }` when clean, or `{ status: "max-iterations" }` if it needs your eyes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Cut a release
|
||||||
|
|
||||||
|
Runs verify first; blocked if tests fail.
|
||||||
|
Writes CHANGELOG, updates STATUS + ROADMAP, creates annotated tag.
|
||||||
|
**Stops before pushing** — you confirm manually.
|
||||||
|
|
||||||
|
```js
|
||||||
|
Workflow({
|
||||||
|
name: 'release',
|
||||||
|
args: { action: 'release', release: 'v0.5.0' }
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
After it stops, review the tag then:
|
||||||
|
```bash
|
||||||
|
git push && git push --tags
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Full lifecycle example
|
||||||
|
|
||||||
|
```
|
||||||
|
1. DEVELOP features
|
||||||
|
Workflow({ name:"release", args:{ action:"develop", mode:"single", release:"v0.6.0" } })
|
||||||
|
|
||||||
|
2. VERIFY manually (you run the extension in browser, test your flows)
|
||||||
|
|
||||||
|
3. DEBUG any failures you find
|
||||||
|
Workflow({ name:"release", args:{ action:"debug", context:"<paste failure>" } })
|
||||||
|
# repeat as needed
|
||||||
|
|
||||||
|
4. VERIFY again to confirm clean
|
||||||
|
Workflow({ name:"release", args:{ action:"verify" } })
|
||||||
|
|
||||||
|
5. RELEASE
|
||||||
|
Workflow({ name:"release", args:{ action:"release", release:"v0.6.0" } })
|
||||||
|
# review tag, then: git push && git push --tags
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phone vs PC
|
||||||
|
|
||||||
|
| Scenario | Recipe |
|
||||||
|
|----------|--------|
|
||||||
|
| Kick off a release from your phone / remote session | `develop` + `mode:"single"` — fires in background, check `/workflows` |
|
||||||
|
| At your PC, want to supervise and intervene | `develop` + `mode:"multi"` — generates prompts, open terminals |
|
||||||
|
| Quick sanity check | `verify` |
|
||||||
|
| Fixing a bug you found while testing | `debug` with failure context |
|
||||||
|
| Cutting and tagging | `release` — always confirms before push |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Plan file discovery
|
||||||
|
|
||||||
|
The `develop` action scans `docs/superpowers/plans/` for files whose filename or opening lines reference the release label. To be explicit, pass plan paths directly (not yet wired — add `args.plans` if needed).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Relay server roles
|
||||||
|
|
||||||
|
The relay at `localhost:7331` supports roles: `pm`, `dev-a`, `dev-b`, `dev-c`.
|
||||||
|
Start it before opening terminal sessions: `cd tools/relay && ./start.sh`
|
||||||
|
See `docs/superpowers/coordination/RELAY.md` for protocol details.
|
||||||
Reference in New Issue
Block a user