@olegkoval/agent-skills 1.19.0 → 1.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/.claude-plugin/plugin.json +3 -2
  2. package/.cursor-plugin/index.json +5 -0
  3. package/.grok-plugin/index.json +5 -0
  4. package/.kiro/steering/garmin-watchface.md +201 -0
  5. package/.kiro/steering/qodoloop.md +13 -1
  6. package/.windsurf/rules/garmin-watchface.md +200 -0
  7. package/.windsurf/rules/qodoloop.md +13 -1
  8. package/README.md +7 -1
  9. package/catalog/skills.json +28 -4
  10. package/collections/wearables.json +7 -0
  11. package/package.json +1 -1
  12. package/packages/marketing/viral-launch/adapters/claude/skills/viral-launch/references/external-skills.md +12 -0
  13. package/packages/marketing/viral-launch/adapters/claude/skills/viral-launch/references/launch-checklist.md +42 -0
  14. package/packages/marketing/viral-launch/adapters/cursor/skills/viral-launch/references/external-skills.md +12 -0
  15. package/packages/marketing/viral-launch/adapters/cursor/skills/viral-launch/references/launch-checklist.md +42 -0
  16. package/packages/marketing/viral-launch/adapters/grok/skills/viral-launch/references/external-skills.md +12 -0
  17. package/packages/marketing/viral-launch/adapters/grok/skills/viral-launch/references/launch-checklist.md +42 -0
  18. package/packages/software-development/qodoloop/SKILL.md +13 -1
  19. package/packages/software-development/qodoloop/adapters/claude/skills/qodoloop/SKILL.md +13 -1
  20. package/packages/software-development/qodoloop/adapters/claude/skills/qodoloop/references/graphql-queries.md +151 -0
  21. package/packages/software-development/qodoloop/adapters/cursor/skills/qodoloop/SKILL.md +13 -1
  22. package/packages/software-development/qodoloop/adapters/cursor/skills/qodoloop/references/graphql-queries.md +151 -0
  23. package/packages/software-development/qodoloop/adapters/grok/skills/qodoloop/SKILL.md +13 -1
  24. package/packages/software-development/qodoloop/adapters/grok/skills/qodoloop/references/graphql-queries.md +151 -0
  25. package/packages/software-development/qodoloop/adapters/kiro/steering/qodoloop.md +13 -1
  26. package/packages/software-development/qodoloop/adapters/windsurf/rules/qodoloop.md +13 -1
  27. package/packages/software-development/semantic-release-beta/adapters/claude/skills/semantic-release-beta/references/github-actions.md +16 -0
  28. package/packages/software-development/semantic-release-beta/adapters/claude/skills/semantic-release-beta/references/node-semantic-release.md +13 -0
  29. package/packages/software-development/semantic-release-beta/adapters/claude/skills/semantic-release-beta/references/preset.md +47 -0
  30. package/packages/software-development/semantic-release-beta/adapters/claude/skills/semantic-release-beta/references/validation.md +17 -0
  31. package/packages/software-development/semantic-release-beta/adapters/cursor/skills/semantic-release-beta/references/github-actions.md +16 -0
  32. package/packages/software-development/semantic-release-beta/adapters/cursor/skills/semantic-release-beta/references/node-semantic-release.md +13 -0
  33. package/packages/software-development/semantic-release-beta/adapters/cursor/skills/semantic-release-beta/references/preset.md +47 -0
  34. package/packages/software-development/semantic-release-beta/adapters/cursor/skills/semantic-release-beta/references/validation.md +17 -0
  35. package/packages/software-development/semantic-release-beta/adapters/grok/skills/semantic-release-beta/references/github-actions.md +16 -0
  36. package/packages/software-development/semantic-release-beta/adapters/grok/skills/semantic-release-beta/references/node-semantic-release.md +13 -0
  37. package/packages/software-development/semantic-release-beta/adapters/grok/skills/semantic-release-beta/references/preset.md +47 -0
  38. package/packages/software-development/semantic-release-beta/adapters/grok/skills/semantic-release-beta/references/validation.md +17 -0
  39. package/packages/wearables/garmin-watchface/SKILL.md +204 -0
  40. package/packages/wearables/garmin-watchface/adapters/claude/plugin.json +5 -0
  41. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/SKILL.md +205 -0
  42. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/references/devices.md +98 -0
  43. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/references/display.md +120 -0
  44. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/references/layout.md +224 -0
  45. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/references/simulator.md +146 -0
  46. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/references/store.md +151 -0
  47. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/references/testing.md +154 -0
  48. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/scripts/ciq-calibrate +184 -0
  49. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/scripts/ciq-capture +215 -0
  50. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/scripts/ciq-devices +177 -0
  51. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/scripts/ciq-doctor +85 -0
  52. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/templates/Makefile +72 -0
  53. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/templates/monkey.jungle +13 -0
  54. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/templates/monkey.test.jungle +7 -0
  55. package/packages/wearables/garmin-watchface/adapters/codex/README.md +3 -0
  56. package/packages/wearables/garmin-watchface/adapters/cursor/plugin.json +6 -0
  57. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/SKILL.md +205 -0
  58. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/references/devices.md +98 -0
  59. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/references/display.md +120 -0
  60. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/references/layout.md +224 -0
  61. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/references/simulator.md +146 -0
  62. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/references/store.md +151 -0
  63. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/references/testing.md +154 -0
  64. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/scripts/ciq-calibrate +184 -0
  65. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/scripts/ciq-capture +215 -0
  66. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/scripts/ciq-devices +177 -0
  67. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/scripts/ciq-doctor +85 -0
  68. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/templates/Makefile +72 -0
  69. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/templates/monkey.jungle +13 -0
  70. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/templates/monkey.test.jungle +7 -0
  71. package/packages/wearables/garmin-watchface/adapters/grok/plugin.json +6 -0
  72. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/SKILL.md +205 -0
  73. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/references/devices.md +98 -0
  74. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/references/display.md +120 -0
  75. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/references/layout.md +224 -0
  76. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/references/simulator.md +146 -0
  77. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/references/store.md +151 -0
  78. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/references/testing.md +154 -0
  79. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/scripts/ciq-calibrate +184 -0
  80. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/scripts/ciq-capture +215 -0
  81. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/scripts/ciq-devices +177 -0
  82. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/scripts/ciq-doctor +85 -0
  83. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/templates/Makefile +72 -0
  84. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/templates/monkey.jungle +13 -0
  85. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/templates/monkey.test.jungle +7 -0
  86. package/packages/wearables/garmin-watchface/adapters/kiro/steering/garmin-watchface.md +201 -0
  87. package/packages/wearables/garmin-watchface/adapters/windsurf/rules/garmin-watchface.md +200 -0
  88. package/packages/wearables/garmin-watchface/references/devices.md +98 -0
  89. package/packages/wearables/garmin-watchface/references/display.md +120 -0
  90. package/packages/wearables/garmin-watchface/references/layout.md +224 -0
  91. package/packages/wearables/garmin-watchface/references/simulator.md +146 -0
  92. package/packages/wearables/garmin-watchface/references/store.md +151 -0
  93. package/packages/wearables/garmin-watchface/references/testing.md +154 -0
  94. package/packages/wearables/garmin-watchface/scripts/ciq-calibrate +184 -0
  95. package/packages/wearables/garmin-watchface/scripts/ciq-capture +215 -0
  96. package/packages/wearables/garmin-watchface/scripts/ciq-devices +177 -0
  97. package/packages/wearables/garmin-watchface/scripts/ciq-doctor +85 -0
  98. package/packages/wearables/garmin-watchface/templates/Makefile +72 -0
  99. package/packages/wearables/garmin-watchface/templates/monkey.jungle +13 -0
  100. package/packages/wearables/garmin-watchface/templates/monkey.test.jungle +7 -0
  101. package/scripts/build-adapters.sh +1 -1
  102. package/scripts/validate-catalog.sh +2 -1
@@ -0,0 +1,42 @@
1
+ # Launch checklist
2
+
3
+ Use this checklist before calling a project launch-ready.
4
+
5
+ ## Repo
6
+
7
+ - README headline says what the project does and for whom.
8
+ - First screen contains a demo, screenshot, or quickstart.
9
+ - Install steps work from a clean checkout.
10
+ - Examples cover the highest-intent use cases.
11
+ - License and contribution expectations are clear.
12
+ - Known limitations are stated without weakening the launch angle.
13
+
14
+ ## Message
15
+
16
+ - One-sentence positioning is specific.
17
+ - The hook names a real problem or desire.
18
+ - Differentiation is concrete.
19
+ - Claims are backed by repo content, screenshots, demos, benchmarks, or examples.
20
+ - Copy avoids fake urgency, fake social proof, and generic hype.
21
+
22
+ ## Distribution
23
+
24
+ - Launch channels are chosen for the actual audience.
25
+ - Each channel gets native copy, not pasted generic copy.
26
+ - Assets include at least one short post, one longer post, and one direct outreach note.
27
+ - Launch timing includes a response window for comments, issues, and feedback.
28
+
29
+ ## Shareability
30
+
31
+ - There is a public artifact people can link to.
32
+ - The demo shows a before/after or clear transformation.
33
+ - Users have a reason to share the output, not only the product.
34
+ - Any referral or waitlist mechanism is tied to user value.
35
+
36
+ ## Metrics
37
+
38
+ - Activation event is defined.
39
+ - Share event is defined.
40
+ - Conversion event is defined.
41
+ - Feedback collection path is defined.
42
+ - Launch review date is defined before launch.
@@ -0,0 +1,12 @@
1
+ # External skills
2
+
3
+ Skill search found these related launch and marketing skills:
4
+
5
+ - `coreyhaines31/marketingskills@launch-strategy` - broad launch strategy skill, about 37K installs in Skills CLI search; source repo `coreyhaines31/marketingskills` has about 20K GitHub stars.
6
+ - `refoundai/lenny-skills@launch-marketing` - product management and launch marketing skill, under 1K installs in Skills CLI search.
7
+
8
+ Prefer this local `olko:viral-launch` skill when the work is specifically to make a repository launch-ready. Consider installing `coreyhaines31/marketingskills@launch-strategy` when the user wants a broader marketing strategy workflow:
9
+
10
+ ```bash
11
+ npx skills add coreyhaines31/marketingskills@launch-strategy -g -y
12
+ ```
@@ -0,0 +1,42 @@
1
+ # Launch checklist
2
+
3
+ Use this checklist before calling a project launch-ready.
4
+
5
+ ## Repo
6
+
7
+ - README headline says what the project does and for whom.
8
+ - First screen contains a demo, screenshot, or quickstart.
9
+ - Install steps work from a clean checkout.
10
+ - Examples cover the highest-intent use cases.
11
+ - License and contribution expectations are clear.
12
+ - Known limitations are stated without weakening the launch angle.
13
+
14
+ ## Message
15
+
16
+ - One-sentence positioning is specific.
17
+ - The hook names a real problem or desire.
18
+ - Differentiation is concrete.
19
+ - Claims are backed by repo content, screenshots, demos, benchmarks, or examples.
20
+ - Copy avoids fake urgency, fake social proof, and generic hype.
21
+
22
+ ## Distribution
23
+
24
+ - Launch channels are chosen for the actual audience.
25
+ - Each channel gets native copy, not pasted generic copy.
26
+ - Assets include at least one short post, one longer post, and one direct outreach note.
27
+ - Launch timing includes a response window for comments, issues, and feedback.
28
+
29
+ ## Shareability
30
+
31
+ - There is a public artifact people can link to.
32
+ - The demo shows a before/after or clear transformation.
33
+ - Users have a reason to share the output, not only the product.
34
+ - Any referral or waitlist mechanism is tied to user value.
35
+
36
+ ## Metrics
37
+
38
+ - Activation event is defined.
39
+ - Share event is defined.
40
+ - Conversion event is defined.
41
+ - Feedback collection path is defined.
42
+ - Launch review date is defined before launch.
@@ -42,7 +42,19 @@ Qodo has **no check run to poll** — there is nothing in `gh pr checks` to wait
42
42
  gh pr view --json number,headRefName,headRefOid -q '{number, branch: .headRefName, sha: .headRefOid}'
43
43
  ```
44
44
 
45
- Check out the branch if not already on it.
45
+ Check out the branch if not already on it, **then require a clean working
46
+ tree** (`git status --porcelain` empty) before touching anything:
47
+
48
+ ```bash
49
+ [ -z "$(git status --porcelain)" ] || { echo "working tree not clean — refusing to start, would risk committing unrelated changes"; exit 1; }
50
+ ```
51
+
52
+ This is the precondition step E's scoped `git add <file>` depends on: staging
53
+ only the files a fix touched is safe *because* the tree started clean, so
54
+ nothing else could be sitting in those files. Skip this check and a file
55
+ with pre-existing local edits will have those edits swept into the fix
56
+ commit right along with it — the exact failure `git add -A` had, just
57
+ narrower.
46
58
 
47
59
  ### 2. Loop (max 5 iterations)
48
60
 
@@ -43,7 +43,19 @@ Qodo has **no check run to poll** — there is nothing in `gh pr checks` to wait
43
43
  gh pr view --json number,headRefName,headRefOid -q '{number, branch: .headRefName, sha: .headRefOid}'
44
44
  ```
45
45
 
46
- Check out the branch if not already on it.
46
+ Check out the branch if not already on it, **then require a clean working
47
+ tree** (`git status --porcelain` empty) before touching anything:
48
+
49
+ ```bash
50
+ [ -z "$(git status --porcelain)" ] || { echo "working tree not clean — refusing to start, would risk committing unrelated changes"; exit 1; }
51
+ ```
52
+
53
+ This is the precondition step E's scoped `git add <file>` depends on: staging
54
+ only the files a fix touched is safe *because* the tree started clean, so
55
+ nothing else could be sitting in those files. Skip this check and a file
56
+ with pre-existing local edits will have those edits swept into the fix
57
+ commit right along with it — the exact failure `git add -A` had, just
58
+ narrower.
47
59
 
48
60
  ### 2. Loop (max 5 iterations)
49
61
 
@@ -0,0 +1,151 @@
1
+ # GraphQL queries reference
2
+
3
+ Field names verified by introspection against GitHub's live GraphQL schema
4
+ (`AddPullRequestReviewThreadReplyInput`) and against a real Qodo install's
5
+ comment output — not guessed.
6
+
7
+ **The bot's login string is spelled differently in REST vs GraphQL.** REST
8
+ (`.user.login` on `issues/.../comments`) returns `qodo-code-review[bot]`.
9
+ GraphQL (`author.login` on `reviewThreads`) returns `qodo-code-review` — no
10
+ `[bot]` suffix — confirmed live against a real PR with real Qodo inline
11
+ threads. Using the REST spelling in a GraphQL filter silently matches
12
+ nothing, which reads as "no findings" instead of "wrong filter" — exactly the
13
+ kind of bug that has no crash and no error to notice. Use `[bot]` only in
14
+ REST-based jq filters (`.user.login`); use the bare name everywhere you're
15
+ filtering a GraphQL `author.login`.
16
+
17
+ ## Fetch unresolved Qodo threads (paginated)
18
+
19
+ ```graphql
20
+ query($cursor: String) {
21
+ repository(owner: "OWNER", name: "REPO") {
22
+ pullRequest(number: PR_NUMBER) {
23
+ reviewThreads(first: 100, after: $cursor) {
24
+ pageInfo { hasNextPage endCursor }
25
+ nodes {
26
+ id
27
+ isResolved
28
+ comments(first: 1) {
29
+ nodes { body path line author { login } }
30
+ }
31
+ }
32
+ }
33
+ }
34
+ }
35
+ }
36
+ ```
37
+
38
+ Filter client-side to `qodo-code-review` (GraphQL spelling — see the note
39
+ above) and `isResolved == false` — the author isn't filterable server-side in
40
+ this shape. **Follow `pageInfo.hasNextPage`/`endCursor` until it's exhausted**;
41
+ stopping after the first page silently drops every thread past the 100th on a
42
+ PR with a lot of findings:
43
+
44
+ A page fetch can occasionally come back malformed (a transient API hiccup,
45
+ not anything specific to this query — reproduced live, then failed to
46
+ reproduce on an identical immediate retry). Retry once per page before
47
+ giving up rather than letting the whole loop crash on it:
48
+
49
+ ```bash
50
+ CURSOR=null
51
+ ALL_THREADS='[]'
52
+ while :; do
53
+ for attempt in 1 2; do
54
+ PAGE=$(gh api graphql -f query='
55
+ query($cursor: String) {
56
+ repository(owner: "OWNER", name: "REPO") {
57
+ pullRequest(number: PR_NUMBER) {
58
+ reviewThreads(first: 100, after: $cursor) {
59
+ pageInfo { hasNextPage endCursor }
60
+ nodes {
61
+ id
62
+ isResolved
63
+ comments(first: 1) { nodes { body path line author { login } } }
64
+ }
65
+ }
66
+ }
67
+ }
68
+ }' -f cursor="$CURSOR")
69
+ jq -e . >/dev/null 2>&1 <<< "$PAGE" && break
70
+ [ "$attempt" = "2" ] && { echo "page fetch failed twice, aborting" >&2; exit 1; }
71
+ done
72
+
73
+ ALL_THREADS=$(jq -c --argjson acc "$ALL_THREADS" \
74
+ '$acc + .data.repository.pullRequest.reviewThreads.nodes' <<< "$PAGE")
75
+
76
+ HAS_NEXT=$(jq -r '.data.repository.pullRequest.reviewThreads.pageInfo.hasNextPage' <<< "$PAGE")
77
+ [ "$HAS_NEXT" = "true" ] || break
78
+ CURSOR=$(jq -r '.data.repository.pullRequest.reviewThreads.pageInfo.endCursor' <<< "$PAGE")
79
+ done
80
+
81
+ echo "$ALL_THREADS" | jq \
82
+ '.[] | select(.comments.nodes[0].author.login == "qodo-code-review") | select(.isResolved == false)'
83
+ ```
84
+
85
+ ## Parsing a thread's finding out of `comments.nodes[0].body`
86
+
87
+ The body is markdown with embedded HTML. Extract:
88
+ - **Title + severity**: first line has a badge image; `alt="Remediation recommended"` = actionable, `alt="Informational"` = optional. The finding title/tags follow on the next line (e.g. `3\. pickclaimroaster branch untested <code>📘 Rule violation</code> ...`).
89
+ - **Agent Prompt**: the fenced ```` ```...``` ```` block under a `<summary>` reading either `Agent Prompt` or `Agent prompt` (Qodo's casing differs between the inline-comment surface and the rollup issue-comment surface — match case-insensitively). This block is the whole fix spec: issue description, context, fix focus files/lines, and often a suggested fix. Use it verbatim as the task.
90
+
91
+ If a thread somehow has no Agent Prompt block (seen only on the rollup's
92
+ lower-severity "Optional" entries in some cases), fall back to the finding's
93
+ plain-text description above the badge.
94
+
95
+ ## Reply to a thread
96
+
97
+ ```bash
98
+ gh api graphql -f query='
99
+ mutation($threadId: ID!, $body: String!) {
100
+ addPullRequestReviewThreadReply(input: {pullRequestReviewThreadId: $threadId, body: $body}) {
101
+ comment { id }
102
+ }
103
+ }' -f threadId="$THREAD_ID" -f body="$REPLY_TEXT"
104
+ ```
105
+
106
+ Pass the thread id and reply text as GraphQL **variables** (`-f`), never
107
+ interpolated straight into the query string. A reply containing a quote,
108
+ backtick, or embedded newline breaks — or, worse, injects into — a
109
+ hand-built query string; `gh api graphql -f` handles the escaping correctly
110
+ when the value travels as a variable instead.
111
+
112
+ `pullRequestReviewThreadId` and `body` are the only required input fields
113
+ (`pullRequestReviewId` and `clientMutationId` are optional — omit them).
114
+
115
+ ## Resolve a thread (batch)
116
+
117
+ ```graphql
118
+ mutation {
119
+ t1: resolveReviewThread(input: {threadId: "ID1"}) { thread { isResolved } }
120
+ t2: resolveReviewThread(input: {threadId: "ID2"}) { thread { isResolved } }
121
+ }
122
+ ```
123
+
124
+ Only resolve a thread whose fix is already pushed and confirmed durable on
125
+ the branch (SKILL.md §2E-F) — resolving first and pushing second means a
126
+ failed push leaves GitHub showing the finding as handled when it isn't. Never
127
+ resolve a blocked/skipped finding at all; reply to it and leave it open.
128
+
129
+ ## Fetch the rollup issue comment (context only, not the source of truth)
130
+
131
+ Useful for the human-readable summary counts (bugs/rule-violations) in your
132
+ final report, or as a fallback if `reviewThreads` ever comes back empty for a
133
+ PR that clearly has a completed review. Select the latest by `created_at`.
134
+ Whether Qodo edits this comment in place across passes or posts a new one
135
+ each time is **unconfirmed** — every PR checked had exactly one, untouched
136
+ since creation, which doesn't distinguish the two. Sort by `created_at` and
137
+ take the last one either way; it's correct under both behaviors:
138
+
139
+ ```bash
140
+ gh api --paginate "repos/{owner}/{repo}/issues/<PR_NUMBER>/comments?per_page=100" \
141
+ | jq -s 'add
142
+ | map(select(.user.login == "qodo-code-review[bot]"))
143
+ | map(select(.body | startswith("<h3>Code Review by Qodo</h3>")))
144
+ | sort_by(.created_at)
145
+ | last'
146
+ ```
147
+
148
+ A rate-limit/paused comment reads `<h3>Qodo is busy working</h3>` while
149
+ in-flight, or contains "Qodo reviews are paused" / "review limit" when
150
+ terminally blocked — check for that text before assuming a missing review
151
+ comment just means "still running".
@@ -44,7 +44,19 @@ Qodo has **no check run to poll** — there is nothing in `gh pr checks` to wait
44
44
  gh pr view --json number,headRefName,headRefOid -q '{number, branch: .headRefName, sha: .headRefOid}'
45
45
  ```
46
46
 
47
- Check out the branch if not already on it.
47
+ Check out the branch if not already on it, **then require a clean working
48
+ tree** (`git status --porcelain` empty) before touching anything:
49
+
50
+ ```bash
51
+ [ -z "$(git status --porcelain)" ] || { echo "working tree not clean — refusing to start, would risk committing unrelated changes"; exit 1; }
52
+ ```
53
+
54
+ This is the precondition step E's scoped `git add <file>` depends on: staging
55
+ only the files a fix touched is safe *because* the tree started clean, so
56
+ nothing else could be sitting in those files. Skip this check and a file
57
+ with pre-existing local edits will have those edits swept into the fix
58
+ commit right along with it — the exact failure `git add -A` had, just
59
+ narrower.
48
60
 
49
61
  ### 2. Loop (max 5 iterations)
50
62
 
@@ -0,0 +1,151 @@
1
+ # GraphQL queries reference
2
+
3
+ Field names verified by introspection against GitHub's live GraphQL schema
4
+ (`AddPullRequestReviewThreadReplyInput`) and against a real Qodo install's
5
+ comment output — not guessed.
6
+
7
+ **The bot's login string is spelled differently in REST vs GraphQL.** REST
8
+ (`.user.login` on `issues/.../comments`) returns `qodo-code-review[bot]`.
9
+ GraphQL (`author.login` on `reviewThreads`) returns `qodo-code-review` — no
10
+ `[bot]` suffix — confirmed live against a real PR with real Qodo inline
11
+ threads. Using the REST spelling in a GraphQL filter silently matches
12
+ nothing, which reads as "no findings" instead of "wrong filter" — exactly the
13
+ kind of bug that has no crash and no error to notice. Use `[bot]` only in
14
+ REST-based jq filters (`.user.login`); use the bare name everywhere you're
15
+ filtering a GraphQL `author.login`.
16
+
17
+ ## Fetch unresolved Qodo threads (paginated)
18
+
19
+ ```graphql
20
+ query($cursor: String) {
21
+ repository(owner: "OWNER", name: "REPO") {
22
+ pullRequest(number: PR_NUMBER) {
23
+ reviewThreads(first: 100, after: $cursor) {
24
+ pageInfo { hasNextPage endCursor }
25
+ nodes {
26
+ id
27
+ isResolved
28
+ comments(first: 1) {
29
+ nodes { body path line author { login } }
30
+ }
31
+ }
32
+ }
33
+ }
34
+ }
35
+ }
36
+ ```
37
+
38
+ Filter client-side to `qodo-code-review` (GraphQL spelling — see the note
39
+ above) and `isResolved == false` — the author isn't filterable server-side in
40
+ this shape. **Follow `pageInfo.hasNextPage`/`endCursor` until it's exhausted**;
41
+ stopping after the first page silently drops every thread past the 100th on a
42
+ PR with a lot of findings:
43
+
44
+ A page fetch can occasionally come back malformed (a transient API hiccup,
45
+ not anything specific to this query — reproduced live, then failed to
46
+ reproduce on an identical immediate retry). Retry once per page before
47
+ giving up rather than letting the whole loop crash on it:
48
+
49
+ ```bash
50
+ CURSOR=null
51
+ ALL_THREADS='[]'
52
+ while :; do
53
+ for attempt in 1 2; do
54
+ PAGE=$(gh api graphql -f query='
55
+ query($cursor: String) {
56
+ repository(owner: "OWNER", name: "REPO") {
57
+ pullRequest(number: PR_NUMBER) {
58
+ reviewThreads(first: 100, after: $cursor) {
59
+ pageInfo { hasNextPage endCursor }
60
+ nodes {
61
+ id
62
+ isResolved
63
+ comments(first: 1) { nodes { body path line author { login } } }
64
+ }
65
+ }
66
+ }
67
+ }
68
+ }' -f cursor="$CURSOR")
69
+ jq -e . >/dev/null 2>&1 <<< "$PAGE" && break
70
+ [ "$attempt" = "2" ] && { echo "page fetch failed twice, aborting" >&2; exit 1; }
71
+ done
72
+
73
+ ALL_THREADS=$(jq -c --argjson acc "$ALL_THREADS" \
74
+ '$acc + .data.repository.pullRequest.reviewThreads.nodes' <<< "$PAGE")
75
+
76
+ HAS_NEXT=$(jq -r '.data.repository.pullRequest.reviewThreads.pageInfo.hasNextPage' <<< "$PAGE")
77
+ [ "$HAS_NEXT" = "true" ] || break
78
+ CURSOR=$(jq -r '.data.repository.pullRequest.reviewThreads.pageInfo.endCursor' <<< "$PAGE")
79
+ done
80
+
81
+ echo "$ALL_THREADS" | jq \
82
+ '.[] | select(.comments.nodes[0].author.login == "qodo-code-review") | select(.isResolved == false)'
83
+ ```
84
+
85
+ ## Parsing a thread's finding out of `comments.nodes[0].body`
86
+
87
+ The body is markdown with embedded HTML. Extract:
88
+ - **Title + severity**: first line has a badge image; `alt="Remediation recommended"` = actionable, `alt="Informational"` = optional. The finding title/tags follow on the next line (e.g. `3\. pickclaimroaster branch untested <code>📘 Rule violation</code> ...`).
89
+ - **Agent Prompt**: the fenced ```` ```...``` ```` block under a `<summary>` reading either `Agent Prompt` or `Agent prompt` (Qodo's casing differs between the inline-comment surface and the rollup issue-comment surface — match case-insensitively). This block is the whole fix spec: issue description, context, fix focus files/lines, and often a suggested fix. Use it verbatim as the task.
90
+
91
+ If a thread somehow has no Agent Prompt block (seen only on the rollup's
92
+ lower-severity "Optional" entries in some cases), fall back to the finding's
93
+ plain-text description above the badge.
94
+
95
+ ## Reply to a thread
96
+
97
+ ```bash
98
+ gh api graphql -f query='
99
+ mutation($threadId: ID!, $body: String!) {
100
+ addPullRequestReviewThreadReply(input: {pullRequestReviewThreadId: $threadId, body: $body}) {
101
+ comment { id }
102
+ }
103
+ }' -f threadId="$THREAD_ID" -f body="$REPLY_TEXT"
104
+ ```
105
+
106
+ Pass the thread id and reply text as GraphQL **variables** (`-f`), never
107
+ interpolated straight into the query string. A reply containing a quote,
108
+ backtick, or embedded newline breaks — or, worse, injects into — a
109
+ hand-built query string; `gh api graphql -f` handles the escaping correctly
110
+ when the value travels as a variable instead.
111
+
112
+ `pullRequestReviewThreadId` and `body` are the only required input fields
113
+ (`pullRequestReviewId` and `clientMutationId` are optional — omit them).
114
+
115
+ ## Resolve a thread (batch)
116
+
117
+ ```graphql
118
+ mutation {
119
+ t1: resolveReviewThread(input: {threadId: "ID1"}) { thread { isResolved } }
120
+ t2: resolveReviewThread(input: {threadId: "ID2"}) { thread { isResolved } }
121
+ }
122
+ ```
123
+
124
+ Only resolve a thread whose fix is already pushed and confirmed durable on
125
+ the branch (SKILL.md §2E-F) — resolving first and pushing second means a
126
+ failed push leaves GitHub showing the finding as handled when it isn't. Never
127
+ resolve a blocked/skipped finding at all; reply to it and leave it open.
128
+
129
+ ## Fetch the rollup issue comment (context only, not the source of truth)
130
+
131
+ Useful for the human-readable summary counts (bugs/rule-violations) in your
132
+ final report, or as a fallback if `reviewThreads` ever comes back empty for a
133
+ PR that clearly has a completed review. Select the latest by `created_at`.
134
+ Whether Qodo edits this comment in place across passes or posts a new one
135
+ each time is **unconfirmed** — every PR checked had exactly one, untouched
136
+ since creation, which doesn't distinguish the two. Sort by `created_at` and
137
+ take the last one either way; it's correct under both behaviors:
138
+
139
+ ```bash
140
+ gh api --paginate "repos/{owner}/{repo}/issues/<PR_NUMBER>/comments?per_page=100" \
141
+ | jq -s 'add
142
+ | map(select(.user.login == "qodo-code-review[bot]"))
143
+ | map(select(.body | startswith("<h3>Code Review by Qodo</h3>")))
144
+ | sort_by(.created_at)
145
+ | last'
146
+ ```
147
+
148
+ A rate-limit/paused comment reads `<h3>Qodo is busy working</h3>` while
149
+ in-flight, or contains "Qodo reviews are paused" / "review limit" when
150
+ terminally blocked — check for that text before assuming a missing review
151
+ comment just means "still running".
@@ -43,7 +43,19 @@ Qodo has **no check run to poll** — there is nothing in `gh pr checks` to wait
43
43
  gh pr view --json number,headRefName,headRefOid -q '{number, branch: .headRefName, sha: .headRefOid}'
44
44
  ```
45
45
 
46
- Check out the branch if not already on it.
46
+ Check out the branch if not already on it, **then require a clean working
47
+ tree** (`git status --porcelain` empty) before touching anything:
48
+
49
+ ```bash
50
+ [ -z "$(git status --porcelain)" ] || { echo "working tree not clean — refusing to start, would risk committing unrelated changes"; exit 1; }
51
+ ```
52
+
53
+ This is the precondition step E's scoped `git add <file>` depends on: staging
54
+ only the files a fix touched is safe *because* the tree started clean, so
55
+ nothing else could be sitting in those files. Skip this check and a file
56
+ with pre-existing local edits will have those edits swept into the fix
57
+ commit right along with it — the exact failure `git add -A` had, just
58
+ narrower.
47
59
 
48
60
  ### 2. Loop (max 5 iterations)
49
61
 
@@ -0,0 +1,151 @@
1
+ # GraphQL queries reference
2
+
3
+ Field names verified by introspection against GitHub's live GraphQL schema
4
+ (`AddPullRequestReviewThreadReplyInput`) and against a real Qodo install's
5
+ comment output — not guessed.
6
+
7
+ **The bot's login string is spelled differently in REST vs GraphQL.** REST
8
+ (`.user.login` on `issues/.../comments`) returns `qodo-code-review[bot]`.
9
+ GraphQL (`author.login` on `reviewThreads`) returns `qodo-code-review` — no
10
+ `[bot]` suffix — confirmed live against a real PR with real Qodo inline
11
+ threads. Using the REST spelling in a GraphQL filter silently matches
12
+ nothing, which reads as "no findings" instead of "wrong filter" — exactly the
13
+ kind of bug that has no crash and no error to notice. Use `[bot]` only in
14
+ REST-based jq filters (`.user.login`); use the bare name everywhere you're
15
+ filtering a GraphQL `author.login`.
16
+
17
+ ## Fetch unresolved Qodo threads (paginated)
18
+
19
+ ```graphql
20
+ query($cursor: String) {
21
+ repository(owner: "OWNER", name: "REPO") {
22
+ pullRequest(number: PR_NUMBER) {
23
+ reviewThreads(first: 100, after: $cursor) {
24
+ pageInfo { hasNextPage endCursor }
25
+ nodes {
26
+ id
27
+ isResolved
28
+ comments(first: 1) {
29
+ nodes { body path line author { login } }
30
+ }
31
+ }
32
+ }
33
+ }
34
+ }
35
+ }
36
+ ```
37
+
38
+ Filter client-side to `qodo-code-review` (GraphQL spelling — see the note
39
+ above) and `isResolved == false` — the author isn't filterable server-side in
40
+ this shape. **Follow `pageInfo.hasNextPage`/`endCursor` until it's exhausted**;
41
+ stopping after the first page silently drops every thread past the 100th on a
42
+ PR with a lot of findings:
43
+
44
+ A page fetch can occasionally come back malformed (a transient API hiccup,
45
+ not anything specific to this query — reproduced live, then failed to
46
+ reproduce on an identical immediate retry). Retry once per page before
47
+ giving up rather than letting the whole loop crash on it:
48
+
49
+ ```bash
50
+ CURSOR=null
51
+ ALL_THREADS='[]'
52
+ while :; do
53
+ for attempt in 1 2; do
54
+ PAGE=$(gh api graphql -f query='
55
+ query($cursor: String) {
56
+ repository(owner: "OWNER", name: "REPO") {
57
+ pullRequest(number: PR_NUMBER) {
58
+ reviewThreads(first: 100, after: $cursor) {
59
+ pageInfo { hasNextPage endCursor }
60
+ nodes {
61
+ id
62
+ isResolved
63
+ comments(first: 1) { nodes { body path line author { login } } }
64
+ }
65
+ }
66
+ }
67
+ }
68
+ }' -f cursor="$CURSOR")
69
+ jq -e . >/dev/null 2>&1 <<< "$PAGE" && break
70
+ [ "$attempt" = "2" ] && { echo "page fetch failed twice, aborting" >&2; exit 1; }
71
+ done
72
+
73
+ ALL_THREADS=$(jq -c --argjson acc "$ALL_THREADS" \
74
+ '$acc + .data.repository.pullRequest.reviewThreads.nodes' <<< "$PAGE")
75
+
76
+ HAS_NEXT=$(jq -r '.data.repository.pullRequest.reviewThreads.pageInfo.hasNextPage' <<< "$PAGE")
77
+ [ "$HAS_NEXT" = "true" ] || break
78
+ CURSOR=$(jq -r '.data.repository.pullRequest.reviewThreads.pageInfo.endCursor' <<< "$PAGE")
79
+ done
80
+
81
+ echo "$ALL_THREADS" | jq \
82
+ '.[] | select(.comments.nodes[0].author.login == "qodo-code-review") | select(.isResolved == false)'
83
+ ```
84
+
85
+ ## Parsing a thread's finding out of `comments.nodes[0].body`
86
+
87
+ The body is markdown with embedded HTML. Extract:
88
+ - **Title + severity**: first line has a badge image; `alt="Remediation recommended"` = actionable, `alt="Informational"` = optional. The finding title/tags follow on the next line (e.g. `3\. pickclaimroaster branch untested <code>📘 Rule violation</code> ...`).
89
+ - **Agent Prompt**: the fenced ```` ```...``` ```` block under a `<summary>` reading either `Agent Prompt` or `Agent prompt` (Qodo's casing differs between the inline-comment surface and the rollup issue-comment surface — match case-insensitively). This block is the whole fix spec: issue description, context, fix focus files/lines, and often a suggested fix. Use it verbatim as the task.
90
+
91
+ If a thread somehow has no Agent Prompt block (seen only on the rollup's
92
+ lower-severity "Optional" entries in some cases), fall back to the finding's
93
+ plain-text description above the badge.
94
+
95
+ ## Reply to a thread
96
+
97
+ ```bash
98
+ gh api graphql -f query='
99
+ mutation($threadId: ID!, $body: String!) {
100
+ addPullRequestReviewThreadReply(input: {pullRequestReviewThreadId: $threadId, body: $body}) {
101
+ comment { id }
102
+ }
103
+ }' -f threadId="$THREAD_ID" -f body="$REPLY_TEXT"
104
+ ```
105
+
106
+ Pass the thread id and reply text as GraphQL **variables** (`-f`), never
107
+ interpolated straight into the query string. A reply containing a quote,
108
+ backtick, or embedded newline breaks — or, worse, injects into — a
109
+ hand-built query string; `gh api graphql -f` handles the escaping correctly
110
+ when the value travels as a variable instead.
111
+
112
+ `pullRequestReviewThreadId` and `body` are the only required input fields
113
+ (`pullRequestReviewId` and `clientMutationId` are optional — omit them).
114
+
115
+ ## Resolve a thread (batch)
116
+
117
+ ```graphql
118
+ mutation {
119
+ t1: resolveReviewThread(input: {threadId: "ID1"}) { thread { isResolved } }
120
+ t2: resolveReviewThread(input: {threadId: "ID2"}) { thread { isResolved } }
121
+ }
122
+ ```
123
+
124
+ Only resolve a thread whose fix is already pushed and confirmed durable on
125
+ the branch (SKILL.md §2E-F) — resolving first and pushing second means a
126
+ failed push leaves GitHub showing the finding as handled when it isn't. Never
127
+ resolve a blocked/skipped finding at all; reply to it and leave it open.
128
+
129
+ ## Fetch the rollup issue comment (context only, not the source of truth)
130
+
131
+ Useful for the human-readable summary counts (bugs/rule-violations) in your
132
+ final report, or as a fallback if `reviewThreads` ever comes back empty for a
133
+ PR that clearly has a completed review. Select the latest by `created_at`.
134
+ Whether Qodo edits this comment in place across passes or posts a new one
135
+ each time is **unconfirmed** — every PR checked had exactly one, untouched
136
+ since creation, which doesn't distinguish the two. Sort by `created_at` and
137
+ take the last one either way; it's correct under both behaviors:
138
+
139
+ ```bash
140
+ gh api --paginate "repos/{owner}/{repo}/issues/<PR_NUMBER>/comments?per_page=100" \
141
+ | jq -s 'add
142
+ | map(select(.user.login == "qodo-code-review[bot]"))
143
+ | map(select(.body | startswith("<h3>Code Review by Qodo</h3>")))
144
+ | sort_by(.created_at)
145
+ | last'
146
+ ```
147
+
148
+ A rate-limit/paused comment reads `<h3>Qodo is busy working</h3>` while
149
+ in-flight, or contains "Qodo reviews are paused" / "review limit" when
150
+ terminally blocked — check for that text before assuming a missing review
151
+ comment just means "still running".
@@ -35,7 +35,19 @@ Qodo has **no check run to poll** — there is nothing in `gh pr checks` to wait
35
35
  gh pr view --json number,headRefName,headRefOid -q '{number, branch: .headRefName, sha: .headRefOid}'
36
36
  ```
37
37
 
38
- Check out the branch if not already on it.
38
+ Check out the branch if not already on it, **then require a clean working
39
+ tree** (`git status --porcelain` empty) before touching anything:
40
+
41
+ ```bash
42
+ [ -z "$(git status --porcelain)" ] || { echo "working tree not clean — refusing to start, would risk committing unrelated changes"; exit 1; }
43
+ ```
44
+
45
+ This is the precondition step E's scoped `git add <file>` depends on: staging
46
+ only the files a fix touched is safe *because* the tree started clean, so
47
+ nothing else could be sitting in those files. Skip this check and a file
48
+ with pre-existing local edits will have those edits swept into the fix
49
+ commit right along with it — the exact failure `git add -A` had, just
50
+ narrower.
39
51
 
40
52
  ### 2. Loop (max 5 iterations)
41
53