Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion plugins/spryker-ai-dev-sdk/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "spryker-ai-dev-sdk",
"version": "0.2.0",
"version": "0.3.0",
"description": "Set of setup tools and skills for Spryker project development.",
"author": {
"name": "Spryker Systems GmbH",
Expand Down
134 changes: 134 additions & 0 deletions plugins/spryker-ai-dev-sdk/skills/spryker-bugfix/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# spryker-bugfix

End-to-end bug-fixing workflow for Spryker projects: from a **ticket _or_ a plain description** to a
committed, validated, QA-accepted fix on a `bugfix/*` branch. In Autonomous mode it goes all the way to
a pushed **Draft PR** with a remote-CI watch loop.

This skill is an **orchestrator** — it runs a fixed sequence of stages and delegates the heavy work of
each stage to an already-installed skill or Claude subagent. It writes no product code itself; it
coordinates the skills that do.

## Files

| File | Role |
|------|------|
| [`SKILL.md`](SKILL.md) | The workflow spine — Steps 0–12, one paragraph each. This is what Claude loads. |
| [`stages.md`](stages.md) | Full, authoritative per-step instructions + the stage→skill quick map. Read the relevant § before each step. |
| [`reference.md`](reference.md) | Run-lean context discipline (`$BUGFIX_DIR`, State Object), operating principles, decision log, red flags. Read once per run. |

## Two ways in — the ticket is optional

The bug context can come from **either or both** of:

- a **ticket** from any tracker (JIRA key, GitHub issue URL/number, or any other service), **or**
- a **free-text description** of the symptom with technical hints.

A ticket is **never required**. When a ticket exists and its integration is reachable (Atlassian MCP,
`gh`, …) the skill pulls it for extra context; otherwise it works entirely from the description. The
branch name, PR title, and commit message all fall back to `no-ticket` / `NO-TICKET`.

## Design constraints

- **Claude-only.** Every stage delegates to a bundled/installed `Skill(...)` or a Claude subagent. No
third-party MCP is required for the core flow — the **only** external touchpoint is the optional
Step 0 ticket pull. Every spawned subagent runs on a Claude model.
- **Run lean.** Bulk output (Chrome, XDebug, codecept, phpcs/phpstan, review, verification, CI logs)
runs inside subagents that write raw logs to `$BUGFIX_DIR`
(`$CLAUDE_PROJECT_DIR/.claude/.cache/spryker-bugfix/<bugfix-id>/`) and return only compact verdicts.
- **Plan is a task list.** Step 0 arranges the 12 stages as a `TaskCreate` task list and drives it with
`TaskUpdate` (one task `in_progress` at a time; a fresh attempt task per loopback). `TaskList` is the
live position — it survives compaction and scheduled wake-ups, so a resumed run or the watch loop
re-orients from it. It complements the `run.log` timeline and the `decisions.md` rationale.
- **The bug is the contract.** A fix is "done" only when the user-visible symptom no longer reproduces
with evidence **and** every gate is green.
- **PR channel is capability-gated.** Step 0 probes how the run can reach a remote and records
`PR_CHANNEL` — `gh` (push + Draft PR + CI watch), `git-only` (push a branch, no PR API), or `none`
(local-only). `gh` is **never assumed**: if it's missing or unauthenticated, Step 11 degrades to a
clean local terminal (commit, and — where possible — push + a handoff `gh pr create` line) instead of
failing. Every GitHub step checks the channel first and is skipped-with-a-note when unavailable.

## Modes

- **Collaborative** — the agent stops at the important decision points and **before push** for review.
- **Autonomous** — after the single Step 0 intake, the agent runs unattended to a pushed Draft PR;
every fork is a logged CRITICAL DECISION, not a question. The only hard stops are a stale/dirty base
(Step 2) and the attempt budget (`attempt > 3`).

## Flow

```mermaid
flowchart TD
Start([Trigger: 'fix this bug' / ticket / description]) --> S0

S0["Step 0 — Mode + context<br/>(ticket OPTIONAL, or description)<br/>run dir + logger, env-reset<br/>probe PR_CHANNEL: gh / git-only / none"]
S0 --> S1["Step 1 — Intake &amp; framing"]
S1 --> S2{"Step 2 — Branch<br/>SAFETY GATE<br/>clean tree &amp; fresh base?"}

S2 -- "dirty / stale" --> Abort["Ask (Collaborative)<br/>or abort (Autonomous)"]
Abort --> Report
S2 -- "ok → bugfix/&lt;key|no-ticket&gt;/&lt;name&gt;" --> S3

S3["Step 3 — Reproduce<br/>spryker-runtime + spryker-docs-research"]
S3 --> S4

S4["Step 4 — Root cause<br/>LOOP RE-ENTRY · attempt++<br/>ai-runtime-debugging + spryker-runtime"]
S4 --> S5["Step 5 — Fix + re-run repro"]
S5 --> S6["Step 6 — Functional tests<br/>codecept-functional"]
S6 --> S7["Step 7 — Static validation<br/>static-validation"]
S7 --> S8{"Step 8 — Code review GATE<br/>code-review"}

S8 -- "blocker/major" --> Budget
S8 -- "clean" --> S9{"Step 9 — QA GATE<br/>spryker-qa-coverage (E2E)"}

S9 -- "rejected" --> Budget
S9 -- "accepted" --> S10{"Step 10 — Final verification<br/>tests + spryker-verifier / spryker-runtime<br/>symptom gone in running app?"}

S10 -- "FAIL" --> Budget
S10 -- "PASS" --> S11{"Step 11 — commit always<br/>MODE + PR_CHANNEL gate"}

Budget{"attempt &gt; 3?"}
Budget -- "no → attempt++" --> S4
Budget -- "yes" --> Report

S11 -- "Collaborative / pre-push review" --> Confirm["Commit → STOP<br/>present for user confirmation"]
S11 -- "Autonomous · PR_CHANNEL=none" --> Local["Commit LOCALLY<br/>skip push/PR/watch<br/>report publish commands"]
S11 -- "Autonomous · PR_CHANNEL=git-only" --> PushOnly["Commit → push branch<br/>skip PR + watch<br/>hand over gh pr create line"]
S11 -- "Autonomous · PR_CHANNEL=gh/mcp" --> Ship["Commit → push →<br/>Draft PR (no labels)"]
Confirm --> Report
Local --> Report
PushOnly --> Report
Ship --> Watch{"Watch loop<br/>gh pr checks ~15m"}

Watch -- "all green" --> Report
Watch -- "red (your code)" --> Budget
Watch -- "flaky/infra" --> Watch

Report(["Step 12 — Final report<br/>ALWAYS LAST, every terminal state<br/>outcome · root cause · decisions · gates · log path"])
```

### The verification loop

Steps 8 (review), 9 (QA), 10 (final verification), and 11 (remote CI) are gates. A failure in any of
them draws from **one shared `attempt` counter** and loops back to **Step 4** to re-investigate, then
forward through the full chain again. The hard stop is `attempt > 3`: the run STOPs and reports —
nothing is pushed and no PR is marked ready with a known-broken state.

## Stage → skill map

| Step | Delegates to |
|------|--------------|
| 0 | `AskUserQuestion`; **optional** ticket pull (Atlassian MCP / `gh issue view` / paste) |
| 3 | `Skill(spryker-runtime)` + `Skill(spryker-docs-research)` |
| 4 | `Skill(ai-runtime-debugging)` + `Skill(spryker-runtime)` |
| 6 | `Skill(codecept-functional)` |
| 7 | `Skill(static-validation)` |
| 8 | `Skill(code-review)` |
| 9 | `Skill(spryker-qa-coverage)` |
| 10 | `Skill(codecept-functional)` re-run + `spryker-verifier` agent / `Skill(spryker-runtime)` |
| 11 | `git` / `gh pr create --draft` / `ScheduleWakeup` or `CronCreate` watch loop |

## Packaging note

This skill ships in the `spryker-ai-dev-sdk` plugin under `vendor/spryker-sdk/ai-dev/…`, which is
Composer-managed — `composer update spryker-sdk/ai-dev` may overwrite it. The durable home for edits is
the plugin's own repository (`github.com/spryker-sdk/ai-dev`).
173 changes: 173 additions & 0 deletions plugins/spryker-ai-dev-sdk/skills/spryker-bugfix/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
---
name: spryker-bugfix
description: >
End-to-end bug-fixing workflow: from an optional tracker ticket (JIRA, GitHub Issues, or any
service) or a plain bug description to a committed,
validated, QA-accepted fix on a bugfix branch (autonomous mode adds a pushed Draft PR +
CI watch). Orchestrates reproduce → root-cause → fix → functional tests → static checks →
review → QA → final verification via the project's stage skills. Trigger — "fix this bug",
"fix ticket XY-1122", "broken, reproduce and fix it": any bug symptom PLUS the expectation of a
DELIVERED fix. NOT for a single isolated step (one test, "just run CI"), new features,
refactors without a symptom, or investigation-only requests ("just find where it goes wrong,
don't fix").
---

# Spryker Bug-Fixing Workflow

This skill drives a bug from intake to a delivered, validated fix. It is an **orchestrator**: each
stage delegates to an existing installed skill. Your job is to run the stages in order, carry context
between them, enforce the verification loop, and respect the operating mode the user picked.

> **Note — the ticket is optional.** The bug can come from a tracker ticket (JIRA, GitHub Issues, or
> any other service) **or** from a plain free-text description with no ticket at all. A ticket is never
> required — it is just one possible source of the bug context. When a ticket exists and the matching
> MCP/CLI is available, the skill pulls it for extra context; otherwise it works entirely from the
> description. Everything downstream (branch name, PR title, commit message) has a `no-ticket` fallback.

> **Note — PR delivery is chosen and capability-gated.** Step 0 asks **whether to open a PR at all and
> via which channel**, then **probes** what's actually available and records `PR_CHANNEL`: `gh` (native
> GitHub CLI — push + Draft PR + CI watch), `mcp` (a connected **forge MCP server** for the remote host
> — GitHub, GitLab, Bitbucket, … — same flow via MCP tools), `git-only` (push a branch but no PR API —
> commit + push, then hand the create-PR command to the user), or `none` (no reachable remote —
> **local-only**: commit and stop). `gh` is **never assumed** — a missing/unauthenticated `gh` is fine
> when an MCP or plain `git` is available. Every push/PR action checks the preference + `PR_CHANNEL`
> first; anything unavailable (or a "no PR" choice) is **skipped with a clear note in the report**, never
> attempted-and-failed. This never aborts the run — it only changes how far Step 11 goes.

> **Note — Claude-only orchestration.** This skill is built to run on **Claude and the skills/agents
> already installed in the project** — nothing else. Every stage delegates to a bundled/installed
> `Skill(...)` or Claude subagent; no third-party MCP server is required for the core flow. The only
> external touchpoint is the **optional** Step 0 ticket pull (e.g. JIRA via the Atlassian MCP); if the
> ticket text is pasted or a free-text description is given, the whole workflow runs without any external
> MCP. Keep every subagent this skill spawns on a Claude model.

The core lessons this workflow enforces: a bug usually has *multiple* candidate paths, the visible
symptom is often downstream of the real cause, and a fix is not "done" until the running app proves
the symptom is gone **and** every gate is green. Build that rigor in regardless of which module,
feature, or layer the bug lives in.

**This file is the workflow spine only.** The full, authoritative instructions live verbatim in two
companion files in this directory:

- [stages.md](stages.md) — complete per-step instructions (Steps 0–12) + the stage→skill quick map.
**Read the relevant § before executing each step below.**
- [reference.md](reference.md) — the run-lean context discipline (`$BUGFIX_DIR`, State Object),
operating principles, the decision & question log, and the red-flags list. **Read it once at the
start of every run, before Step 0.**

## Context discipline (summary)

Heavy work (Chrome, XDebug, codecept, phpcs/phpstan, review, final verification, CI logs) runs in
**subagents** that write raw output to files under `$BUGFIX_DIR`
(`$CLAUDE_PROJECT_DIR/.claude/.cache/spryker-bugfix/<bugfix-id>/`) and return only compact verdicts.
The orchestrator retains only the **State Object**: mode/base/branch/attempt, extra expectations, repro
summary, root-cause `file:line`, diff stat, per-gate verdicts (≤5 actionable items each), and log-file
pointers. Details: [reference.md](reference.md) § Run lean / § The run directory / § The State Object.

## Plan tracking (summary)

At the end of Step 0, **arrange the plan as a task list** with `TaskCreate` — one task per stage
(Steps 1–12) — and drive it with `TaskUpdate` as the run proceeds: mark a stage `in_progress` when you
enter it and `completed` when its gate is green; on a loopback, reopen the affected gate task(s) and add
a fresh attempt task. `TaskList` is the live, at-a-glance checklist a human (or a resumed run) can read
to see where the run stands — it **survives compaction and scheduled wake-ups**, complementing the
append-only `run.log` timeline (the log is the history; the task list is the current state). This is the
same pattern the PRD workflow uses. Details: [stages.md](stages.md) § Step 0 (plan task list) and
[reference.md](reference.md) § Plan task list.

## Principles (summary)

The bug is the contract — the fix is proven only when the user-visible symptom no longer reproduces,
with evidence. Carry context forward between stages; confirm the real executing path before fixing;
never report a stage green that wasn't; honor `.claude/rules/*`. **Autonomous mode never asks after
Step 0** — decide, proceed, and log a CRITICAL DECISION in `$BUGFIX_DIR/decisions.md`; the only
Autonomous stops are the stale/dirty base (Step 2) and `attempt > 3`. Maintain the append-only
decision & question log from Step 0 onward. Details: [reference.md](reference.md) § Operating
principles and § The decision & question log.

## Workflow spine

**Step 0 — Choose mode and gather context (ALWAYS FIRST).** One multi-tab `AskUserQuestion`: mode
(Autonomous vs Collaborative), the bug context (an **optional** ticket from any tracker **and/or** a
free-text description), base branch, env freshness, pre-push personal review, **PR delivery** (create a
PR or not, and via which channel — auto / `gh` / a named forge MCP / push-only), and extra expectations
beyond the default scope. Then create `$BUGFIX_DIR` + `run.log` step logger, **probe `PR_CHANNEL`**,
handle the env-reset decision, and — only if a ticket was given and its tracker is reachable — pull the
ticket for extra context. Read [stages.md](stages.md) § Step 0 before executing this stage.

**Step 1 — Intake & framing.** Turn the context into a crisp problem statement: verbatim symptom,
affected actor/surface, environment, provisional module/layer scope. Keep it short — it aligns
later stages and subagents. Read [stages.md](stages.md) § Step 1 before executing this stage.

**Step 2 — Create the bugfix branch. ← SAFETY GATE.** Verify a clean tree and an up-to-date base
first; if dirty/stale, ask (Collaborative) or abort with a report (Autonomous). Branch
`bugfix/<jira-key>/<brief-kebab-name>` (lowercase; `no-ticket` fallback), then finalize
`$BUGFIX_DIR`. Read [stages.md](stages.md) § Step 2 before executing this stage.

**Step 3 — Reproduce & understand the bug.** Ensure the env is actually running, then delegate
reproduction to a subagent using `Skill(spryker-runtime)` (writes `$BUGFIX_DIR/repro-notes.md`,
returns a summary) and, in parallel, `Skill(spryker-docs-research)` for expected behavior. A bug you
couldn't reproduce is a hypothesis. Read [stages.md](stages.md) § Step 3 before executing this stage.

**Step 4 — Root-cause investigation. ← LOOP RE-ENTRY POINT.** The shared `attempt` counter is
defined here (starts at 1; +1 on every loopback from Steps 8/9/11; **hard stop when `attempt > 3`**).
Delegate runtime tracing to a subagent (`Skill(ai-runtime-debugging)` + `Skill(spryker-runtime)`)
that returns the confirmed executing path `file:line` + decisive values. When several candidates
survive in Autonomous mode, pick the evidence-backed one and log a CRITICAL DECISION.
Read [stages.md](stages.md) § Step 4 before executing this stage.

**Step 5 — Implement the fix & verify it resolves the bug.** Smallest correct change at the root
cause; parallel subagents for independent multi-file edits. **Mandatory:** re-run the Step 3 repro
and confirm the symptom is gone with the same evidence. Read [stages.md](stages.md) § Step 5 before
executing this stage.

**Step 6 — Functional test coverage (subagent).** One subagent with `Skill(codecept-functional)`:
enter testing mode first, add/update a regression test (ideally fails without the fix, passes with
it), write the run log to `$BUGFIX_DIR`, return only the pass/fail verdict + test paths. Confirm
green before moving on. Read [stages.md](stages.md) § Step 6 before executing this stage.

**Step 7 — Static validation (subagent).** Subagent runs `Skill(static-validation)`
(phpcbf/phpcs/phpstan on the diff), fixes and re-runs until clean, returns `clean` or the
remaining violations. Read [stages.md](stages.md) § Step 7 before executing this stage.

**Step 8 — Code review. ← GATE (loops back to Step 4).** Run `Skill(code-review)` (keep
only ≤5 blocker/major items); fix findings, then re-run static checks (and tests if behavior was
touched). Only blocker/major findings gate — **nits never loop**. Clean → Step 9; failing →
`attempt`+1 and return to Step 4 through 5→6→7→8; `attempt > 3` → **STOP and report** (no push, no
PR). Read [stages.md](stages.md) § Step 8 before executing this stage.

**Step 9 — QA acceptance (independent). ← GATE.** `Skill(spryker-qa-coverage)` in an isolated
subagent, handed the full session context (changed files, repro scenarios, env gotchas, regen
commands already run, ticket/description). QA must confirm the symptom is gone **E2E**. Accepted → continue;
rejected → treat as a Step 8 failure (loop to Step 4 within the budget).
Read [stages.md](stages.md) § Step 9 before executing this stage.

**Step 10 — Final verification before commit.** Re-run the affected functional tests (subagent),
then perform an **end-to-end final verification of the fix in the running app** (subagent — the
`spryker-verifier` agent, or `Skill(spryker-runtime)`) as the last gate before commit/push: confirm
the user-visible symptom is gone with fresh evidence. Returns a PASS/FAIL verdict + evidence; a FAIL
is treated as a Step 8 failure (loop to Step 4 within the budget).
Read [stages.md](stages.md) § Step 10 before executing this stage.

**Step 11 — Commit, push, Draft PR, watch loop. ← MODE GATE + PR-CHANNEL GATE.** Always commit on the
branch first. Then act by mode **and** by the `PR_CHANNEL` probed at Step 0. Collaborative (or pre-push
review requested): commit, then **STOP and present** for user confirmation — never push without it.
Autonomous: push and open a **Draft PR** *only if `PR_CHANNEL=gh`* (title `<TICKET-KEY>: <summary>`,
**no labels**), write `$BUGFIX_DIR/watch-state.md`, and arm a ~15-min watch loop
that re-hydrates from that file and polls `gh pr checks` — red check → subagent pulls the failed logs,
`attempt`+1, return to Step 4 through the **full** gate chain before re-pushing; `attempt > 3` → STOP,
cancel the loop, leave the PR in Draft, comment and report. If `PR_CHANNEL=git-only`, push the branch
and **skip** the PR + watch loop, handing the user a ready-to-run `gh pr create` line and the branch
name. If `PR_CHANNEL=none`, **skip push, PR, and watch entirely** — leave the committed branch local and
tell the user how to push it themselves. Read [stages.md](stages.md) § Step 11 before executing this stage.

**Step 12 — Final report (ALWAYS LAST, every terminal state).** Outcome, bug + root cause,
CRITICAL DECISIONS (headline section), OPEN QUESTIONS/RISKS, per-gate status (honest), extra
expectations handled, and — always the last line — the absolute path to the step log and decision
log. Read [stages.md](stages.md) § Step 12 before executing this stage.

## Quick map & red flags

The stage → skill quick-map table lives in [stages.md](stages.md) § Stage → skill quick map.
Before deviating from any gate, shortcut, or budget above, read
[reference.md](reference.md) § Red flags — stop and reconsider.
Loading
Loading