getsuperpower
Advanced tools
| # Development Design Delivery GetSuperpower | ||
| This example combines product/design shaping with implementation discipline. | ||
| Use it when a change needs more than a quick patch: clarify the request, explore | ||
| the interface, pressure-test the plan, implement with tests, review the result, | ||
| and keep rollback evidence. | ||
| The callable entry skill is: | ||
| ```text | ||
| skills/development-design-delivery/SKILL.md | ||
| ``` | ||
| After install and agent restart, invoke: | ||
| ```text | ||
| $development-design-delivery build this product feature | ||
| ``` | ||
| ## Flow | ||
| | Stage | Skill | Gate | | ||
| | --- | --- | --- | | ||
| | Shape success criteria | `superpowers:brainstorming` | Human approval | | ||
| | Explore interface options | `mattpocock:design-an-interface` | Human approval | | ||
| | Stress-test the requirement | `mattpocock:grill-with-docs` | Human approval | | ||
| | Write implementation plan | `superpowers:writing-plans` | None | | ||
| | Check architecture boundary | `mattpocock:codebase-design` | None | | ||
| | Build with tests | `mattpocock:tdd` | None | | ||
| | Debug when blocked | `mattpocock:diagnosing-bugs` | None | | ||
| | Review the change | `mattpocock:review` | None | | ||
| | Preserve evidence | `pony-trail` | None | | ||
| ## Dependencies | ||
| This GetSuperpower combines reusable agent skills: | ||
| - `./skills/development-design-delivery` | ||
| - `superpowers:brainstorming` | ||
| - `mattpocock:design-an-interface` | ||
| - `mattpocock:grill-with-docs` | ||
| - `superpowers:writing-plans` | ||
| - `mattpocock:codebase-design` | ||
| - `mattpocock:tdd` | ||
| - `mattpocock:diagnosing-bugs` | ||
| - `mattpocock:review` | ||
| - `pony-trail` | ||
| `getsuperpower install` and `getsuperpower clone` automatically use the Skills | ||
| CLI to fetch missing `mattpocock:*` dependencies. If that automatic bootstrap | ||
| fails, run the same package install through the CLI and retry: | ||
| ```bash | ||
| bun run dev -- skills install mattpocock/skills | ||
| ``` | ||
| ## Try It | ||
| Validate this GetSuperpower from the repo root: | ||
| ```bash | ||
| bun run dev -- validate examples/workflows/development-design-delivery | ||
| ``` | ||
| List its dependencies: | ||
| ```bash | ||
| bun run dev -- deps examples/workflows/development-design-delivery | ||
| ``` | ||
| Install it into a project: | ||
| ```bash | ||
| bun run dev -- install examples/workflows/development-design-delivery | ||
| bun run dev -- clone examples/workflows/development-design-delivery | ||
| ``` | ||
| `clone <source>` is equivalent to `install <source>`. |
| --- | ||
| name: development-design-delivery | ||
| description: Use when running a product-minded engineering workflow from request shaping through interface design, implementation, review, and evidence capture. | ||
| --- | ||
| # Development Design Delivery GetSuperpower | ||
| This is the entry skill for the development-design-delivery GetSuperpower. | ||
| When this skill is used, run the workflow below in order. Load/use every | ||
| required sub-skill before doing the work for its phase. | ||
| ## Required Sub-Skills | ||
| Before doing workflow work, load/use these skills in order: | ||
| 1. superpowers:brainstorming - shape the request, context, constraints, and success criteria | ||
| 2. mattpocock:design-an-interface - explore API, module, or UI interface options | ||
| 3. mattpocock:grill-with-docs - stress-test the requirement and preserve design docs | ||
| 4. superpowers:writing-plans - split approved scope into executable tasks | ||
| 5. mattpocock:codebase-design - check module boundaries, seams, and testability | ||
| 6. mattpocock:tdd - build task by task with failing tests first | ||
| 7. mattpocock:diagnosing-bugs - diagnose unexpected failures or regressions when blocked | ||
| 8. mattpocock:review - review changes against standards and the approved spec | ||
| 9. pony-trail - record file-change evidence, verification, and rollback context | ||
| If any required sub-skill is unavailable, stop and tell the user which | ||
| dependency is missing. For missing `mattpocock:*` skills, tell the user to run: | ||
| ```bash | ||
| getsuperpower skills install mattpocock/skills | ||
| ``` | ||
| ## Flow | ||
| 1. Shape the request and success criteria. | ||
| - Skill: superpowers:brainstorming | ||
| - Gate: wait for explicit human approval. | ||
| 2. Explore API, module, or UI interface options. | ||
| - Skill: mattpocock:design-an-interface | ||
| - Gate: wait for explicit human approval. | ||
| 3. Stress-test the plan and record docs. | ||
| - Skill: mattpocock:grill-with-docs | ||
| - Gate: wait for explicit human approval. | ||
| 4. Write the task-by-task implementation plan. | ||
| - Skill: superpowers:writing-plans | ||
| 5. Check module boundaries and seams before implementation. | ||
| - Skill: mattpocock:codebase-design | ||
| 6. Implement with TDD. | ||
| - Skill: mattpocock:tdd | ||
| 7. Use systematic debugging if behavior is unexpected or tests fail. | ||
| - Skill: mattpocock:diagnosing-bugs | ||
| 8. Review the change against repo standards and the approved spec. | ||
| - Skill: mattpocock:review | ||
| 9. Preserve verification and rollback evidence. | ||
| - Skill: pony-trail | ||
| ## Author Notes | ||
| - Keep this entry skill, `workflow.json`, and `README.md` aligned when adding or removing steps. | ||
| - This skill orchestrates through required instructions; GetSuperpower installs and validates the dependency skills. | ||
| - Do not silently skip approval gates, interface exploration, implementation planning, TDD, review, or evidence capture. |
| { | ||
| "schemaVersion": "0.1", | ||
| "name": "development-design-delivery", | ||
| "version": "0.1.0", | ||
| "description": "Shape, design, plan, implement, review, and preserve evidence for serious product engineering work.", | ||
| "skills": [ | ||
| { | ||
| "source": "./skills/development-design-delivery" | ||
| }, | ||
| { | ||
| "source": "superpowers:brainstorming" | ||
| }, | ||
| { | ||
| "source": "mattpocock:design-an-interface" | ||
| }, | ||
| { | ||
| "source": "mattpocock:grill-with-docs" | ||
| }, | ||
| { | ||
| "source": "superpowers:writing-plans" | ||
| }, | ||
| { | ||
| "source": "mattpocock:codebase-design" | ||
| }, | ||
| { | ||
| "source": "mattpocock:tdd" | ||
| }, | ||
| { | ||
| "source": "mattpocock:diagnosing-bugs" | ||
| }, | ||
| { | ||
| "source": "mattpocock:review" | ||
| }, | ||
| { | ||
| "source": "pony-trail" | ||
| } | ||
| ], | ||
| "steps": [ | ||
| { | ||
| "id": "shape", | ||
| "title": "Shape the request and success criteria", | ||
| "skill": "superpowers:brainstorming", | ||
| "gate": "human_approval" | ||
| }, | ||
| { | ||
| "id": "interface-design", | ||
| "title": "Explore API, module, or UI interface options", | ||
| "skill": "mattpocock:design-an-interface", | ||
| "gate": "human_approval" | ||
| }, | ||
| { | ||
| "id": "requirement-review", | ||
| "title": "Stress-test the plan and record docs", | ||
| "skill": "mattpocock:grill-with-docs", | ||
| "gate": "human_approval" | ||
| }, | ||
| { | ||
| "id": "implementation-plan", | ||
| "title": "Write the task-by-task implementation plan", | ||
| "skill": "superpowers:writing-plans" | ||
| }, | ||
| { | ||
| "id": "architecture-boundary", | ||
| "title": "Check module boundaries and seams", | ||
| "skill": "mattpocock:codebase-design" | ||
| }, | ||
| { | ||
| "id": "build", | ||
| "title": "Implement with TDD", | ||
| "skill": "mattpocock:tdd" | ||
| }, | ||
| { | ||
| "id": "debug", | ||
| "title": "Use systematic debugging when blocked", | ||
| "skill": "mattpocock:diagnosing-bugs" | ||
| }, | ||
| { | ||
| "id": "review", | ||
| "title": "Review against standards and spec", | ||
| "skill": "mattpocock:review" | ||
| }, | ||
| { | ||
| "id": "evidence", | ||
| "title": "Record verification and rollback evidence", | ||
| "skill": "pony-trail" | ||
| } | ||
| ] | ||
| } |
| # Grilled Product Dev GetSuperpower | ||
| This example GetSuperpower is for product-development requests that are still a | ||
| little soft. It uses Matt Pocock's `grilling` skill first to pressure-test the | ||
| idea, then hands the approved direction to Superpowers for design and planning. | ||
| The flow is intentionally narrow: | ||
| 1. Grill the request one question at a time until the goal, constraints, and | ||
| success criteria are clear. | ||
| 2. Use `superpowers:brainstorming` to turn the sharpened direction into an | ||
| approved design. | ||
| 3. Use `superpowers:writing-plans` to split that design into executable tasks. | ||
| The callable entry skill is: | ||
| ```text | ||
| skills/grilled-product-dev/SKILL.md | ||
| ``` | ||
| After install and agent restart, invoke: | ||
| ```text | ||
| $grilled-product-dev help me shape this product change | ||
| ``` | ||
| ## Dependencies | ||
| This GetSuperpower combines one Matt Pocock skill with two Superpowers skills: | ||
| - `./skills/grilled-product-dev` | ||
| - `mattpocock:grilling` | ||
| - `superpowers:brainstorming` | ||
| - `superpowers:writing-plans` | ||
| `getsuperpower install` and `getsuperpower clone` automatically use the Skills | ||
| CLI to fetch missing `mattpocock:*` dependencies. If that automatic bootstrap | ||
| fails, install the Matt Pocock skills package and retry: | ||
| ```bash | ||
| bun run dev -- skills install mattpocock/skills | ||
| ``` | ||
| ## Try It | ||
| Validate this GetSuperpower from the repo root: | ||
| ```bash | ||
| bun run dev -- validate examples/workflows/grilled-product-dev | ||
| ``` | ||
| List its dependencies: | ||
| ```bash | ||
| bun run dev -- deps examples/workflows/grilled-product-dev | ||
| ``` | ||
| Install it into a project: | ||
| ```bash | ||
| bun run dev -- install examples/workflows/grilled-product-dev | ||
| bun run dev -- clone examples/workflows/grilled-product-dev | ||
| ``` | ||
| `clone <source>` is equivalent to `install <source>`. | ||
| Restart the agent app after install so the `$grilled-product-dev` entry skill | ||
| and its sub-skills are available. |
| --- | ||
| name: grilled-product-dev | ||
| description: Use when shaping a product-development request that should be grilled before Superpowers design and planning. | ||
| --- | ||
| # Grilled Product Dev GetSuperpower | ||
| This is the entry skill for the grilled-product-dev GetSuperpower. | ||
| When this skill is used, run the workflow below in order. Load/use every | ||
| required sub-skill before doing the work for its phase. | ||
| ## Required Sub-Skills | ||
| Before doing workflow work, load/use these skills in order: | ||
| 1. mattpocock:grilling - interview the human one question at a time and recommend answers until the request is sharp | ||
| 2. superpowers:brainstorming - turn the approved direction into a design and written spec | ||
| 3. superpowers:writing-plans - split the approved design into executable tasks | ||
| If any required sub-skill is unavailable, stop and tell the user which | ||
| dependency is missing. | ||
| ## Flow | ||
| 1. Sharpen the request through Matt Pocock grilling. | ||
| - Skill: mattpocock:grilling | ||
| - Gate: wait for explicit human approval that the grilled direction is ready. | ||
| 2. Turn the approved direction into a Superpowers design. | ||
| - Skill: superpowers:brainstorming | ||
| - Gate: wait for explicit human approval of the design and written spec. | ||
| 3. Write the implementation plan. | ||
| - Skill: superpowers:writing-plans | ||
| ## Author Notes | ||
| - Keep this entry skill, `workflow.json`, and `README.md` aligned when adding or removing steps. | ||
| - `superpowers:brainstorming` expects `superpowers:writing-plans` to be the next implementation skill, so grilling runs before brainstorming in this workflow. | ||
| - This skill orchestrates required instructions; GetSuperpower installs and validates the dependency skills. |
| { | ||
| "schemaVersion": "0.1", | ||
| "name": "grilled-product-dev", | ||
| "version": "0.1.0", | ||
| "description": "Sharpen a product-development request with grilling before Superpowers design and planning.", | ||
| "skills": [ | ||
| { | ||
| "source": "./skills/grilled-product-dev" | ||
| }, | ||
| { | ||
| "source": "mattpocock:grilling" | ||
| }, | ||
| { | ||
| "source": "superpowers:brainstorming" | ||
| }, | ||
| { | ||
| "source": "superpowers:writing-plans" | ||
| } | ||
| ], | ||
| "steps": [ | ||
| { | ||
| "id": "grill", | ||
| "title": "Sharpen the request through grilling", | ||
| "skill": "mattpocock:grilling", | ||
| "gate": "human_approval" | ||
| }, | ||
| { | ||
| "id": "shape", | ||
| "title": "Turn the approved direction into a Superpowers design", | ||
| "skill": "superpowers:brainstorming", | ||
| "gate": "human_approval" | ||
| }, | ||
| { | ||
| "id": "plan", | ||
| "title": "Write the implementation plan", | ||
| "skill": "superpowers:writing-plans" | ||
| } | ||
| ] | ||
| } |
| --- | ||
| name: openspec-delivery | ||
| description: Use when running a professional OpenSpec delivery workflow from proposal through design, plan, TDD implementation, verification, and archive. | ||
| --- | ||
| # OpenSpec Delivery GetSuperpower | ||
| This is the entry skill for the openspec-delivery GetSuperpower. | ||
| When this skill is used, run the delivery workflow below in order. Load/use | ||
| every required sub-skill before doing the work for its phase. | ||
| ## Required Sub-Skills | ||
| Before doing workflow work, load/use these skills in order: | ||
| 1. opsx-handoff-review (`./skills/opsx-handoff-review`) - OpenSpec proposal, review, handoff, and archive checkpoints | ||
| 2. superpowers:brainstorming - design deepening before implementation planning | ||
| 3. superpowers:writing-plans - split approved scope into executable tasks | ||
| 4. mattpocock:tdd - build task by task with failing tests first | ||
| 5. pony-trail - record file-change evidence, verification, and rollback context | ||
| If any required sub-skill is unavailable, stop and tell the user which dependency is missing. | ||
| ## Flow | ||
| 1. Run `/opsx:propose` to create proposal, specs, and tasks. | ||
| - Skill: opsx-handoff-review (`./skills/opsx-handoff-review`) | ||
| 2. Review `proposal.md` with the human owner. | ||
| - Skill: opsx-handoff-review (`./skills/opsx-handoff-review`) | ||
| - Gate: wait for explicit human approval. | ||
| 3. Deepen design details with Superpowers brainstorming. | ||
| - Skill: superpowers:brainstorming | ||
| - Gate: wait for explicit human approval. | ||
| 4. Split tasks into an implementation plan. | ||
| - Skill: superpowers:writing-plans | ||
| 5. Build each task with TDD and `specs/` context. | ||
| - Skill: mattpocock:tdd | ||
| 6. Verify delivery and preserve evidence. | ||
| - Skill: pony-trail | ||
| 7. Run `/opsx:archive` to update specs and project knowledge. | ||
| - Skill: opsx-handoff-review (`./skills/opsx-handoff-review`) | ||
| - Gate: wait for explicit human approval. | ||
| ## Author Notes | ||
| - Keep this entry skill, `workflow.json`, and `README.md` aligned when adding or removing steps. | ||
| - This skill orchestrates through required instructions; GetSuperpower installs and validates the dependency skills. | ||
| - Do not silently skip OpenSpec review, human approval gates, TDD, verification, or archive. |
| import pc from "picocolors"; | ||
| export const GETSUPERPOWER_ASCII_LOGO = [ | ||
| "GETSUPERPOWER", | ||
| "Skill trees for serious agent work.", | ||
| ].join("\n"); | ||
| export function brand(value: string): string { | ||
| return pc.bold(pc.cyan(value)); | ||
| } | ||
| export function success(value: string): string { | ||
| return pc.bold(pc.green(value)); | ||
| } | ||
| export function warning(value: string): string { | ||
| return pc.yellow(value); | ||
| } | ||
| export function errorText(value: string): string { | ||
| return pc.red(value); | ||
| } | ||
| export function muted(value: string): string { | ||
| return pc.dim(value); | ||
| } | ||
| export function commandText(value: string): string { | ||
| return pc.magenta(value); | ||
| } | ||
| export function label(value: string): string { | ||
| return muted(value); | ||
| } | ||
| export function keyValue(key: string, value: string): string { | ||
| return `${label(`${key}:`)} ${value}`; | ||
| } | ||
| export function nextStep(command: string): string { | ||
| return `${label("Next:")} ${commandText(command)}`; | ||
| } | ||
| export function rootHelpBanner(): string { | ||
| return [ | ||
| brand(GETSUPERPOWER_ASCII_LOGO), | ||
| "", | ||
| success("Welcome to GetSuperpower."), | ||
| "Install and author workflow skill trees for agent work.", | ||
| "", | ||
| label("Start:"), | ||
| ` ${commandText("getsuperpower init release-review")}`, | ||
| ` ${commandText("getsuperpower validate ./release-review")}`, | ||
| ` ${commandText("getsuperpower clone https://github.com/acme/release-review.git")}`, | ||
| ` ${commandText("getsuperpower install ./release-review")}`, | ||
| "", | ||
| label("Inspect:"), | ||
| ` ${commandText("getsuperpower list")}`, | ||
| ` ${commandText("getsuperpower deps ./release-review")}`, | ||
| "", | ||
| ].join("\n"); | ||
| } | ||
| export function styleHelpTitle(title: string): string { | ||
| return brand(title); | ||
| } | ||
| export function styleHelpTerm(term: string): string { | ||
| return commandText(term); | ||
| } |
| import { mkdir, mkdtemp, stat, writeFile } from "node:fs/promises"; | ||
| import { tmpdir } from "node:os"; | ||
| import { isAbsolute, join, resolve } from "node:path"; | ||
| import { buildProgram } from "../cli"; | ||
| export type CliSandboxEvaluationMode = "baseline" | "workflow"; | ||
| export interface CliSandboxCriterion { | ||
| id: string; | ||
| label: string; | ||
| passed: boolean; | ||
| detail: string; | ||
| } | ||
| export interface CliSandboxCommandRun { | ||
| args: string[]; | ||
| activeMs: number; | ||
| failed: boolean; | ||
| logs: string[]; | ||
| error?: string; | ||
| } | ||
| export interface CliSandboxTokenSpend { | ||
| inputTokens?: number; | ||
| outputTokens?: number; | ||
| } | ||
| export interface CliSandboxRun { | ||
| mode: CliSandboxEvaluationMode; | ||
| label: string; | ||
| projectDir: string; | ||
| homeDir: string; | ||
| activeMs: number; | ||
| cliCommands: number; | ||
| checkRetries: number; | ||
| commandFailures: number; | ||
| externalSideEffects: number; | ||
| criteria: CliSandboxCriterion[]; | ||
| commands: CliSandboxCommandRun[]; | ||
| tokenSpend: CliSandboxTokenSpend | null; | ||
| } | ||
| export interface CliSandboxMatrixRow { | ||
| metric: string; | ||
| baseline: string; | ||
| workflow: string; | ||
| delta: string; | ||
| } | ||
| export interface CliSandboxEvaluationReport { | ||
| generatedAt: string; | ||
| workflowSource: string; | ||
| workflowSourcePath: string; | ||
| sandboxRoot: string; | ||
| runs: [CliSandboxRun, CliSandboxRun]; | ||
| matrices: { | ||
| performance: CliSandboxMatrixRow[]; | ||
| accuracy: CliSandboxMatrixRow[]; | ||
| tokenSpend: CliSandboxMatrixRow[]; | ||
| }; | ||
| } | ||
| export interface RunCliSandboxEvaluationOptions { | ||
| generatedAt?: string; | ||
| repoRoot?: string; | ||
| sandboxRoot?: string; | ||
| workflowSource?: string; | ||
| } | ||
| const defaultWorkflowSource = "examples/workflows/openspec-superpowers"; | ||
| const expectedInstalledSkills = [ | ||
| "openspec-delivery", | ||
| "opsx-handoff-review", | ||
| "superpowers-brainstorming", | ||
| "superpowers-writing-plans", | ||
| "tdd", | ||
| "pony-trail", | ||
| ]; | ||
| export async function runCliSandboxEvaluation( | ||
| options: RunCliSandboxEvaluationOptions = {}, | ||
| ): Promise<CliSandboxEvaluationReport> { | ||
| const repoRoot = options.repoRoot ?? resolve(import.meta.dir, "..", ".."); | ||
| const workflowSource = options.workflowSource ?? defaultWorkflowSource; | ||
| const workflowSourcePath = isAbsolute(workflowSource) | ||
| ? workflowSource | ||
| : resolve(repoRoot, workflowSource); | ||
| const sandboxRoot = | ||
| options.sandboxRoot ?? (await mkdtemp(join(tmpdir(), "getsuperpower-cli-eval-"))); | ||
| await mkdir(sandboxRoot, { recursive: true }); | ||
| const baselineRun = await runBaseline({ | ||
| projectDir: join(sandboxRoot, "baseline-project"), | ||
| homeDir: join(sandboxRoot, "baseline-home"), | ||
| workflowSourcePath, | ||
| }); | ||
| const workflowRun = await runWorkflow({ | ||
| projectDir: join(sandboxRoot, "workflow-project"), | ||
| homeDir: join(sandboxRoot, "workflow-home"), | ||
| workflowSourcePath, | ||
| }); | ||
| return createEvaluationReport({ | ||
| generatedAt: options.generatedAt ?? new Date().toISOString(), | ||
| workflowSource, | ||
| workflowSourcePath, | ||
| sandboxRoot, | ||
| runs: [baselineRun, workflowRun], | ||
| }); | ||
| } | ||
| export function renderCliSandboxEvaluation(report: CliSandboxEvaluationReport): string { | ||
| return [ | ||
| "# GetSuperpower CLI Sandbox Evaluation", | ||
| "", | ||
| `Generated: ${report.generatedAt}`, | ||
| `Workflow source: ${report.workflowSource}`, | ||
| `Sandbox root: ${report.sandboxRoot}`, | ||
| "", | ||
| "## Performance Matrix", | ||
| renderMatrix(report.matrices.performance), | ||
| "", | ||
| "## Accuracy Matrix", | ||
| renderMatrix(report.matrices.accuracy), | ||
| "", | ||
| "## Token Spend Matrix", | ||
| renderMatrix(report.matrices.tokenSpend), | ||
| "", | ||
| "Token metrics are unavailable because CLI sandbox runs do not expose provider token metadata.", | ||
| "", | ||
| "## Acceptance Criteria", | ||
| ...report.runs.flatMap((run) => [ | ||
| "", | ||
| `### ${run.label}`, | ||
| ...run.criteria.map( | ||
| (criterion) => | ||
| `- ${criterion.passed ? "PASS" : "FAIL"} ${criterion.label}: ${criterion.detail}`, | ||
| ), | ||
| ]), | ||
| "", | ||
| ].join("\n"); | ||
| } | ||
| function createEvaluationReport(input: { | ||
| generatedAt: string; | ||
| workflowSource: string; | ||
| workflowSourcePath: string; | ||
| sandboxRoot: string; | ||
| runs: [CliSandboxRun, CliSandboxRun]; | ||
| }): CliSandboxEvaluationReport { | ||
| const [baseline, workflow] = input.runs; | ||
| return { | ||
| generatedAt: input.generatedAt, | ||
| workflowSource: input.workflowSource, | ||
| workflowSourcePath: input.workflowSourcePath, | ||
| sandboxRoot: input.sandboxRoot, | ||
| runs: input.runs, | ||
| matrices: { | ||
| performance: [ | ||
| millisecondsRow("Active wall-clock time", baseline.activeMs, workflow.activeMs), | ||
| countRow("CLI commands", baseline.cliCommands, workflow.cliCommands), | ||
| countRow("Check retries", baseline.checkRetries, workflow.checkRetries), | ||
| ], | ||
| accuracy: [ | ||
| textRow( | ||
| "Acceptance criteria passed", | ||
| `${countPassedCriteria(baseline)}/${baseline.criteria.length}`, | ||
| `${countPassedCriteria(workflow)}/${workflow.criteria.length}`, | ||
| formatSignedNumber(countPassedCriteria(workflow) - countPassedCriteria(baseline)), | ||
| ), | ||
| percentRow("Acceptance pass rate", criteriaPassRate(baseline), criteriaPassRate(workflow)), | ||
| countRow("CLI command failures", baseline.commandFailures, workflow.commandFailures), | ||
| countRow( | ||
| "External side effects", | ||
| baseline.externalSideEffects, | ||
| workflow.externalSideEffects, | ||
| ), | ||
| ], | ||
| tokenSpend: tokenSpendRows(baseline, workflow), | ||
| }, | ||
| }; | ||
| } | ||
| async function runBaseline(input: { | ||
| projectDir: string; | ||
| homeDir: string; | ||
| workflowSourcePath: string; | ||
| }): Promise<CliSandboxRun> { | ||
| await mkdir(input.projectDir, { recursive: true }); | ||
| await mkdir(input.homeDir, { recursive: true }); | ||
| const externalCalls: string[] = []; | ||
| const commands = await runCommands({ | ||
| projectDir: input.projectDir, | ||
| externalCalls, | ||
| commands: [ | ||
| ["validate", input.workflowSourcePath], | ||
| ["deps", input.workflowSourcePath], | ||
| ], | ||
| }); | ||
| const logs = commands.flatMap((command) => command.logs); | ||
| const workflowRecord = join( | ||
| input.projectDir, | ||
| ".getsuperpower", | ||
| "workflows", | ||
| "openspec-delivery.json", | ||
| ); | ||
| return buildRun({ | ||
| mode: "baseline", | ||
| label: "Before workflow install/use", | ||
| projectDir: input.projectDir, | ||
| homeDir: input.homeDir, | ||
| commands, | ||
| externalSideEffects: externalCalls.length, | ||
| criteria: [ | ||
| { | ||
| id: "baseline-validates-workflow", | ||
| label: "CLI validates the workflow source", | ||
| passed: logs.some((line) => | ||
| stripAnsi(line).includes("GetSuperpower valid: openspec-delivery@0.1.0"), | ||
| ), | ||
| detail: "validate should accept the OpenSpec workflow fixture", | ||
| }, | ||
| { | ||
| id: "baseline-lists-dependencies", | ||
| label: "CLI lists workflow dependencies before install", | ||
| passed: | ||
| logs.some((line) => stripAnsi(line).includes("- mattpocock:tdd")) && | ||
| logs.some((line) => stripAnsi(line).includes("- pony-trail")), | ||
| detail: "deps should expose reusable workflow skill requirements", | ||
| }, | ||
| { | ||
| id: "baseline-does-not-install", | ||
| label: "Baseline mode leaves the project uninstalled", | ||
| passed: !(await pathExists(workflowRecord)), | ||
| detail: ".getsuperpower workflow records should not exist before install/clone", | ||
| }, | ||
| { | ||
| id: "baseline-no-external-side-effects", | ||
| label: "Baseline mode avoids external side effects", | ||
| passed: externalCalls.length === 0, | ||
| detail: "validate/deps should not invoke the external Skills CLI", | ||
| }, | ||
| ], | ||
| }); | ||
| } | ||
| async function runWorkflow(input: { | ||
| projectDir: string; | ||
| homeDir: string; | ||
| workflowSourcePath: string; | ||
| }): Promise<CliSandboxRun> { | ||
| await mkdir(input.projectDir, { recursive: true }); | ||
| await mkdir(input.homeDir, { recursive: true }); | ||
| await writeFakeDependencyHome(input.homeDir); | ||
| const externalCalls: string[] = []; | ||
| const commands = await runCommands({ | ||
| projectDir: input.projectDir, | ||
| externalCalls, | ||
| commands: [ | ||
| ["clone", input.workflowSourcePath, "--home", input.homeDir, "--agents", "codex"], | ||
| ["list"], | ||
| ], | ||
| }); | ||
| const logs = commands.flatMap((command) => command.logs); | ||
| const workflowRecord = join( | ||
| input.projectDir, | ||
| ".getsuperpower", | ||
| "workflows", | ||
| "openspec-delivery.json", | ||
| ); | ||
| const installedSkillResults = await Promise.all( | ||
| expectedInstalledSkills.map((skill) => | ||
| pathExists(join(input.homeDir, ".agents", "skills", skill, "SKILL.md")), | ||
| ), | ||
| ); | ||
| return buildRun({ | ||
| mode: "workflow", | ||
| label: "After workflow clone/use", | ||
| projectDir: input.projectDir, | ||
| homeDir: input.homeDir, | ||
| commands, | ||
| externalSideEffects: externalCalls.length, | ||
| criteria: [ | ||
| { | ||
| id: "workflow-record-written", | ||
| label: "Workflow mode writes the installed workflow record", | ||
| passed: await pathExists(workflowRecord), | ||
| detail: ".getsuperpower/workflows/openspec-delivery.json should exist", | ||
| }, | ||
| { | ||
| id: "workflow-installs-skills", | ||
| label: "Workflow mode installs every required skill into the sandbox home", | ||
| passed: installedSkillResults.every(Boolean), | ||
| detail: expectedInstalledSkills.join(", "), | ||
| }, | ||
| { | ||
| id: "workflow-list-shows-installed-workflow", | ||
| label: "Workflow mode lists the installed workflow", | ||
| passed: logs.some((line) => stripAnsi(line).includes("openspec-delivery 0.1.0")), | ||
| detail: "list should show the workflow installed by clone", | ||
| }, | ||
| { | ||
| id: "workflow-no-external-side-effects", | ||
| label: "Workflow mode avoids external side effects in the sandbox", | ||
| passed: externalCalls.length === 0, | ||
| detail: "fake sandbox dependencies should prevent network/package bootstrap", | ||
| }, | ||
| ], | ||
| }); | ||
| } | ||
| function buildRun(input: { | ||
| mode: CliSandboxEvaluationMode; | ||
| label: string; | ||
| projectDir: string; | ||
| homeDir: string; | ||
| commands: CliSandboxCommandRun[]; | ||
| externalSideEffects: number; | ||
| criteria: CliSandboxCriterion[]; | ||
| }): CliSandboxRun { | ||
| return { | ||
| mode: input.mode, | ||
| label: input.label, | ||
| projectDir: input.projectDir, | ||
| homeDir: input.homeDir, | ||
| activeMs: sum(input.commands.map((command) => command.activeMs)), | ||
| cliCommands: input.commands.length, | ||
| checkRetries: 0, | ||
| commandFailures: input.commands.filter((command) => command.failed).length, | ||
| externalSideEffects: input.externalSideEffects, | ||
| criteria: input.criteria, | ||
| commands: input.commands, | ||
| tokenSpend: null, | ||
| }; | ||
| } | ||
| async function runCommands(input: { | ||
| projectDir: string; | ||
| externalCalls: string[]; | ||
| commands: string[][]; | ||
| }): Promise<CliSandboxCommandRun[]> { | ||
| const runs: CliSandboxCommandRun[] = []; | ||
| for (const args of input.commands) { | ||
| runs.push( | ||
| await runCommand({ projectDir: input.projectDir, externalCalls: input.externalCalls, args }), | ||
| ); | ||
| } | ||
| return runs; | ||
| } | ||
| async function runCommand(input: { | ||
| projectDir: string; | ||
| externalCalls: string[]; | ||
| args: string[]; | ||
| }): Promise<CliSandboxCommandRun> { | ||
| const logs: string[] = []; | ||
| const originalLog = console.log; | ||
| const originalError = console.error; | ||
| const startedAt = performance.now(); | ||
| let failed = false; | ||
| let error: string | undefined; | ||
| console.log = (...values: unknown[]) => { | ||
| logs.push(values.join(" ")); | ||
| }; | ||
| console.error = (...values: unknown[]) => { | ||
| logs.push(values.join(" ")); | ||
| }; | ||
| try { | ||
| await buildProgram({ | ||
| cwd: input.projectDir, | ||
| installExternalSkillDependency: async (dependency) => { | ||
| input.externalCalls.push(dependency.source); | ||
| throw new Error(`Sandbox blocked external skill install: ${dependency.source}`); | ||
| }, | ||
| }).parseAsync(input.args, { from: "user" }); | ||
| } catch (caught) { | ||
| failed = true; | ||
| error = caught instanceof Error ? caught.message : String(caught); | ||
| logs.push(`ERROR: ${error}`); | ||
| } finally { | ||
| console.log = originalLog; | ||
| console.error = originalError; | ||
| } | ||
| return { | ||
| args: input.args, | ||
| activeMs: performance.now() - startedAt, | ||
| failed, | ||
| logs, | ||
| ...(error ? { error } : {}), | ||
| }; | ||
| } | ||
| async function writeFakeDependencyHome(homeDir: string): Promise<void> { | ||
| const superpowersRoot = join( | ||
| homeDir, | ||
| ".codex", | ||
| "plugins", | ||
| "cache", | ||
| "openai-curated", | ||
| "superpowers", | ||
| "sandbox-plugin", | ||
| "skills", | ||
| ); | ||
| await writeSkill(join(superpowersRoot, "brainstorming"), { | ||
| name: "brainstorming", | ||
| description: "Sandbox Superpowers brainstorming skill.", | ||
| }); | ||
| await writeSkill(join(superpowersRoot, "writing-plans"), { | ||
| name: "writing-plans", | ||
| description: "Sandbox Superpowers writing-plans skill.", | ||
| }); | ||
| await writeSkill(join(homeDir, ".agents", "skills", "tdd"), { | ||
| name: "tdd", | ||
| description: "Sandbox Matt Pocock TDD skill.", | ||
| }); | ||
| } | ||
| async function writeSkill( | ||
| path: string, | ||
| input: { name: string; description: string }, | ||
| ): Promise<void> { | ||
| await mkdir(path, { recursive: true }); | ||
| await writeFile( | ||
| join(path, "SKILL.md"), | ||
| [ | ||
| "---", | ||
| `name: ${input.name}`, | ||
| `description: "${input.description}"`, | ||
| "---", | ||
| "", | ||
| `# ${input.name}`, | ||
| ].join("\n"), | ||
| ); | ||
| } | ||
| async function pathExists(path: string): Promise<boolean> { | ||
| try { | ||
| await stat(path); | ||
| return true; | ||
| } catch (error) { | ||
| if ((error as NodeJS.ErrnoException).code === "ENOENT") { | ||
| return false; | ||
| } | ||
| throw error; | ||
| } | ||
| } | ||
| function renderMatrix(rows: CliSandboxMatrixRow[]): string { | ||
| return [ | ||
| "| Metric | Baseline | Workflow | Delta |", | ||
| "| --- | --- | --- | --- |", | ||
| ...rows.map((row) => `| ${row.metric} | ${row.baseline} | ${row.workflow} | ${row.delta} |`), | ||
| ].join("\n"); | ||
| } | ||
| function tokenSpendRows(baseline: CliSandboxRun, workflow: CliSandboxRun): CliSandboxMatrixRow[] { | ||
| return [ | ||
| tokenRow("Input tokens", baseline.tokenSpend?.inputTokens, workflow.tokenSpend?.inputTokens), | ||
| tokenRow("Output tokens", baseline.tokenSpend?.outputTokens, workflow.tokenSpend?.outputTokens), | ||
| tokenRow("Total tokens", totalTokens(baseline.tokenSpend), totalTokens(workflow.tokenSpend)), | ||
| tokenRow( | ||
| "Tokens per accepted criterion", | ||
| tokensPerAcceptedCriterion(baseline), | ||
| tokensPerAcceptedCriterion(workflow), | ||
| ), | ||
| ]; | ||
| } | ||
| function tokenRow( | ||
| metric: string, | ||
| baseline: number | undefined, | ||
| workflow: number | undefined, | ||
| ): CliSandboxMatrixRow { | ||
| if (baseline === undefined || workflow === undefined) { | ||
| return textRow(metric, "unavailable", "unavailable", "unavailable"); | ||
| } | ||
| return countRow(metric, baseline, workflow); | ||
| } | ||
| function totalTokens(tokens: CliSandboxTokenSpend | null): number | undefined { | ||
| if (!tokens || tokens.inputTokens === undefined || tokens.outputTokens === undefined) { | ||
| return undefined; | ||
| } | ||
| return tokens.inputTokens + tokens.outputTokens; | ||
| } | ||
| function tokensPerAcceptedCriterion(run: CliSandboxRun): number | undefined { | ||
| const total = totalTokens(run.tokenSpend); | ||
| const passed = countPassedCriteria(run); | ||
| if (total === undefined || passed === 0) { | ||
| return undefined; | ||
| } | ||
| return total / passed; | ||
| } | ||
| function millisecondsRow(metric: string, baseline: number, workflow: number): CliSandboxMatrixRow { | ||
| return textRow( | ||
| metric, | ||
| `${Math.round(baseline)} ms`, | ||
| `${Math.round(workflow)} ms`, | ||
| `${formatSignedNumber(Math.round(workflow - baseline))} ms`, | ||
| ); | ||
| } | ||
| function countRow(metric: string, baseline: number, workflow: number): CliSandboxMatrixRow { | ||
| return textRow( | ||
| metric, | ||
| formatNumber(baseline), | ||
| formatNumber(workflow), | ||
| formatSignedNumber(workflow - baseline), | ||
| ); | ||
| } | ||
| function percentRow(metric: string, baseline: number, workflow: number): CliSandboxMatrixRow { | ||
| return textRow( | ||
| metric, | ||
| `${formatNumber(baseline)}%`, | ||
| `${formatNumber(workflow)}%`, | ||
| `${formatSignedNumber(workflow - baseline)} pp`, | ||
| ); | ||
| } | ||
| function textRow( | ||
| metric: string, | ||
| baseline: string, | ||
| workflow: string, | ||
| delta: string, | ||
| ): CliSandboxMatrixRow { | ||
| return { metric, baseline, workflow, delta }; | ||
| } | ||
| function criteriaPassRate(run: CliSandboxRun): number { | ||
| if (run.criteria.length === 0) { | ||
| return 100; | ||
| } | ||
| return (countPassedCriteria(run) / run.criteria.length) * 100; | ||
| } | ||
| function countPassedCriteria(run: CliSandboxRun): number { | ||
| return run.criteria.filter((criterion) => criterion.passed).length; | ||
| } | ||
| function sum(values: number[]): number { | ||
| return values.reduce((total, value) => total + value, 0); | ||
| } | ||
| function formatNumber(value: number): string { | ||
| return Number.isInteger(value) ? String(value) : value.toFixed(2); | ||
| } | ||
| function formatSignedNumber(value: number): string { | ||
| if (value > 0) { | ||
| return `+${formatNumber(value)}`; | ||
| } | ||
| return formatNumber(value); | ||
| } | ||
| function stripAnsi(value: string): string { | ||
| const escapeCharacter = String.fromCharCode(27); | ||
| return value.replace(new RegExp(`${escapeCharacter}\\[[0-?]*[ -/]*[@-~]`, "g"), ""); | ||
| } |
@@ -1,8 +0,12 @@ | ||
| # OpenSpec + Superpowers GetSuperpower | ||
| # OpenSpec Delivery GetSuperpower | ||
| This example turns the OpenSpec + Superpowers handoff diagram into an installable | ||
| GetSuperpower reference. | ||
| This example turns an OpenSpec delivery loop into an installable GetSuperpower | ||
| reference. The user calls one professional entry skill, and that skill | ||
| coordinates proposal, design, planning, implementation, verification, and | ||
| archive work. | ||
| It models a closed AI-assisted development loop: | ||
| <img src="../../../assets/diagrams/openspec-delivery-workflow.svg" alt="OpenSpec Delivery workflow diagram" width="920" /> | ||
| It models a closed AI-assisted delivery loop: | ||
| 1. OpenSpec runs `/opsx:propose` to define scope and generate `proposal.md`, | ||
@@ -22,3 +26,3 @@ `specs/`, and `tasks.md`. | ||
| ```text | ||
| skills/openspec-superpowers/SKILL.md | ||
| skills/openspec-delivery/SKILL.md | ||
| ``` | ||
@@ -29,3 +33,3 @@ | ||
| ```text | ||
| $openspec-superpowers implement this OpenSpec change | ||
| $openspec-delivery implement this OpenSpec change | ||
| ``` | ||
@@ -48,3 +52,3 @@ | ||
| - `./skills/openspec-superpowers` | ||
| - `./skills/openspec-delivery` | ||
| - `./skills/opsx-handoff-review` | ||
@@ -69,3 +73,3 @@ - `superpowers:brainstorming` | ||
| ```bash | ||
| bun run dev -- getsuperpower validate examples/workflows/openspec-superpowers | ||
| bun run dev -- validate examples/workflows/openspec-superpowers | ||
| ``` | ||
@@ -76,3 +80,3 @@ | ||
| ```bash | ||
| bun run dev -- getsuperpower deps examples/workflows/openspec-superpowers | ||
| bun run dev -- deps examples/workflows/openspec-superpowers | ||
| ``` | ||
@@ -83,9 +87,9 @@ | ||
| ```bash | ||
| bun run dev -- getsuperpower install examples/workflows/openspec-superpowers | ||
| bun run dev -- getsuperpower clone examples/workflows/openspec-superpowers | ||
| bun run dev -- install examples/workflows/openspec-superpowers | ||
| bun run dev -- clone examples/workflows/openspec-superpowers | ||
| ``` | ||
| `getsuperpower clone <source>` is equivalent to `getsuperpower install <source>`. | ||
| `clone <source>` is equivalent to `install <source>`. | ||
| Restart the agent app after install so the `$openspec-superpowers` entry skill | ||
| Restart the agent app after install so the `$openspec-delivery` entry skill | ||
| and its sub-skills are available. |
| { | ||
| "schemaVersion": "0.1", | ||
| "name": "openspec-superpowers", | ||
| "name": "openspec-delivery", | ||
| "version": "0.1.0", | ||
| "description": "OpenSpec proposes, reviews, and archives while Superpowers deepens design, executes task by task, and verifies delivery.", | ||
| "description": "Professional OpenSpec delivery workflow from proposal through design, plan, TDD implementation, verification, and archive.", | ||
| "skills": [ | ||
| { | ||
| "source": "./skills/openspec-superpowers" | ||
| "source": "./skills/openspec-delivery" | ||
| }, | ||
@@ -10,0 +10,0 @@ { |
+2
-2
| { | ||
| "name": "getsuperpower", | ||
| "version": "0.3.1", | ||
| "version": "0.3.2", | ||
| "type": "module", | ||
@@ -16,3 +16,2 @@ "repository": { | ||
| "bundled-skills", | ||
| "bundled-workflows", | ||
| "examples" | ||
@@ -29,2 +28,3 @@ ], | ||
| "deps:check-recency": "bun scripts/check-package-recency.ts", | ||
| "sandbox:evaluate-cli": "bun scripts/evaluate-cli-sandbox.ts", | ||
| "typecheck": "tsc --noEmit", | ||
@@ -31,0 +31,0 @@ "format": "biome format --write .", |
+44
-49
@@ -5,21 +5,23 @@ <img src="/assets/getsupwerpower.jpg" alt="GetSuperpower" width="640" /> | ||
| GetSuperpower installs reusable AI-agent workflows. | ||
| GetSuperpower packages a whole AI-agent workflow as one callable skill. | ||
| A **GetSuperpower** is a deployable bundle skills set for an AI agent workflow. | ||
| It installs the skills a project needs, records the workflow under `.getsuperpower/`, | ||
| and can give users one entry skill to call when the workflow provides one. | ||
| A **GetSuperpower** is an all-in-one workflow skill. Install it once, call one | ||
| entry skill, and the agent follows the required sub-skills in order. A workflow | ||
| can plan a spec, brainstorm design, write an implementation plan, build with | ||
| TDD, and archive the result without the user calling each skill separately. | ||
| ## Quick Start | ||
| Install or clone the default product-development GetSuperpower: | ||
| Install a workflow example from the GetSuperpower git repository: | ||
| ```bash | ||
| npx getsuperpower install product-dev | ||
| npx getsuperpower@latest install 'https://github.com/0xroylee/getsuperpower.git#examples/workflows/openspec-superpowers' | ||
| ``` | ||
| Install from a public git repository: | ||
| Install other workflow examples the same way: | ||
| ```bash | ||
| npx getsuperpower install https://github.com/acme/release-review.git | ||
| npx getsuperpower install 'https://github.com/acme/workflows.git#examples/release-review' | ||
| npx getsuperpower@latest install 'https://github.com/0xroylee/getsuperpower.git#examples/workflows/release-review' | ||
| npx getsuperpower@latest clone 'https://github.com/0xroylee/getsuperpower.git#examples/workflows/real-engineering' | ||
| npx getsuperpower@latest install 'https://github.com/0xroylee/getsuperpower.git#examples/workflows/development-design-delivery' | ||
| ``` | ||
@@ -30,6 +32,6 @@ | ||
| ```bash | ||
| npx getsuperpower list | ||
| npx getsuperpower@latest list | ||
| ``` | ||
| Supported agents: Claude, Codex, opencode, Cursor, and GitHub Copilot. | ||
| Supported agents: Claude, Codex, Cursor, opencode/OpenCodex, and GitHub Copilot. CLI aliases include `opencode`, `opencodex`, `copilot`, and `github-copilot`. | ||
@@ -42,3 +44,3 @@ Restart your agent after installing skills so it reloads them. | ||
| `workflow.json` installs the skill tree. The entry skill runs it. Sub-skills are the steps the agent follows. | ||
| `workflow.json` installs the skill tree. The entry skill is the one command users invoke. Sub-skills are the steps the agent follows behind that call. | ||
@@ -49,20 +51,2 @@ ### Install And Run Sequence | ||
| ## Try A Callable Workflow | ||
| Some GetSuperpowers include an entry skill. That is the one skill a user calls to run the whole skill tree. | ||
| From a cloned repo, the OpenSpec + Superpowers example installs `$openspec-superpowers`: | ||
| ```bash | ||
| npx getsuperpower install examples/workflows/openspec-superpowers | ||
| ``` | ||
| Then restart your agent app and invoke: | ||
| ```text | ||
| $openspec-superpowers implement this OpenSpec change | ||
| ``` | ||
| The entry skill tells the agent to use the required sub-skills in order. The CLI handles installation, validation, and local workflow records. | ||
| ## Create Your Own | ||
@@ -75,3 +59,3 @@ | ||
| ```bash | ||
| npx getsuperpower init release-review | ||
| npx getsuperpower@latest init release-review | ||
| ``` | ||
@@ -97,3 +81,3 @@ | ||
| ```bash | ||
| npx getsuperpower skills install creating-bundle-skills | ||
| npx getsuperpower@latest skills install creating-bundle-skills | ||
| ``` | ||
@@ -113,4 +97,4 @@ | ||
| ```bash | ||
| npx getsuperpower validate release-review | ||
| npx getsuperpower deps release-review | ||
| npx getsuperpower@latest validate release-review | ||
| npx getsuperpower@latest deps release-review | ||
| ``` | ||
@@ -124,3 +108,4 @@ | ||
| | --- | --- | --- | | ||
| | `examples/workflows/openspec-superpowers` | OpenSpec proposal -> Superpowers planning/TDD -> archive. | Includes `$openspec-superpowers`. | | ||
| | `examples/workflows/openspec-superpowers` | OpenSpec Delivery: proposal -> design -> plan -> TDD -> verification -> archive. | Includes `$openspec-delivery`. | | ||
| | `examples/workflows/development-design-delivery` | Product-minded engineering: shape -> interface design -> plan -> TDD -> review -> evidence. | Includes `$development-design-delivery`. | | ||
| | `examples/workflows/real-engineering` | RTK, `pony-trail`, Superpowers, and Matt Pocock skills together. | Fetches Matt Pocock skills if missing. | | ||
@@ -132,20 +117,21 @@ | `examples/workflows/release-review` | Small release-risk review workflow. | Good starter example. | | ||
| ```bash | ||
| npx getsuperpower skills install mattpocock/skills | ||
| npx getsuperpower@latest skills install mattpocock/skills | ||
| ``` | ||
| ## Common Commands | ||
| ## Commands | ||
| | Command | Purpose | | ||
| | --- | --- | | ||
| | `npx getsuperpower install product-dev` | Install the default GetSuperpower. | | ||
| | `npx getsuperpower clone product-dev` | Same as install; deploy a GetSuperpower by name or source. | | ||
| | `npx getsuperpower install https://github.com/acme/release-review.git` | Install a GetSuperpower from a public git repo. | | ||
| | `npx getsuperpower deps <source>` | Show required skills before install or clone. | | ||
| | `npx getsuperpower list` | Show installed GetSuperpowers. | | ||
| | `npx getsuperpower init <name>` | Create a GetSuperpower scaffold. | | ||
| | `npx getsuperpower validate <path>` | Validate a workflow manifest. | | ||
| | `npx getsuperpower skills install` | Install the GetSuperpower authoring skill. | | ||
| | `npx getsuperpower skills install mattpocock/skills` | Install an external skills package through the Skills CLI. | | ||
| | `npx getsuperpower skills install creating-bundle-skills` | Install the GetSuperpower authoring skill. | | ||
| The GetSuperpower CLI supports workflow install, inspection, authoring, and skill management. Below are some of the most used commands: | ||
| - `npx getsuperpower@latest install <path-or-git-url>` | ||
| - `npx getsuperpower@latest clone <path-or-git-url>` | ||
| - `npx getsuperpower@latest deps <source>` | ||
| - `npx getsuperpower@latest list` | ||
| - `npx getsuperpower@latest init <name>` | ||
| - `npx getsuperpower@latest validate <path>` | ||
| - `npx getsuperpower@latest skills install` | ||
| - `npx getsuperpower@latest skills install mattpocock/skills` | ||
| - `npx getsuperpower@latest skills install creating-bundle-skills` | ||
| Run `npx getsuperpower@latest --help` or `npx getsuperpower@latest <command> --help` for detailed usage. | ||
| The older `bundle` and `workflow` commands still work as compatibility aliases. | ||
@@ -176,4 +162,13 @@ | ||
| Landing app: | ||
| ```bash | ||
| cd landing | ||
| bun install | ||
| bun run dev | ||
| bun run build | ||
| ``` | ||
| ## Compatibility | ||
| The package and CLI binary are named `getsuperpower`. |
+33
-17
@@ -6,4 +6,11 @@ #!/usr/bin/env bun | ||
| import { Command } from "commander"; | ||
| import pc from "picocolors"; | ||
| import { | ||
| keyValue, | ||
| muted, | ||
| rootHelpBanner, | ||
| styleHelpTerm, | ||
| styleHelpTitle, | ||
| success, | ||
| } from "./cli-theme"; | ||
| import { | ||
| configureGetSuperpowerCommand, | ||
@@ -18,3 +25,3 @@ type GetSuperpowerExternalSkillDependencyInstaller, | ||
| const CLI_VERSION = "0.3.1"; | ||
| const CLI_VERSION = "0.3.2"; | ||
@@ -44,2 +51,11 @@ interface CommanderVersionInternals { | ||
| .option("-v", "output the version number"); | ||
| program.configureHelp({ | ||
| styleTitle: styleHelpTitle, | ||
| styleSubcommandTerm: styleHelpTerm, | ||
| styleOptionTerm: styleHelpTerm, | ||
| }); | ||
| program.addHelpText("before", rootHelpBanner); | ||
| program.action(() => { | ||
| program.help(); | ||
| }); | ||
@@ -111,4 +127,4 @@ program.on("option:v", () => { | ||
| "-a, --agents <agents>", | ||
| "comma-separated targets: claude,copilot,codex,cursor", | ||
| "claude,copilot,codex,cursor", | ||
| "comma-separated targets: claude,copilot,codex,cursor,opencode (aliases: github-copilot,opencodex)", | ||
| "claude,copilot,codex,cursor,opencode", | ||
| ) | ||
@@ -258,9 +274,9 @@ .option("--home <dir>", "home directory that contains agent config folders", homedir()) | ||
| ): void { | ||
| console.log(pc.cyan(result.dryRun ? `Skill ${operation} plan` : `Skill ${operation} result`)); | ||
| console.log(`Skill: ${result.skillName}`); | ||
| console.log(`${pc.dim("Source:")} ${result.source.path}`); | ||
| console.log(success(result.dryRun ? `Skill ${operation} plan` : `Skill ${operation} result`)); | ||
| console.log(keyValue("Skill", result.skillName)); | ||
| console.log(keyValue("Source", result.source.path)); | ||
| for (const target of result.targets) { | ||
| console.log( | ||
| `${target.agent}: ${formatSkillInstallStatus(target.status)} ${pc.dim(target.destination)}`, | ||
| `${target.agent}: ${formatSkillInstallStatus(target.status)} ${muted(target.destination)}`, | ||
| ); | ||
@@ -272,9 +288,9 @@ } | ||
| console.log( | ||
| pc.cyan(result.dryRun ? `Prehook ${operation} plan` : `Prehook ${operation} result`), | ||
| success(result.dryRun ? `Prehook ${operation} plan` : `Prehook ${operation} result`), | ||
| ); | ||
| for (const prehook of result.prehooks) { | ||
| console.log( | ||
| `${prehook.agent}: ${formatSkillInstallStatus(prehook.status)} ${pc.dim( | ||
| `${prehook.agent}: ${formatSkillInstallStatus(prehook.status)} ${muted( | ||
| prehook.hookScript, | ||
| )} ${pc.dim(`settings: ${prehook.settingsPath}`)}`, | ||
| )} ${muted(`settings: ${prehook.settingsPath}`)}`, | ||
| ); | ||
@@ -312,11 +328,11 @@ } | ||
| console.log( | ||
| pc.cyan(result.dryRun ? "Skills package install plan" : "Skills package install result"), | ||
| success(result.dryRun ? "Skills package install plan" : "Skills package install result"), | ||
| ); | ||
| console.log(`Package: ${result.packageName}`); | ||
| console.log(`${pc.dim("Home:")} ${result.homeDir}`); | ||
| console.log(`${pc.dim("Internal command:")} npx --yes skills@latest add ${result.packageName}`); | ||
| console.log(keyValue("Package", result.packageName)); | ||
| console.log(keyValue("Home", result.homeDir)); | ||
| console.log(keyValue("Internal command", `npx --yes skills@latest add ${result.packageName}`)); | ||
| if (!result.dryRun) { | ||
| console.log(""); | ||
| console.log(pc.green("Welcome to GetSuperpower.")); | ||
| console.log(success("Welcome to GetSuperpower.")); | ||
| console.log("Restart your agent IDE so it loads the latest skills."); | ||
@@ -332,3 +348,3 @@ } | ||
| console.log(""); | ||
| console.log(pc.green("Welcome to GetSuperpower.")); | ||
| console.log(success("Welcome to GetSuperpower.")); | ||
| console.log("Restart your agent IDE so it loads the latest skills."); | ||
@@ -335,0 +351,0 @@ } |
+165
-17
@@ -0,7 +1,10 @@ | ||
| import { existsSync } from "node:fs"; | ||
| import { homedir } from "node:os"; | ||
| import { isAbsolute, join, resolve } from "node:path"; | ||
| import { cancel as clackCancel, confirm as clackConfirm, isCancel } from "@clack/prompts"; | ||
| import type { Command } from "commander"; | ||
| import pc from "picocolors"; | ||
| import { commandText, keyValue, muted, nextStep, success, warning } from "./cli-theme"; | ||
| import { | ||
| MissingMattPocockSkillError, | ||
| MissingSuperpowersSkillError, | ||
| parseSkillInstallAgents, | ||
@@ -76,2 +79,23 @@ type SkillInstallResult, | ||
| export interface GetSuperpowerOnboardPrompt { | ||
| confirm(input: { message: string; defaultValue: boolean }): Promise<boolean>; | ||
| } | ||
| export interface GetSuperpowerOnboardCommand { | ||
| executable: string; | ||
| args: string[]; | ||
| cwd: string; | ||
| env: Record<string, string | undefined>; | ||
| } | ||
| export interface GetSuperpowerOnboardCommandResult { | ||
| stdout: string; | ||
| stderr: string; | ||
| exitCode: number; | ||
| } | ||
| export type GetSuperpowerOnboardCommandRunner = ( | ||
| command: GetSuperpowerOnboardCommand, | ||
| ) => Promise<GetSuperpowerOnboardCommandResult>; | ||
| export interface ConfigureGetSuperpowerCommandOptions { | ||
@@ -83,2 +107,4 @@ rootDir: string; | ||
| workflowGitCommandRunner?: WorkflowGitCommandRunner; | ||
| onboardPrompt?: GetSuperpowerOnboardPrompt; | ||
| onboardCommandRunner?: GetSuperpowerOnboardCommandRunner; | ||
| } | ||
@@ -122,2 +148,3 @@ | ||
| configureDependencyCommand(command, options); | ||
| configureOnboardCommand(command, options); | ||
| } | ||
@@ -140,5 +167,5 @@ | ||
| console.log(`GetSuperpower created: ${scaffold.bundleDir}`); | ||
| console.log(`${pc.dim("Manifest:")} ${scaffold.manifestPath}`); | ||
| console.log(`${pc.dim("README:")} ${scaffold.readmePath}`); | ||
| console.log(success(`GetSuperpower created: ${scaffold.bundleDir}`)); | ||
| console.log(keyValue("Manifest", scaffold.manifestPath)); | ||
| console.log(keyValue("README", scaffold.readmePath)); | ||
| }); | ||
@@ -158,5 +185,7 @@ | ||
| try { | ||
| console.log(`GetSuperpower valid: ${bundle.manifest.name}@${bundle.manifest.version}`); | ||
| console.log(`${pc.dim("Steps:")} ${bundle.manifest.steps.length}`); | ||
| console.log(`${pc.dim("Skills:")} ${bundle.manifest.skills.length}`); | ||
| console.log( | ||
| success(`GetSuperpower valid: ${bundle.manifest.name}@${bundle.manifest.version}`), | ||
| ); | ||
| console.log(keyValue("Steps", String(bundle.manifest.steps.length))); | ||
| console.log(keyValue("Skills", String(bundle.manifest.skills.length))); | ||
| } finally { | ||
@@ -187,3 +216,3 @@ await bundle.cleanup?.(); | ||
| .description("Install a GetSuperpower and its skills.") | ||
| .argument("<source>", "GetSuperpower name, local path, or workflow source") | ||
| .argument("<source>", "local GetSuperpower path, workflow.json path, or public git source") | ||
| .option( | ||
@@ -196,3 +225,3 @@ "--dir <dir>", | ||
| "--agents <agents>", | ||
| "comma-separated skill install targets: codex,claude,cursor", | ||
| "comma-separated skill install targets: codex,claude,cursor,copilot,opencode (aliases: github-copilot,opencodex)", | ||
| "codex,claude,cursor", | ||
@@ -242,4 +271,4 @@ ) | ||
| console.log(`GetSuperpower installed: ${install.workflow.name}`); | ||
| console.log(`${pc.dim("GetSuperpower file:")} ${install.path}`); | ||
| console.log(success(`GetSuperpower installed: ${install.workflow.name}`)); | ||
| console.log(keyValue("GetSuperpower file", install.path)); | ||
| } finally { | ||
@@ -268,3 +297,3 @@ await bundle.cleanup?.(); | ||
| if (!input.installedExternalPackages.has(externalPackage)) { | ||
| console.log(`Installing external skill dependency with skills CLI: ${externalPackage}`); | ||
| console.log(keyValue("Installing external skill dependency", externalPackage)); | ||
| await input.installExternalSkillDependency({ | ||
@@ -280,3 +309,3 @@ source: input.source, | ||
| } catch (retryError) { | ||
| if (retryError instanceof MissingMattPocockSkillError) { | ||
| if (isMissingBootstrappableSkillError(retryError)) { | ||
| throw new Error( | ||
@@ -312,3 +341,3 @@ `The skills CLI ran for ${externalPackage}, but ${input.source} is still missing. ${retryError.message}`, | ||
| function getSkillsCliPackageForMissingDependency(source: string, error: unknown): string | null { | ||
| if (!(error instanceof MissingMattPocockSkillError)) { | ||
| if (!isMissingBootstrappableSkillError(error)) { | ||
| return null; | ||
@@ -320,2 +349,10 @@ } | ||
| function isMissingBootstrappableSkillError( | ||
| error: unknown, | ||
| ): error is MissingMattPocockSkillError | MissingSuperpowersSkillError { | ||
| return ( | ||
| error instanceof MissingMattPocockSkillError || error instanceof MissingSuperpowersSkillError | ||
| ); | ||
| } | ||
| export function getSkillsCliPackageForSource(source: string): string | null { | ||
@@ -326,2 +363,6 @@ if (isBareSkillsCliPackage(source)) { | ||
| if (source.startsWith("superpowers:")) { | ||
| return "obra/superpowers"; | ||
| } | ||
| if (source.startsWith("mattpocock:")) { | ||
@@ -406,3 +447,4 @@ return "mattpocock/skills"; | ||
| if (workflows.length === 0) { | ||
| console.log(pc.dim("No GetSuperpowers installed.")); | ||
| console.log(muted("No GetSuperpowers installed.")); | ||
| console.log(nextStep("getsuperpower install <path-or-git-url>")); | ||
| return; | ||
@@ -425,3 +467,3 @@ } | ||
| .description("List the skill dependencies declared by a GetSuperpower.") | ||
| .argument("<source>", "bundled GetSuperpower name or local GetSuperpower path") | ||
| .argument("<source>", "local GetSuperpower path, workflow.json path, or public git source") | ||
| .action(async (source: string) => { | ||
@@ -435,3 +477,3 @@ const bundle = await loadWorkflowBundle(source, { | ||
| try { | ||
| console.log(`GetSuperpower dependencies: ${bundle.manifest.name}`); | ||
| console.log(success(`GetSuperpower dependencies: ${bundle.manifest.name}`)); | ||
| for (const skill of bundle.manifest.skills) { | ||
@@ -447,2 +489,108 @@ const optional = skill.optional ? " (optional)" : ""; | ||
| function configureOnboardCommand( | ||
| command: Command, | ||
| options: ConfigureGetSuperpowerCommandOptions, | ||
| ): void { | ||
| command | ||
| .command("onboard") | ||
| .description("Step through RTK and CodeGraph setup for this workspace.") | ||
| .option("--dir <dir>", "project directory to onboard", options.rootDir) | ||
| .action((commandOptions: { dir: string }) => runGetSuperpowerOnboard(commandOptions, options)); | ||
| } | ||
| async function runGetSuperpowerOnboard( | ||
| commandOptions: { dir: string }, | ||
| options: ConfigureGetSuperpowerCommandOptions, | ||
| ): Promise<void> { | ||
| const targetDir = resolvePath(options.rootDir, commandOptions.dir); | ||
| if (!existsSync(targetDir)) { | ||
| throw new Error(`Onboard target directory does not exist: ${targetDir}`); | ||
| } | ||
| const prompt = options.onboardPrompt ?? createDefaultOnboardPrompt(); | ||
| const runCommand = options.onboardCommandRunner ?? runExternalSkillCommand; | ||
| console.log(success("GetSuperpower onboard")); | ||
| console.log(keyValue("Workspace", targetDir)); | ||
| const rtkResult = await runCommand({ | ||
| executable: "rtk", | ||
| args: ["--version"], | ||
| cwd: targetDir, | ||
| env: process.env, | ||
| }); | ||
| if (rtkResult.exitCode === 0) { | ||
| console.log(success("RTK ready")); | ||
| } else if ( | ||
| await prompt.confirm({ | ||
| message: "RTK is not available. Show RTK setup guidance to reduce Codex token usage?", | ||
| defaultValue: true, | ||
| }) | ||
| ) { | ||
| printRtkSetupGuidance(); | ||
| } else { | ||
| console.log(warning("RTK setup skipped")); | ||
| } | ||
| const codegraphDir = join(targetDir, ".codegraph"); | ||
| if (existsSync(codegraphDir)) { | ||
| console.log(success("CodeGraph ready")); | ||
| } else if ( | ||
| await prompt.confirm({ | ||
| message: "CodeGraph is not initialized. Index this codebase with CodeGraph now?", | ||
| defaultValue: true, | ||
| }) | ||
| ) { | ||
| await runCodeGraphInit({ targetDir, runCommand }); | ||
| } else { | ||
| console.log(warning("CodeGraph setup skipped")); | ||
| } | ||
| console.log(success("GetSuperpower onboard complete")); | ||
| } | ||
| function printRtkSetupGuidance(): void { | ||
| console.log(success("RTK setup guidance")); | ||
| console.log("Install or enable RTK, then verify it with:"); | ||
| console.log(commandText("rtk --version")); | ||
| } | ||
| async function runCodeGraphInit(input: { | ||
| targetDir: string; | ||
| runCommand: GetSuperpowerOnboardCommandRunner; | ||
| }): Promise<void> { | ||
| const result = await input.runCommand({ | ||
| executable: "codegraph", | ||
| args: ["init", "-i"], | ||
| cwd: input.targetDir, | ||
| env: process.env, | ||
| }); | ||
| if (result.exitCode !== 0) { | ||
| const detail = result.stderr.trim() || result.stdout.trim() || `exit ${result.exitCode}`; | ||
| throw new Error(`CodeGraph setup failed while running codegraph init -i: ${detail}`); | ||
| } | ||
| console.log(success("CodeGraph indexed")); | ||
| } | ||
| function createDefaultOnboardPrompt(): GetSuperpowerOnboardPrompt { | ||
| return { | ||
| confirm: async (input) => { | ||
| const result = await clackConfirm({ | ||
| message: input.message, | ||
| initialValue: input.defaultValue, | ||
| }); | ||
| if (isCancel(result)) { | ||
| clackCancel("GetSuperpower onboard cancelled"); | ||
| throw new Error("GetSuperpower onboard cancelled"); | ||
| } | ||
| return result; | ||
| }, | ||
| }; | ||
| } | ||
| function resolvePath(rootDir: string, path: string): string { | ||
@@ -449,0 +597,0 @@ return isAbsolute(path) ? path : resolve(join(rootDir, path)); |
@@ -6,4 +6,4 @@ import { constants, type Dirent } from "node:fs"; | ||
| export type SkillInstallAgent = "claude" | "copilot" | "codex" | "cursor"; | ||
| type HookCapableSkillInstallAgent = Exclude<SkillInstallAgent, "cursor">; | ||
| export type SkillInstallAgent = "claude" | "copilot" | "codex" | "cursor" | "opencode"; | ||
| type HookCapableSkillInstallAgent = Exclude<SkillInstallAgent, "cursor" | "opencode">; | ||
@@ -126,2 +126,3 @@ export type SkillInstallStatus = | ||
| cursor: { kind: "cursor_rule", path: [".cursor", "rules"] }, | ||
| opencode: { kind: "directory", path: [".agents", "skills"] }, | ||
| }; | ||
@@ -333,3 +334,5 @@ | ||
| const homeDir = options.homeDir ?? process.env.HOME ?? process.cwd(); | ||
| const skillPath = await findSuperpowersSkillPath(homeDir, skill.skillFolder); | ||
| const skillPath = | ||
| (await findSuperpowersSkillPath(homeDir, skill.skillFolder)) ?? | ||
| (await findInstalledSuperpowersSkillPath(homeDir, skill)); | ||
@@ -350,2 +353,12 @@ if (!skillPath) { | ||
| async function findInstalledSuperpowersSkillPath( | ||
| homeDir: string, | ||
| skill: SupportedSuperpowersSkill, | ||
| ): Promise<string | null> { | ||
| return ( | ||
| (await findInstalledSkillPath(homeDir, skill.installName)) ?? | ||
| (await findInstalledSkillPath(homeDir, skill.skillFolder)) | ||
| ); | ||
| } | ||
| async function findSuperpowersSkillPath( | ||
@@ -406,3 +419,3 @@ homeDir: string, | ||
| export function parseSkillInstallAgents(rawAgents: string): SkillInstallAgent[] { | ||
| const agents = rawAgents | ||
| const rawAgentEntries = rawAgents | ||
| .split(",") | ||
@@ -412,13 +425,21 @@ .map((agent) => agent.trim()) | ||
| if (agents.length === 0) { | ||
| if (rawAgentEntries.length === 0) { | ||
| throw new Error("At least one agent target is required."); | ||
| } | ||
| for (const agent of agents) { | ||
| if (!isSkillInstallAgent(agent)) { | ||
| throw new Error(`Unknown skill install agent: ${agent}`); | ||
| const uniqueAgents: SkillInstallAgent[] = []; | ||
| const seenAgents = new Set<SkillInstallAgent>(); | ||
| for (const rawAgent of rawAgentEntries) { | ||
| const agent = normalizeSkillInstallAgent(rawAgent); | ||
| if (!agent) { | ||
| throw new Error(`Unknown skill install agent: ${rawAgent}`); | ||
| } | ||
| if (!seenAgents.has(agent)) { | ||
| seenAgents.add(agent); | ||
| uniqueAgents.push(agent); | ||
| } | ||
| } | ||
| return agents as SkillInstallAgent[]; | ||
| return uniqueAgents; | ||
| } | ||
@@ -796,7 +817,29 @@ | ||
| function isSkillInstallAgent(agent: string): agent is SkillInstallAgent { | ||
| return agent === "claude" || agent === "copilot" || agent === "codex" || agent === "cursor"; | ||
| return ( | ||
| agent === "claude" || | ||
| agent === "copilot" || | ||
| agent === "codex" || | ||
| agent === "cursor" || | ||
| agent === "opencode" | ||
| ); | ||
| } | ||
| function normalizeSkillInstallAgent(agent: string): SkillInstallAgent | null { | ||
| const normalized = agent.toLowerCase(); | ||
| const aliases: Record<string, SkillInstallAgent> = { | ||
| "github copilot": "copilot", | ||
| "github-copilot": "copilot", | ||
| githubcopilot: "copilot", | ||
| github_copilot: "copilot", | ||
| "open codex": "opencode", | ||
| "open-codex": "opencode", | ||
| opencodex: "opencode", | ||
| }; | ||
| const canonical = aliases[normalized] ?? normalized; | ||
| return isSkillInstallAgent(canonical) ? canonical : null; | ||
| } | ||
| function hasPrehookSupport(agent: SkillInstallAgent): agent is HookCapableSkillInstallAgent { | ||
| return agent !== "cursor"; | ||
| return agent !== "cursor" && agent !== "opencode"; | ||
| } | ||
@@ -809,3 +852,3 @@ | ||
| function formatSuperpowersInstallCommand(source: string): string { | ||
| return `getsuperpower skills install ${source} --agents codex,claude,cursor --home ~`; | ||
| return `getsuperpower skills install ${source} --agents codex,claude,cursor,copilot,opencode --home ~`; | ||
| } | ||
@@ -812,0 +855,0 @@ |
@@ -77,3 +77,3 @@ import { existsSync } from "node:fs"; | ||
| | { | ||
| kind: "bundled" | "local"; | ||
| kind: "local"; | ||
| path: string; | ||
@@ -348,4 +348,5 @@ } | ||
| const sourceDir = join(findBundledWorkflowsDir(), source); | ||
| return { sourceDir, source: { kind: "bundled", path: sourceDir } }; | ||
| throw new Error( | ||
| `Unsupported GetSuperpower source: ${source}. Use a local path, workflow.json path, or public git URL.`, | ||
| ); | ||
| } | ||
@@ -515,19 +516,1 @@ | ||
| } | ||
| function findBundledWorkflowsDir(): string { | ||
| const currentDir = dirname(new URL(import.meta.url).pathname); | ||
| const candidates = [ | ||
| join(currentDir, "..", "..", "..", "bundled-workflows"), | ||
| join(currentDir, "..", "bundled-workflows"), | ||
| join(process.cwd(), "bundled-workflows"), | ||
| ]; | ||
| const found = candidates.find((candidate) => | ||
| existsSync(join(candidate, "product-dev", workflowFileName)), | ||
| ); | ||
| if (!found) { | ||
| throw new Error("Unable to locate bundled workflow files."); | ||
| } | ||
| return found; | ||
| } |
| # Product Dev GetSuperpower | ||
| This GetSuperpower composes a bundle-skills product-development path: | ||
| 1. Shape the request with `superpowers:brainstorming`. | ||
| 2. Write the implementation plan with `superpowers:writing-plans`. | ||
| It installs the GetSuperpower contract first. Automatic step execution is intentionally deferred. |
| { | ||
| "schemaVersion": "0.1", | ||
| "name": "product-dev", | ||
| "version": "0.1.0", | ||
| "description": "Shape and plan product development changes.", | ||
| "skills": [ | ||
| { | ||
| "source": "superpowers:brainstorming" | ||
| }, | ||
| { | ||
| "source": "superpowers:writing-plans" | ||
| } | ||
| ], | ||
| "steps": [ | ||
| { | ||
| "id": "shape", | ||
| "title": "Shape the request", | ||
| "skill": "superpowers:brainstorming", | ||
| "gate": "human_approval" | ||
| }, | ||
| { | ||
| "id": "plan", | ||
| "title": "Write the implementation plan", | ||
| "skill": "superpowers:writing-plans" | ||
| } | ||
| ] | ||
| } |
| --- | ||
| name: openspec-superpowers | ||
| description: Use when running the OpenSpec + Superpowers GetSuperpower workflow, skill tree, or multi-skill development loop from proposal through archive. | ||
| --- | ||
| # OpenSpec + Superpowers GetSuperpower | ||
| This is the entry skill for the openspec-superpowers GetSuperpower. | ||
| When this skill is used, run the workflow below in order. Load/use every required sub-skill before doing the work for its phase. | ||
| ## Required Sub-Skills | ||
| Before doing workflow work, load/use these skills in order: | ||
| 1. opsx-handoff-review (`./skills/opsx-handoff-review`) - OpenSpec proposal, review, handoff, and archive checkpoints | ||
| 2. superpowers:brainstorming - design deepening before implementation planning | ||
| 3. superpowers:writing-plans - split approved scope into executable tasks | ||
| 4. mattpocock:tdd - build task by task with failing tests first | ||
| 5. pony-trail - record file-change evidence, verification, and rollback context | ||
| If any required sub-skill is unavailable, stop and tell the user which dependency is missing. | ||
| ## Flow | ||
| 1. Run `/opsx:propose` to create proposal, specs, and tasks. | ||
| - Skill: opsx-handoff-review (`./skills/opsx-handoff-review`) | ||
| 2. Review `proposal.md` with the human owner. | ||
| - Skill: opsx-handoff-review (`./skills/opsx-handoff-review`) | ||
| - Gate: wait for explicit human approval. | ||
| 3. Deepen design details with Superpowers brainstorming. | ||
| - Skill: superpowers:brainstorming | ||
| - Gate: wait for explicit human approval. | ||
| 4. Split tasks into an implementation plan. | ||
| - Skill: superpowers:writing-plans | ||
| 5. Build each task with TDD and `specs/` context. | ||
| - Skill: mattpocock:tdd | ||
| 6. Verify delivery and preserve evidence. | ||
| - Skill: pony-trail | ||
| 7. Run `/opsx:archive` to update specs and project knowledge. | ||
| - Skill: opsx-handoff-review (`./skills/opsx-handoff-review`) | ||
| - Gate: wait for explicit human approval. | ||
| ## Author Notes | ||
| - Keep this entry skill, `workflow.json`, and `README.md` aligned when adding or removing steps. | ||
| - This skill orchestrates through required instructions; GetSuperpower installs and validates the dependency skills. | ||
| - Do not silently skip OpenSpec review, human approval gates, TDD, verification, or archive. |
Sorry, the diff of this file is too big to display
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 3 instances
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 2 instances
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 2 instances
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
900233
9.82%42
16.67%22677
7.41%165
-2.94%35
25%