|
| 1 | +--- |
| 2 | +name: fix-bug |
| 3 | +description: "End-to-end bug fix workflow for the Ktor project. Accepts a GitHub issue (#NUMBER), YouTrack issue (KTOR-NUMBER), or YouTrack URL (https://youtrack.jetbrains.com/issue/KTOR-NUMBER). Fetches the issue, creates a failing reproducer test, commits on a new branch, implements the fix, validates, and opens a PR. Use this skill whenever the user wants to fix a bug from an issue tracker, mentions a KTOR issue number, or references a GitHub issue to fix." |
| 4 | +user_invocable: true |
| 5 | +--- |
| 6 | + |
| 7 | +# Fix Bug Skill |
| 8 | + |
| 9 | +Automates the full bug-fix lifecycle for the Ktor project: understand issue, reproduce, fix, validate, and open a PR. |
| 10 | + |
| 11 | +## Input Parsing |
| 12 | + |
| 13 | +The user provides one of: |
| 14 | +- `#123` — GitHub issue in `ktorio/ktor` |
| 15 | +- `KTOR-9352` — YouTrack issue ID |
| 16 | +- `https://youtrack.jetbrains.com/issue/KTOR-9352` or `https://youtrack.jetbrains.com/issue/KTOR-9352/some-slug` — YouTrack URL |
| 17 | + |
| 18 | +Parse the input to determine the source: |
| 19 | + |
| 20 | +1. **GitHub**: Extract the number, fetch via `gh issue view NUMBER --repo ktorio/ktor` |
| 21 | +2. **YouTrack ID** (pattern `KTOR-\d+`): Fetch via the YouTrack MCP (see below) |
| 22 | +3. **YouTrack URL**: Extract the `KTOR-XXXX` ID from the URL, then fetch via the YouTrack MCP (see below) |
| 23 | + |
| 24 | +### Fetching YouTrack Issues |
| 25 | + |
| 26 | +Use the YouTrack MCP tools to fetch issue details. Call `mcp__youtrack__get_issue` with the issue ID (e.g., `KTOR-9352`). |
| 27 | + |
| 28 | +If the YouTrack MCP server is not configured (tool calls fail), instruct the user to set it up: |
| 29 | + |
| 30 | +```bash |
| 31 | +claude mcp add --header "Authorization: Bearer <token>" --transport http youtrack https://youtrack.jetbrains.com/mcp |
| 32 | +``` |
| 33 | + |
| 34 | +The permanent token can be created in JetBrains Hub account security settings (linked from YouTrack profile). |
| 35 | + |
| 36 | +From the issue, extract: |
| 37 | +- **Title and description** of the bug |
| 38 | +- **Steps to reproduce** (if provided) |
| 39 | +- **Expected vs actual behavior** |
| 40 | +- **Affected module(s)** — identify which Ktor Gradle module is relevant |
| 41 | +- **Issue comments** — read through comments as they might contain useful information (reproduction details, workarounds, related context) |
| 42 | +- **Issue ID** for branch naming and commit messages (e.g., `KTOR-9352` or `#123`) |
| 43 | + |
| 44 | +## Step 1: Assign Issue and Set In Progress |
| 45 | + |
| 46 | +For **YouTrack issues only**, update the issue status to reflect that work is starting: |
| 47 | + |
| 48 | +1. Call `mcp__youtrack__get_current_user` to get the current user's login. |
| 49 | +2. Call `mcp__youtrack__change_issue_assignee` to assign the issue to the current user. |
| 50 | +3. Call `mcp__youtrack__update_issue` with `customFields: {"State": "In Progress"}` to mark work as started. |
| 51 | + |
| 52 | +If any of these calls fail because the YouTrack MCP is not configured, inform the user how to set it up (see "Fetching YouTrack Issues" section above) and continue with the rest of the workflow — issue tracking updates are not blocking. |
| 53 | + |
| 54 | +Skip this step for GitHub-only issues. |
| 55 | + |
| 56 | +## Step 2: Understand the Codebase Context |
| 57 | + |
| 58 | +Before creating a branch, understand the affected area: |
| 59 | +- Identify the Gradle module from the issue description or affected APIs |
| 60 | +- Read existing tests in that module to understand test patterns and conventions |
| 61 | +- Identify whether this needs a unit test or integration test based on the bug nature |
| 62 | +- Remember: this project uses a **flattened Gradle structure** (e.g., `ktor-client/ktor-client-curl` → `:ktor-client-curl`) |
| 63 | + |
| 64 | +Use the Explore agent or direct file reads to understand: |
| 65 | +- The relevant source code where the bug likely lives |
| 66 | +- Existing test infrastructure (test utilities, base classes, server setup patterns) |
| 67 | +- How similar tests are structured in the same module |
| 68 | + |
| 69 | +## Step 3: Create branch |
| 70 | + |
| 71 | +Determine the base branch: |
| 72 | +- Use `release/3.x` for bug fixes that do **not** introduce new public APIs (patch release) |
| 73 | +- Use `main` for fixes that require new public APIs or are targeted at the next minor release |
| 74 | + |
| 75 | +```bash |
| 76 | +git checkout <base-branch> && git pull && git checkout -b claude/<issue-id>-<short-description> |
| 77 | +``` |
| 78 | + |
| 79 | +Branch naming rules: |
| 80 | +- For YouTrack issues: `claude/KTOR-9352-short-description` |
| 81 | +- For GitHub issues: `claude/123-short-description` |
| 82 | +- The short description is 3 words max, lowercase, hyphenated, derived from the issue title |
| 83 | + |
| 84 | +## Step 4: Write a Failing Reproducer Test |
| 85 | + |
| 86 | +Write a test that demonstrates the bug as described in the issue. The goal is: |
| 87 | +- **Minimal**: Only test the specific buggy behavior, nothing extra |
| 88 | +- **Clear**: Test name in backticks should describe the bug (e.g., `` `KTOR-9352 request with empty body causes NPE` ``) |
| 89 | +- **Failing**: The test MUST fail on the current codebase to confirm the bug exists |
| 90 | + |
| 91 | +Place the test appropriately: |
| 92 | +- Near existing tests for the same module/feature |
| 93 | +- If no test suite exists for this area, create a new test class following the module's conventions |
| 94 | +- For integration tests, place near other integration tests in the module |
| 95 | +- For unit tests, place near other unit tests |
| 96 | +- If the bug is platform-specific, place the test in the corresponding platform source set (e.g., `jvm/test`, `posix/test`) |
| 97 | +- If the bug affects common/shared code, place the test in `common/test` so it runs on all platforms |
| 98 | + |
| 99 | +After writing the test, run it to confirm it fails: |
| 100 | +```bash |
| 101 | +./gradlew :module-name:jvmTest --tests "fully.qualified.TestClassName.methodName" |
| 102 | +``` |
| 103 | + |
| 104 | +If the test is in `common/test` or touches multiplatform code, also run on other affected platforms: |
| 105 | +```bash |
| 106 | +./gradlew :module-name:allTests |
| 107 | +``` |
| 108 | + |
| 109 | +If the test passes (bug is already fixed or test doesn't reproduce correctly): |
| 110 | +- Re-read the issue carefully |
| 111 | +- Adjust the test to more precisely match the reported scenario |
| 112 | +- If the bug truly cannot be reproduced, inform the user and stop |
| 113 | + |
| 114 | +## Step 5: Commit the Reproducer |
| 115 | + |
| 116 | +Stage and commit the failing test: |
| 117 | +```bash |
| 118 | +git add <test-file> |
| 119 | +git commit -m "<ISSUE-ID> Add failing test for <short bug description> |
| 120 | +
|
| 121 | +Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>" |
| 122 | +``` |
| 123 | + |
| 124 | +For GitHub issues, use `#NUMBER` in the commit message. For YouTrack, use `KTOR-XXXX`. |
| 125 | + |
| 126 | +## Step 6: Plan and Implement the Fix |
| 127 | + |
| 128 | +Analyze the bug based on what you learned from the issue and the reproducer test: |
| 129 | +- Trace the code path that leads to the failure |
| 130 | +- Identify the root cause |
| 131 | +- Plan the minimal fix |
| 132 | + |
| 133 | +Implement the fix directly — do not present the plan to the user for approval. Keep changes minimal and focused: |
| 134 | +- Fix only the bug, do not refactor surrounding code |
| 135 | +- Do not add features beyond what's needed |
| 136 | +- Preserve existing comments and code style |
| 137 | + |
| 138 | +## Step 7: Validate the Fix |
| 139 | + |
| 140 | +Run the reproducer test to confirm it passes: |
| 141 | +```bash |
| 142 | +./gradlew :module-name:jvmTest --tests "fully.qualified.TestClassName.methodName" |
| 143 | +``` |
| 144 | + |
| 145 | +Then run the full test suite for the affected module. Choose the scope based on where the changes are: |
| 146 | + |
| 147 | +- **JVM-only changes** (test and fix both in `jvm/`): |
| 148 | + ```bash |
| 149 | + ./gradlew :module-name:jvmTest |
| 150 | + ``` |
| 151 | +- **Common/multiplatform changes** (test or fix in `common/`, or the bug affects multiple platforms): |
| 152 | + ```bash |
| 153 | + ./gradlew :module-name:allTests |
| 154 | + ``` |
| 155 | + |
| 156 | +If any tests fail, investigate and fix. Do not skip or disable tests. |
| 157 | + |
| 158 | +## Step 8: Format and Lint |
| 159 | + |
| 160 | +```bash |
| 161 | +./gradlew :module-name:formatKotlin :module-name:lintKotlin |
| 162 | +``` |
| 163 | + |
| 164 | +Fix any lint issues before proceeding. |
| 165 | + |
| 166 | +## Step 9: ABI Validation |
| 167 | + |
| 168 | +If the fix changed any `public` or `protected` API (new methods, changed signatures, etc.): |
| 169 | +```bash |
| 170 | +./gradlew :module-name:checkLegacyAbi |
| 171 | +``` |
| 172 | + |
| 173 | +If it fails, update the ABI dumps: |
| 174 | +```bash |
| 175 | +./gradlew :module-name:updateLegacyAbi |
| 176 | +``` |
| 177 | + |
| 178 | +Stage the updated `.api` files along with the fix. |
| 179 | + |
| 180 | +If no public API changed, skip this step. |
| 181 | + |
| 182 | +## Step 10: Commit the Fix |
| 183 | + |
| 184 | +```bash |
| 185 | +git add <changed-files> |
| 186 | +git commit -m "<ISSUE-ID> <Imperative description of the fix> |
| 187 | +
|
| 188 | +Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>" |
| 189 | +``` |
| 190 | + |
| 191 | +## Step 11: Push and Create PR |
| 192 | + |
| 193 | +Push the branch and create a PR: |
| 194 | + |
| 195 | +```bash |
| 196 | +git push -u origin claude/<issue-id>-<short-description> |
| 197 | +``` |
| 198 | + |
| 199 | +Create the PR targeting the base branch chosen in Step 3 (`main` or `release/3.x`): |
| 200 | +```bash |
| 201 | +gh pr create --title "<ISSUE-ID> <Short fix description>" --body "$(cat <<'EOF' |
| 202 | +## Summary |
| 203 | +- Fixes <link-to-issue> |
| 204 | +- <1-2 bullet points describing the root cause and fix> |
| 205 | +
|
| 206 | +Closes <issue-reference> |
| 207 | +
|
| 208 | +## Test plan |
| 209 | +- Added failing reproducer test that validates the fix |
| 210 | +- All existing tests in the module continue to pass |
| 211 | +
|
| 212 | +🤖 Generated with [Claude Code](https://claude.com/claude-code) |
| 213 | +EOF |
| 214 | +)" |
| 215 | +``` |
| 216 | + |
| 217 | +The `Closes` line auto-closes the issue when the PR is merged **for GitHub issues only**: |
| 218 | +- For GitHub issues: `Closes #NUMBER` |
| 219 | +- For YouTrack issues: include `KTOR-XXXX` as a plain cross-reference (GitHub will not close YouTrack tickets automatically) |
| 220 | + |
| 221 | +Report the PR URL to the user when done. |
| 222 | + |
| 223 | +After the PR is created, for **YouTrack issues only**, update the issue state: |
| 224 | + |
| 225 | +Call `mcp__youtrack__update_issue` with `customFields: {"State": "Ready for Review"}` to signal the fix is ready for code review. |
| 226 | + |
| 227 | +If the YT MCP call fails, skip silently — the status update is not blocking. |
| 228 | + |
| 229 | +## Step 12: Documentation Issue (if needed) |
| 230 | + |
| 231 | +Assess whether the fix changes behavior that users rely on or that is described in the Ktor documentation. A documentation update is needed when: |
| 232 | +- A public API signature changed (new parameter, changed default, new overload) |
| 233 | +- Behavior that users observe changed (different error message, different default, different timing) |
| 234 | +- A workaround that users might have adopted is no longer necessary |
| 235 | +- A new feature or configuration option was added as part of the fix |
| 236 | + |
| 237 | +If none of the above apply (e.g., an internal-only fix, a crash fix with no API change), skip this step. |
| 238 | + |
| 239 | +When documentation is needed, create a GitHub issue in the `ktorio/ktor-documentation` repository: |
| 240 | + |
| 241 | +````bash |
| 242 | +gh issue create --repo ktorio/ktor-documentation \ |
| 243 | + --title "Document behavior change: <ISSUE-ID> <short description>" \ |
| 244 | + --body "$(cat <<'EOF' |
| 245 | +## Context |
| 246 | +
|
| 247 | +PR: <link-to-the-PR-created-in-step-11> |
| 248 | +Issue: <link-to-the-original-issue> |
| 249 | +
|
| 250 | +## What changed |
| 251 | +
|
| 252 | +<1-3 sentences explaining what behavior changed and why> |
| 253 | +
|
| 254 | +## What should be documented |
| 255 | +
|
| 256 | +<Describe specifically what a technical writer should add or update in the docs. |
| 257 | +Include the affected API, module, and any relevant configuration options.> |
| 258 | +
|
| 259 | +## Suggested code snippet |
| 260 | +
|
| 261 | +```kotlin |
| 262 | +// Include a short usage example if relevant, showing the correct new usage |
| 263 | +``` |
| 264 | +
|
| 265 | +🤖 Generated with [Claude Code](https://claude.com/claude-code) |
| 266 | +EOF |
| 267 | +)" |
| 268 | +```` |
| 269 | + |
| 270 | +Report the documentation issue URL to the user alongside the PR URL. |
0 commit comments