claude-dev-env 1.83.0 → 1.84.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 (165) hide show
  1. package/_shared/pr-loop/audit-contract.md +24 -12
  2. package/_shared/pr-loop/scripts/_claude_permissions_common.py +16 -5
  3. package/_shared/pr-loop/scripts/code_rules_gate.py +2 -3
  4. package/_shared/pr-loop/scripts/reviews_disabled.py +2 -0
  5. package/_shared/pr-loop/scripts/tests/test__claude_permissions_common.py +212 -0
  6. package/_shared/pr-loop/scripts/tests/test_agent_config_carveout.py +18 -0
  7. package/_shared/pr-loop/scripts/tests/test_claude_permissions_common.py +18 -0
  8. package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +37 -0
  9. package/_shared/pr-loop/scripts/tests/test_reviews_disabled.py +14 -0
  10. package/agents/clean-coder.md +3 -0
  11. package/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md +1 -1
  12. package/bin/install.mjs +16 -8
  13. package/bin/install.test.mjs +17 -6
  14. package/commands/CLAUDE.md +0 -1
  15. package/docs/CODE_RULES.md +1 -1
  16. package/hooks/blocking/CLAUDE.md +0 -4
  17. package/hooks/blocking/code_rules_constants_config.py +5 -0
  18. package/hooks/blocking/code_rules_docstrings.py +116 -6
  19. package/hooks/blocking/code_rules_enforcer.py +4 -0
  20. package/hooks/blocking/code_rules_magic_values.py +5 -0
  21. package/hooks/blocking/code_rules_naming_collection.py +11 -6
  22. package/hooks/blocking/code_rules_shared.py +34 -0
  23. package/hooks/blocking/duplicate_rmtree_helper_blocker.py +4 -4
  24. package/hooks/blocking/test_code_rules_enforcer_docstring_prose_wall_illustration.py +197 -0
  25. package/hooks/blocking/test_code_rules_enforcer_docstring_runon_sentence.py +27 -0
  26. package/hooks/blocking/test_code_rules_enforcer_split_constants_config.py +33 -0
  27. package/hooks/blocking/test_code_rules_enforcer_split_shared.py +23 -0
  28. package/hooks/blocking/test_code_rules_magic_values.py +54 -0
  29. package/hooks/blocking/test_duplicate_rmtree_helper_blocker.py +0 -6
  30. package/hooks/blocking/test_pr_converge_bugteam_enforcer_state_tolerance.py +184 -0
  31. package/hooks/blocking/test_shared_stdin_adoption.py +5 -30
  32. package/hooks/hooks_constants/CLAUDE.md +0 -3
  33. package/hooks/hooks_constants/blocking_check_limits.py +3 -0
  34. package/hooks/hooks_constants/code_rules_path_utils_constants.py +1 -1
  35. package/hooks/hooks_constants/duplicate_rmtree_helper_blocker_constants.py +0 -1
  36. package/hooks/hooks_constants/post_tool_use_dispatcher_constants.py +0 -5
  37. package/hooks/validation/post_tool_use_dispatcher.py +1 -1
  38. package/hooks/validation/test_post_tool_use_dispatcher.py +51 -35
  39. package/hooks/workflow/CLAUDE.md +2 -8
  40. package/package.json +1 -1
  41. package/rules/CLAUDE.md +1 -1
  42. package/rules/plain-illustrative-docstrings.md +35 -1
  43. package/skills/CLAUDE.md +6 -1
  44. package/skills/autoconverge/SKILL.md +38 -57
  45. package/skills/autoconverge/reference/closing-report.md +6 -6
  46. package/skills/autoconverge/reference/convergence.md +17 -15
  47. package/skills/autoconverge/reference/gotchas.md +6 -3
  48. package/skills/autoconverge/workflow/autoconverge_report_constants/render_report_constants.py +2 -9
  49. package/skills/autoconverge/workflow/converge.contract.test.mjs +87 -13
  50. package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +1 -1
  51. package/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +16 -9
  52. package/skills/autoconverge/workflow/converge.mjs +70 -73
  53. package/skills/autoconverge/workflow/render_report.py +7 -11
  54. package/skills/bugteam/CLAUDE.md +1 -1
  55. package/skills/bugteam/PROMPTS.md +7 -6
  56. package/skills/bugteam/SKILL.md +25 -72
  57. package/skills/bugteam/reference/CLAUDE.md +1 -3
  58. package/skills/bugteam/reference/README.md +1 -1
  59. package/skills/bugteam/reference/audit-and-teammates.md +1 -1
  60. package/skills/bugteam/reference/obstacles/fix-publish-summary.md +1 -1
  61. package/skills/bugteam/reference/team-setup.md +8 -7
  62. package/skills/bugteam/scripts/CLAUDE.md +0 -6
  63. package/skills/bugteam/scripts/README.md +0 -4
  64. package/skills/bugteam/scripts/bugteam_scripts_constants/CLAUDE.md +0 -1
  65. package/skills/code/SKILL.md +2 -0
  66. package/skills/copilot-review/CLAUDE.md +1 -1
  67. package/skills/copilot-review/SKILL.md +25 -23
  68. package/skills/findbugs/CLAUDE.md +2 -2
  69. package/skills/findbugs/SKILL.md +22 -83
  70. package/skills/fixbugs/SKILL.md +2 -4
  71. package/skills/log-audit/CLAUDE.md +20 -0
  72. package/skills/log-audit/SKILL.md +68 -0
  73. package/skills/log-audit/reference/CLAUDE.md +9 -0
  74. package/skills/log-audit/reference/charter.md +52 -0
  75. package/skills/log-audit/scripts/CLAUDE.md +27 -0
  76. package/skills/log-audit/scripts/cluster_recurrences.py +261 -0
  77. package/skills/log-audit/scripts/collect_log_window.py +199 -0
  78. package/skills/log-audit/scripts/log_audit_constants/CLAUDE.md +12 -0
  79. package/skills/log-audit/scripts/log_audit_constants/cluster_recurrences_constants.py +23 -0
  80. package/skills/log-audit/scripts/log_audit_constants/collect_log_window_constants.py +24 -0
  81. package/skills/log-audit/scripts/log_audit_constants/mine_copilot_findings_constants.py +49 -0
  82. package/skills/log-audit/scripts/mine_copilot_findings.py +302 -0
  83. package/skills/log-audit/scripts/test_cluster_recurrences.py +160 -0
  84. package/skills/log-audit/scripts/test_collect_log_window.py +111 -0
  85. package/skills/log-audit/scripts/test_mine_copilot_findings.py +126 -0
  86. package/skills/monitor-open-prs/SKILL.md +2 -2
  87. package/skills/post-audit-findings/SKILL.md +84 -0
  88. package/skills/pr-converge/CLAUDE.md +2 -0
  89. package/skills/pr-converge/SKILL.md +72 -59
  90. package/skills/pr-converge/reference/CLAUDE.md +1 -1
  91. package/skills/pr-converge/reference/convergence-gates.md +16 -19
  92. package/skills/pr-converge/reference/examples.md +5 -5
  93. package/skills/pr-converge/reference/fix-protocol.md +16 -43
  94. package/skills/pr-converge/reference/obstacles/fix-publish-summary.md +1 -1
  95. package/skills/pr-converge/reference/per-tick.md +24 -45
  96. package/skills/pr-converge/reference/state-schema.md +15 -0
  97. package/skills/pr-converge/scripts/README.md +3 -5
  98. package/skills/pr-fix-protocol/SKILL.md +70 -0
  99. package/skills/pr-loop-lifecycle/SKILL.md +73 -0
  100. package/skills/{bugteam → pr-loop-lifecycle}/reference/teardown-publish-permissions.md +22 -24
  101. package/skills/pr-scope-resolve/SKILL.md +48 -0
  102. package/skills/qbug/CLAUDE.md +4 -4
  103. package/skills/qbug/SKILL.md +46 -144
  104. package/skills/qbug/test_qbug_skill_audit_schema.py +2 -2
  105. package/skills/qbug/test_qbug_skill_post_fix_audit.py +1 -1
  106. package/skills/reviewer-gates/SKILL.md +96 -0
  107. package/skills/session-log/CLAUDE.md +7 -7
  108. package/skills/session-log/SKILL.md +27 -44
  109. package/skills/test_markdown_link_integrity.py +103 -0
  110. package/commands/doc-gist.md +0 -16
  111. package/hooks/blocking/_md_to_html_blocker_test_support.py +0 -65
  112. package/hooks/blocking/conftest.py +0 -30
  113. package/hooks/blocking/md_path_exemptions.py +0 -224
  114. package/hooks/blocking/md_to_html_blocker.py +0 -155
  115. package/hooks/blocking/test_md_to_html_blocker_exemptions.py +0 -434
  116. package/hooks/blocking/test_md_to_html_blocker_extensions.py +0 -157
  117. package/hooks/blocking/test_md_to_html_blocker_path_resolution.py +0 -336
  118. package/hooks/hooks_constants/doc_gist_auto_publish_constants.py +0 -18
  119. package/hooks/hooks_constants/html_companion_constants.py +0 -20
  120. package/hooks/hooks_constants/md_to_html_blocker_constants.py +0 -76
  121. package/hooks/hooks_constants/test_md_to_html_blocker_constants.py +0 -125
  122. package/hooks/workflow/doc_gist_auto_publish.py +0 -144
  123. package/hooks/workflow/md_to_html_companion.py +0 -358
  124. package/hooks/workflow/test_doc_gist_auto_publish.py +0 -117
  125. package/hooks/workflow/test_md_to_html_companion.py +0 -613
  126. package/skills/bugteam/reference/audit-contract.md +0 -163
  127. package/skills/bugteam/scripts/_bugteam_permissions_common.py +0 -455
  128. package/skills/bugteam/scripts/bugteam_scripts_constants/claude_permissions_common_constants.py +0 -69
  129. package/skills/bugteam/scripts/grant_project_claude_permissions.py +0 -280
  130. package/skills/bugteam/scripts/revoke_project_claude_permissions.py +0 -266
  131. package/skills/bugteam/scripts/test__bugteam_permissions_common.py +0 -160
  132. package/skills/bugteam/scripts/test_agent_config_carveout.py +0 -356
  133. package/skills/bugteam/scripts/test_bugteam_permissions_common.py +0 -140
  134. package/skills/doc-gist/CLAUDE.md +0 -25
  135. package/skills/doc-gist/SKILL.md +0 -97
  136. package/skills/doc-gist/references/CLAUDE.md +0 -9
  137. package/skills/doc-gist/references/examples/01-exploration-code-approaches.html +0 -453
  138. package/skills/doc-gist/references/examples/02-exploration-visual-designs.html +0 -515
  139. package/skills/doc-gist/references/examples/03-code-review-pr.html +0 -638
  140. package/skills/doc-gist/references/examples/04-code-understanding.html +0 -491
  141. package/skills/doc-gist/references/examples/05-design-system.html +0 -629
  142. package/skills/doc-gist/references/examples/06-component-variants.html +0 -605
  143. package/skills/doc-gist/references/examples/07-prototype-animation.html +0 -455
  144. package/skills/doc-gist/references/examples/08-prototype-interaction.html +0 -396
  145. package/skills/doc-gist/references/examples/09-slide-deck.html +0 -592
  146. package/skills/doc-gist/references/examples/10-svg-illustrations.html +0 -492
  147. package/skills/doc-gist/references/examples/11-status-report.html +0 -528
  148. package/skills/doc-gist/references/examples/12-incident-report.html +0 -596
  149. package/skills/doc-gist/references/examples/13-flowchart-diagram.html +0 -395
  150. package/skills/doc-gist/references/examples/14-research-feature-explainer.html +0 -381
  151. package/skills/doc-gist/references/examples/15-research-concept-explainer.html +0 -368
  152. package/skills/doc-gist/references/examples/16-implementation-plan.html +0 -702
  153. package/skills/doc-gist/references/examples/17-pr-writeup.html +0 -595
  154. package/skills/doc-gist/references/examples/18-editor-triage-board.html +0 -573
  155. package/skills/doc-gist/references/examples/19-editor-feature-flags.html +0 -663
  156. package/skills/doc-gist/references/examples/20-editor-prompt-tuner.html +0 -722
  157. package/skills/doc-gist/references/examples/21-decision-signoff.html +0 -546
  158. package/skills/doc-gist/references/examples/CLAUDE.md +0 -25
  159. package/skills/doc-gist/references/examples/README.md +0 -5
  160. package/skills/doc-gist/scripts/CLAUDE.md +0 -27
  161. package/skills/doc-gist/scripts/doc_gist_scripts_constants/CLAUDE.md +0 -10
  162. package/skills/doc-gist/scripts/doc_gist_scripts_constants/gist_upload_constants.py +0 -16
  163. package/skills/doc-gist/scripts/gist_upload.py +0 -177
  164. package/skills/doc-gist/scripts/test_gist_upload.py +0 -51
  165. /package/skills/{doc-gist/scripts/doc_gist_scripts_constants → log-audit/scripts/log_audit_constants}/__init__.py +0 -0
@@ -3,7 +3,7 @@ name: qbug
3
3
  description: >-
4
4
  Required baseline review for every new PR. Runs the /bugteam audit → fix →
5
5
  commit → push cycle via one clean-coder subagent (not a full team), looping
6
- until convergence or stuck. Uses the same CODE_RULES gate, A–N category
6
+ until convergence or stuck. Uses the same CODE_RULES gate, A–P category
7
7
  rubric, and per-loop PR review shape as /bugteam — without TeamCreate,
8
8
  teammates, per-loop clean-room, or a loop cap. Invoke /bugteam instead for
9
9
  larger PRs that need per-loop bias isolation or a hard loop cap. Triggers:
@@ -21,8 +21,8 @@ Shared artifacts with /bugteam are referenced below by path, using the `${CLAUDE
21
21
 
22
22
  - Pre-flight script: `${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/preflight.py`
23
23
  - Code-rules gate script: `${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/code_rules_gate.py`
24
- - Bug category rubric A–N: [`bugteam/PROMPTS.md`](../bugteam/PROMPTS.md#audit-spawn-prompt-xml-bugfind-teammate)
25
- - **Audit contract** (finding schema, proof-of-absence, adversarial pass, Haiku secondary, post-fix self-audit, diagnostics JSON): [`bugteam/reference/audit-contract.md`](../bugteam/reference/audit-contract.md)
24
+ - Bug category rubric A–P: [`bugteam/PROMPTS.md`](../bugteam/PROMPTS.md#audit-spawn-prompt-xml-bugfind-teammate)
25
+ - **Audit contract** (finding schema, proof-of-absence, adversarial pass, Haiku secondary, post-fix self-audit, diagnostics JSON): [`_shared/pr-loop/audit-contract.md`](../../_shared/pr-loop/audit-contract.md)
26
26
  - PR comment lifecycle shape: [`bugteam/SKILL.md`](../bugteam/SKILL.md#audit-posting)
27
27
 
28
28
  ## When this skill applies
@@ -31,12 +31,15 @@ Shared artifacts with /bugteam are referenced below by path, using the `${CLAUDE
31
31
 
32
32
  Refusals — first match wins; respond with the quoted line exactly and stop:
33
33
 
34
- - **Disabled via environment.** When `CLAUDE_REVIEWS_DISABLED` contains the
35
- token `bugteam` (comma-separated, case-insensitive, whitespace-tolerant):
36
- `/qbug is disabled via CLAUDE_REVIEWS_DISABLED.` `/qbug` is the bugteam
34
+ - **Disabled via environment.** When `CLAUDE_REVIEWS_DISABLED` carries the
35
+ token `bugteam`:
36
+ `/qbug is disabled via CLAUDE_REVIEWS_DISABLED.` Run the check via
37
+ `python "$HOME/.claude/_shared/pr-loop/scripts/reviews_disabled.py" --reviewer bugteam`
38
+ (exit 0 = disabled). `/qbug` is the bugteam
37
39
  baseline review and shares the `bugteam` token with `/bugteam`; the shared
38
40
  pre-flight script also exits 7 in this case so any caller invoking it
39
- directly halts on the same signal.
41
+ directly halts on the same signal. The gate semantics live in the
42
+ `reviewer-gates` skill (`../reviewer-gates/SKILL.md`).
40
43
  - **No PR or upstream diff.** `No PR or upstream diff. /qbug needs a target.`
41
44
  - **Dirty tree.** `Uncommitted changes detected. Stash, commit, or revert before /qbug.`
42
45
  - **Missing subagent.** Before Step 2, confirm `clean-coder` exists. Else: `Required subagent type clean-coder not installed. /qbug needs clean-coder available.`
@@ -72,9 +75,7 @@ Pre-flight checks (in order):
72
75
 
73
76
  ## Step 1: Resolve PR scope (lead)
74
77
 
75
- 1. Call `pull_request_read(method="get", pullNumber=N, owner=O, repo=R)` via the lead's available MCP tools (`N` comes from the parent skill's PR context, or fall back to `search_issues` MCP with the current branch name to recover the PR number). Extract `number`, `baseRefName`, `headRefName`, `url` from the response.
76
- 2. Else `git merge-base HEAD origin/<default>` then `git diff <merge-base>...HEAD`
77
- 3. Else refuse per § When this skill applies.
78
+ Apply the `pr-scope-resolve` skill (`../pr-scope-resolve/SKILL.md`) with caller `qbug`. When no target exists, refuse per § When this skill applies with the sub-skill's canonical line.
78
79
 
79
80
  Capture: `owner/repo`, `baseRefName`, `headRefName`, PR `number`, `url`, `starting_sha = git rev-parse HEAD`.
80
81
 
@@ -116,7 +117,7 @@ Agent(
116
117
  subagent_type="code-quality-agent",
117
118
  model="haiku",
118
119
  description="qbug Haiku secondary audit for PR <number>",
119
- prompt="<audit-only prompt: read the PR diff, apply A-N categories from <categories_file>, return structured findings. No FIX, no git add, no git commit, no git push.>",
120
+ prompt="<audit-only prompt: read the PR diff, apply A–P categories from <categories_file>, return structured findings. No FIX, no git add, no git commit, no git push.>",
120
121
  run_in_background=False
121
122
  )
122
123
  ```
@@ -187,11 +188,12 @@ The subagent receives this prompt and loops internally — the lead does not re-
187
188
 
188
189
  - Read the patch file.
189
190
  - Audit only added/modified lines. Read <categories_file> for the
190
- A–N category definitions; investigate each category explicitly.
191
+ A–P category definitions; investigate each category explicitly.
191
192
  - Follow the shared audit contract at
192
- bugteam/reference/audit-contract.md. Per category: produce
193
- either a Shape A structured finding or a Shape B structured
194
- proof-of-absence. Bare "verified clean" labels are REJECTED.
193
+ $HOME/.claude/_shared/pr-loop/audit-contract.md. Per category:
194
+ produce either a Shape A structured finding or a Shape B
195
+ structured proof-of-absence. Bare "verified clean" labels are
196
+ REJECTED.
195
197
  - Run the contract's adversarial second pass after the primary
196
198
  finding list.
197
199
  - The LEAD spawns the Haiku secondary auditor in parallel with
@@ -203,87 +205,20 @@ The subagent receives this prompt and loops internally — the lead does not re-
203
205
  <qbug_temp_dir>/loop-<loop_count>-audit.json per the contract's
204
206
  persistence schema.
205
207
 
206
- Post ONE review per loop via `post_audit_thread.py`. Before
207
- serializing, partition the merged findings into anchored (line
208
- appears in the captured diff) and unanchored (line is not in the
209
- diff) buckets. Only anchored findings are written to
210
- `<qbug_temp_dir>/loop-<loop_count>-findings.json` the GitHub
211
- reviews API rejects the entire POST if any inline comment in
212
- `comments[]` targets a line not in the diff at `--commit`, so a
213
- single unanchored entry breaks the whole review. Unanchored
214
- findings surface in the loop's user-facing summary rather than
215
- as inline anchored comments. The JSON root is a list of objects
216
- shaped `{path, line, side, severity, description, fix_summary}`.
217
- For each anchored finding, map `file` `path`; split the
218
- finding's `failure_mode` at the literal `Fix:` heading so the
219
- failure narrative becomes `description` and the suffix beginning
220
- at `Fix:` (including the trailing `Validation:` clause) becomes
221
- `fix_summary` (the `failure_mode` field carries the full
222
- audit-to-fix handoff per
223
- [`agents/code-quality-agent.md`](../../agents/code-quality-agent.md)).
224
- When a finding's `failure_mode` omits the `Fix:` heading, write
225
- the full text to BOTH `description` and `fix_summary`. Set
226
- `side="RIGHT"` for every entry. Zero anchored findings → write
227
- `[]` and pass `--state CLEAN`; one or more anchored findings →
228
- pass `--state DIRTY` with the full list.
229
-
230
- **Self-PR auto-toggle.** GitHub rejects both `APPROVE` and
231
- `REQUEST_CHANGES` reviews with HTTP 422 when the authenticated
232
- identity matches the PR author ("Cannot approve/request changes
233
- on your own pull request"). `post_audit_thread.py` detects this
234
- case via `gh api user` + `gh api repos/<o>/<r>/pulls/<n>` and
235
- auto-resolves an alternate gh account's token for the reviews
236
- POST — the active `gh auth` account is not mutated; only the
237
- bearer token sent on the request changes. After the POST the
238
- active account is still whoever it was before, so no "swap back"
239
- step is needed.
240
-
241
- Configuration:
242
-
243
- - `GH_TOKEN` / `GITHUB_TOKEN` env vars take precedence over the
244
- toggle. Set them when you need to pin a specific reviewer
245
- identity by token rather than by account login.
246
- - `BUGTEAM_REVIEWER_ACCOUNT` env var names which authenticated
247
- alternate to prefer when a toggle is needed (for example,
248
- `BUGTEAM_REVIEWER_ACCOUNT=jl-cmd`). The env var name is shared
249
- across every skill that invokes `post_audit_thread.py`. When
250
- unset, the script falls back to the first alternate account
251
- `gh auth status` reports.
252
- - The named alternate must be logged in (`gh auth login -h
253
- github.com -u <login>`) before the audit skill runs. The
254
- script exits 1 with a pointing-at-`gh auth login` message
255
- when self-PR is detected and no usable alternate is
256
- authenticated.
257
-
258
- ```
259
- python "${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/post_audit_thread.py" \
260
- --skill qbug \
261
- --owner <owner> \
262
- --repo <repo> \
263
- --pr-number <pr_number> \
264
- --commit <head_sha> \
265
- --state <CLEAN|DIRTY> \
266
- --findings-json <qbug_temp_dir>/loop-<loop_count>-findings.json
267
- ```
268
-
269
- The script POSTs a single review with `event=APPROVE` on CLEAN
270
- (the request event; GitHub stores it as `state=APPROVED`; empty
271
- `comments[]`, body documents "no findings") or
272
- `event=REQUEST_CHANGES` on DIRTY (one inline anchored comment per
273
- finding; each becomes its own resolvable thread on the PR). It
274
- handles retries internally (1s / 4s / 16s backoff across four
275
- attempts). Exit 0 emits the new review's `html_url` to stdout;
276
- extract the numeric review id from the URL's
277
- `#pullrequestreview-<id>` suffix (the trailing URL fragment of
278
- `html_url`, the part after `#`). Then harvest child-comment URLs **and PR review
279
- thread node ids** via
280
- `pull_request_read(method="get_review_comments",
281
- owner=<owner>, repo=<repo>, pullNumber=<pr_number>)` filtered to
282
- that review id. The same response carries each
283
- comment's PR review thread node id (e.g. `PRRT_kwDOxxx`) — match
284
- children to findings in the order they appear in the findings
285
- JSON. Each `loop_comment_index[finding_id]` entry must carry
286
- `finding_comment_id` (numeric, used by
208
+ Post ONE review per loop. Read
209
+ $HOME/.claude/skills/post-audit-findings/SKILL.md and apply it
210
+ with `--skill qbug`. That skill owns the findings-JSON mapping,
211
+ the anchored-only serialization, the CLEAN/DIRTY decision, the
212
+ self-PR reviewer toggle, and the exit codes. qbug-specific
213
+ persistence: write the anchored findings JSON to
214
+ `<qbug_temp_dir>/loop-<loop_count>-findings.json` and pass that
215
+ path as `--findings-json`. Unanchored findings surface in the
216
+ loop's user-facing summary rather than as inline anchored
217
+ comments.
218
+
219
+ On exit 0, harvest ids per that skill's "Harvest ids for the fix
220
+ loop" section: each `loop_comment_index[finding_id]` entry must
221
+ carry `finding_comment_id` (numeric, used by
287
222
  `add_reply_to_pull_request_comment`), `finding_comment_url`, and
288
223
  `thread_node_id` (`PRRT_kwDOxxx`, used by `resolve_thread`) so
289
224
  the FIX step can reply against the comment and resolve the
@@ -313,7 +248,7 @@ The subagent receives this prompt and loops internally — the lead does not re-
313
248
  for every modified file.
314
249
 
315
250
  Post-fix self-audit: follow the contract's post-fix self-audit
316
- sequence at bugteam/reference/audit-contract.md. Paranoid mode
251
+ sequence at $HOME/.claude/_shared/pr-loop/audit-contract.md. Paranoid mode
317
252
  (Haiku secondary in parallel), internal iteration cap = 3, exit
318
253
  "stuck: post-fix audit not converging" after 3 rounds with fresh
319
254
  findings. Only when gate_findings empty AND post_fix_findings
@@ -330,55 +265,22 @@ The subagent receives this prompt and loops internally — the lead does not re-
330
265
  Write <qbug_temp_dir>/loop-<loop_count>-diagnostics.json per the
331
266
  contract's diagnostics schema (all eight keys required).
332
267
 
333
- For each finding, atomically (a) post the fix reply and
334
- (b) call `resolve_thread`. The two calls form one logical action
335
- per thread do not yield to the lead between them, and do not
336
- batch all replies before any resolves.
337
-
338
- (a) Reply via
339
- `add_reply_to_pull_request_comment(commentId=<loop_comment_index[finding_id].finding_comment_id>,
340
- body=<reply_body>, owner=<owner>, repo=<repo>,
341
- pullNumber=<pr_number>)`. The reply body uses the unified template
342
- at [`../../_shared/pr-loop/audit-reply-template.md`](../../_shared/pr-loop/audit-reply-template.md).
343
- Skeleton (identical across all paths):
344
-
345
- ```
346
- **Claude finished @<reviewer>'s task** —— <status_line>
347
-
348
- ---
349
- ### <action_heading> ✅
350
-
351
- <1–2 paragraph plain-language explanation>
352
-
353
- **`<file>:<line>`:**
354
- - <bullet describing change or rationale>
355
- - <bullet describing change or rationale>
356
-
357
- <closing paragraph>
358
- ```
359
-
360
- Per-path `<status_line>` / `<action_heading>`:
361
- - `status=fixed`: `Fixed in <short_sha>` (first 7 chars) /
362
- finding-specific action verb (e.g.,
363
- `Replaced Any with concrete type`).
364
- - `status=could_not_address`: `Could not address this loop` /
365
- one-line reason text.
366
- - `status=hook_blocked`: `Hook blocked the fix commit` /
367
- one-line hook summary.
368
-
268
+ For each finding, read
269
+ $HOME/.claude/skills/pr-fix-protocol/SKILL.md and apply its
270
+ reply-and-resolve unit: atomically (a) post the fix reply via
271
+ `add_reply_to_pull_request_comment` against
272
+ `loop_comment_index[finding_id].finding_comment_id`, using the
273
+ body template at
274
+ $HOME/.claude/_shared/pr-loop/audit-reply-template.md, then
275
+ (b) call `pull_request_review_write(method="resolve_thread",
276
+ threadId=<loop_comment_index[finding_id].thread_node_id>)` for
277
+ the same thread. Per-path `<status_line>`:
278
+ - `status=fixed`: `Fixed in <short_sha>` (first 7 chars).
279
+ - `status=could_not_address`: `Could not address this loop`.
280
+ - `status=hook_blocked`: `Hook blocked the fix commit`.
369
281
  Body text is passed directly as string parameters — no temp
370
282
  files, no jq, no shell pipes.
371
283
 
372
- (b) Immediately call
373
- `pull_request_review_write(method="resolve_thread",
374
- threadId=<loop_comment_index[finding_id].thread_node_id>,
375
- owner=<owner>, repo=<repo>, pullNumber=<pr_number>)` for the
376
- same thread (this is the PR review thread node ID —
377
- `PRRT_kwDOxxx` — distinct from the numeric comment ID; the
378
- AUDIT step captures it at audit time when calling
379
- `get_review_comments` and stores it on each
380
- `loop_comment_index` entry alongside `finding_comment_id`).
381
-
382
284
  Update state: last_action="fixed". Append
383
285
  `<N> fix: <short_sha> — <fixed>/<could_not_address>/<hook_blocked>`
384
286
  to audit_log.
@@ -443,7 +345,7 @@ Delete the resolved `<qbug_temp_dir>` tree and any `.qbug-*.md` temp files in th
443
345
  - **No loop cap.** Cycle runs until `converged`, `stuck`, or `error`. User can interrupt.
444
346
  - **Code rules gate before every AUDIT.** Same `validate_content` logic as /bugteam.
445
347
  - **One commit per FIX action.** Linear branch, fast-forward push only.
446
- - **Categories A–N.** Same rubric as [`bugteam/PROMPTS.md`](../bugteam/PROMPTS.md).
348
+ - **Categories A–P.** Same rubric as [`bugteam/PROMPTS.md`](../bugteam/PROMPTS.md).
447
349
  - **One review per loop.** Anchored findings as `comments[]`; unanchored findings surface in the calling skill's user-facing output (chat reply to the user) rather than in the PR review body.
448
350
  - **PR description rewrite on every exit**, same as /bugteam Step 4.5.
449
351
  - **Temp file cleanup on every exit path.**
@@ -1,6 +1,6 @@
1
1
  """Tests verifying the shared audit contract and qbug's reference to it.
2
2
 
3
- The contract lives in bugteam/reference/audit-contract.md and is the single
3
+ The contract lives in _shared/pr-loop/audit-contract.md and is the single
4
4
  source of truth for finding schema, proof-of-absence shape, adversarial pass,
5
5
  Haiku secondary, and de-dup/merge rules. qbug/SKILL.md must reference it.
6
6
  """
@@ -12,7 +12,7 @@ from pathlib import Path
12
12
 
13
13
  SKILL_FILE_PATH = Path(__file__).parent / "SKILL.md"
14
14
  CONTRACT_FILE_PATH = (
15
- Path(__file__).parent.parent / "bugteam" / "reference" / "audit-contract.md"
15
+ Path(__file__).parents[2] / "_shared" / "pr-loop" / "audit-contract.md"
16
16
  )
17
17
  CATEGORY_E_RUBRIC_FILE_PATH = (
18
18
  Path(__file__).parent.parent.parent
@@ -76,7 +76,7 @@ def test_should_require_loop_n_diagnostics_json() -> None:
76
76
 
77
77
  def test_contract_should_require_all_eight_source_keys_in_diagnostics() -> None:
78
78
  contract_path = (
79
- Path(__file__).parent.parent / "bugteam" / "reference" / "audit-contract.md"
79
+ Path(__file__).parents[2] / "_shared" / "pr-loop" / "audit-contract.md"
80
80
  )
81
81
  contract_text = contract_path.read_text(encoding="utf-8")
82
82
  required_keys = [
@@ -0,0 +1,96 @@
1
+ ---
2
+ name: reviewer-gates
3
+ description: >-
4
+ Runs the availability gates a PR-loop orchestrator checks before engaging an
5
+ external reviewer: the CLAUDE_REVIEWS_DISABLED opt-out parse (bugbot,
6
+ bugteam, and copilot tokens via reviews_disabled.py), the once-per-run
7
+ Copilot premium-quota pre-check (copilot_quota.py with copilot_down
8
+ semantics), and the Cursor Bugbot trigger/acknowledge/CI-detect flow
9
+ (check_bugbot_ci.py with the literal `bugbot run` comment). Invoked by
10
+ PR-loop orchestrators — pr-converge, autoconverge, bugteam, qbug, findbugs,
11
+ copilot-review, monitor-open-prs — at run start and at each reviewer
12
+ engagement point. Not a general code-review skill; it decides whether a
13
+ reviewer runs, never what the reviewer finds.
14
+ ---
15
+
16
+ # Reviewer Gates
17
+
18
+ **Core principle:** one place decides whether an external reviewer is engaged. A caller never hand-parses `CLAUDE_REVIEWS_DISABLED`, never re-queries Copilot quota mid-run, and never invents a Bugbot trigger phrase.
19
+
20
+ ## How callers invoke this
21
+
22
+ - **Skill-capable contexts** (a lead session with the `Skill` tool): `Skill({skill: "reviewer-gates", args: "--skill <caller> <gate> [gate parameters]"})`.
23
+ - **Fallback** (a subagent or teammate without the `Skill` tool): the caller's spawn prompt says "Read `~/.claude/skills/reviewer-gates/SKILL.md` and apply the `<gate>` section with the parameters below."
24
+
25
+ Every invocation carries the caller's identity (`--skill <caller>`, e.g. `pr-converge`, `qbug`). The refusal line in Gate 1 and every logged decision names the caller, so a multi-skill session's transcript shows which loop each gate served.
26
+
27
+ ## Gate 1: Reviewer opt-out (`CLAUDE_REVIEWS_DISABLED`)
28
+
29
+ The `CLAUDE_REVIEWS_DISABLED` environment variable is a comma-separated token list (case-insensitive, whitespace-tolerant). Three tokens exist:
30
+
31
+ | Token | Disables |
32
+ |---|---|
33
+ | `bugteam` | The whole bug-audit family: `/bugteam`, `/qbug`, `/findbugs`, and audit dispatch in `/monitor-open-prs` |
34
+ | `bugbot` | Cursor Bugbot triggering and polling |
35
+ | `copilot` | GitHub Copilot review requests and polling |
36
+
37
+ Run the shared parser — never an inline shell parse:
38
+
39
+ ```bash
40
+ python "$HOME/.claude/_shared/pr-loop/scripts/reviews_disabled.py" --reviewer <bugbot|bugteam|copilot>
41
+ ```
42
+
43
+ - **Exit 0** — the named reviewer is opted out. A skill whose whole run depends on that reviewer responds with its refusal line and stops. The template: `/<caller> is disabled via CLAUDE_REVIEWS_DISABLED.` A loop that merely includes the reviewer as one gate marks the reviewer down (`bugbot_down = true`, `copilot_down = true`) and continues on its remaining signals.
44
+ - **Exit 1** — the reviewer is available; continue.
45
+
46
+ ## Gate 2: Copilot quota pre-check (once per run)
47
+
48
+ At run start — before any Copilot request, poll, or agent spawn — run:
49
+
50
+ ```bash
51
+ python "$HOME/.claude/_shared/pr-loop/scripts/copilot_quota.py"
52
+ ```
53
+
54
+ It resolves the configured GitHub account, reads the remaining Copilot premium-request quota via `gh api copilot_internal/user`, and prints one line. Log that line.
55
+
56
+ - **Exit 0** — Copilot has quota. Leave `copilot_down` false (or pass `copilotDisabled: false` to a workflow).
57
+ - **Any non-zero exit** — skip Copilot for the whole run: the account is out of quota, the quota API or account access is down, or no account is set. Set `copilot_down = true` (or `copilotDisabled: true`). The no-account line names the exact `.env` path and key to set; the account comes from the `COPILOT_QUOTA_ACCOUNT` environment variable or a git-ignored `.env` file.
58
+
59
+ Run the pre-check once per run, not per tick or per round. Every later tick reads the stored flag. While `copilot_down` is true:
60
+
61
+ - Skip every Copilot fetch, request, poll, and agent spawn outright.
62
+ - Export `CLAUDE_REVIEWS_DISABLED="copilot"` in the shell of any convergence check (`check_convergence.py`), so the check bypasses its Copilot review gate and pending-requested-reviews gate and the run still marks ready on the remaining signals.
63
+
64
+ `reviewer_availability.py` (same directory) is the single entry point when a caller wants one command answering "may reviewer X be engaged?" — it composes the opt-out parse and, for Copilot, the quota check: exit 0 to engage, non-zero to skip.
65
+
66
+ ## Gate 3: Bugbot trigger, acknowledge, and CI-detect
67
+
68
+ Cursor Bugbot signals through CI check runs, not always through a posted review. The decision tree runs against `<current_head>` with `check_bugbot_ci.py` (installed at `$HOME/.claude/skills/pr-converge/scripts/check_bugbot_ci.py`; `--help` documents every mode):
69
+
70
+ 1. **Silent-pass pre-check (always first).**
71
+ `python "$HOME/.claude/skills/pr-converge/scripts/check_bugbot_ci.py" --check-clean --owner <O> --repo <R> --sha <current_head>`
72
+ - Exit 0 — Bugbot CI completed with a `success`/`neutral` conclusion and posted no review: a silent pass. Record `bugbot_clean_at = <current_head>` and stop; do not trigger.
73
+ - Exit 1 (not a silent pass) or exit 2 (gh CLI error, silent pass not confirmable) — continue.
74
+ 2. **Already-queued check.**
75
+ `... check_bugbot_ci.py --check-active --owner <O> --repo <R> --sha <current_head>`
76
+ - Exit 0 — Bugbot is already queued on this commit. Skip posting; wait for completion (callers schedule their own wakeup).
77
+ - Exit 1 — continue.
78
+ 3. **Trigger.** Post exactly `bugbot run` as an issue comment (`add_issue_comment`) — no `@cursor[bot]` mention, no other text. `bugbot run` is empirically the only re-trigger Cursor Bugbot recognizes; every other phrasing silently no-ops. Wait 8 seconds with an in-turn Monitor delay, never a foreground `sleep` (blocked in headless runs).
79
+ 4. **Acknowledge check.**
80
+ `... check_bugbot_ci.py --owner <O> --repo <R> --sha <current_head>`
81
+ - Exit 0 — a check run is present: record `bugbot_acknowledged_at = <now, ISO 8601>`; the caller polls on its own cadence.
82
+ - Exit non-zero — Bugbot is down: set `bugbot_down = true` and route past the Bugbot phase; the run continues on its remaining signals.
83
+
84
+ The silent-pass pre-check runs first so a bot that already finished cleanly is never re-prompted — Bugbot refuses to re-run on an evaluated commit, and without the pre-check the acknowledge step would falsely mark `bugbot_down = true`.
85
+
86
+ **Flag reset rule:** `bugbot_down` resets to false whenever `<current_head>` changes — a new HEAD invalidates the old down-detection. `copilot_down` never resets mid-run; it holds until the run ends.
87
+
88
+ ## Gotchas
89
+
90
+ - **`bugbot run` is load-bearing text.** Alternative phrasings (`@cursor run`, `cursor review`, `bugbot please`) return no error and do nothing.
91
+ - **A skipped gate is a decision, not an omission.** When `copilot_down` or `bugbot_down` short-circuits a phase, record the flag and the exit line that set it — a convergence report that cannot show why a reviewer was skipped is incomplete.
92
+ - **The opt-out gate re-runs at every reviewer entry point;** the quota pre-check runs once per run. Confusing the two either re-spends quota-API calls per tick or misses a mid-run opt-out.
93
+
94
+ ## Folder map
95
+
96
+ - `SKILL.md` — this file; the skill ships no scripts of its own. Gate scripts live in `_shared/pr-loop/scripts/` (`reviews_disabled.py`, `copilot_quota.py`, `reviewer_availability.py`) and `pr-converge/scripts/` (`check_bugbot_ci.py`).
@@ -1,12 +1,12 @@
1
1
  # session-log
2
2
 
3
- Logs a session report as a gallery-shaped HTML file in the Obsidian vault, auto-publishes it as a secret gist, extracts unrecorded decisions, tidies the project session folder, and outputs a `/rename` command.
3
+ Logs a session report as a self-contained HTML page in the Obsidian vault, publishes it with the `Artifact` tool, extracts unrecorded decisions, tidies the project session folder, and outputs a `/rename` command.
4
4
 
5
5
  **Trigger:** `/session-log`, "journal this session", "log this work", "session report", "save session", "capture session", "document what we did".
6
6
 
7
7
  ## Purpose
8
8
 
9
- Produces a self-contained HTML session report shaped to the session's character (feature build, incident, research, etc.) rather than a fixed template. The skill owns the vault path, session numbering, frontmatter contract, decision extraction, and folder hygiene; it delegates HTML authorship to `doc-gist`.
9
+ Produces a self-contained HTML session report shaped to the session's character (feature build, incident, research, etc.) rather than a fixed template. The skill owns the vault path, session numbering, frontmatter contract, HTML composition and publishing, decision extraction, and folder hygiene.
10
10
 
11
11
  ## Key files
12
12
 
@@ -18,14 +18,14 @@ Produces a self-contained HTML session report shaped to the session's character
18
18
 
19
19
  1. **Backend detection** — headless vault (`ob --version` + `OBSIDIAN_VAULT_PATH`) then local vault (`~/.claude/vault/`). Session number from `[N]. *.html` and `[N]. *.md` files in the project folder.
20
20
  2. **Session metadata** — project name, session number, session ID from `CLAUDE_CODE_SESSION_ID`, date, title.
21
- 3. **HTML via doc-gist shape principles** — gallery-anchored design (e.g., `17-pr-writeup.html` for feature builds, `12-incident-report.html` for incidents). `<!-- @publish-as-gist -->` marker triggers auto-publish hook on Write/Edit.
22
- 4. **Vault context tracking** — two Edit calls set `vault_context_retrieved` and append a vault-context line. The URL from the final Edit is canonical.
21
+ 3. **Compose and publish via the Artifact tool** — loads the `artifact-design` skill first, designs the shape for the session's character (e.g., a PR-writeup shape for feature builds, a timeline shape for incidents), writes the HTML, then publishes it with the `Artifact` tool using the fixed favicon `📓`.
22
+ 4. **Vault context tracking** — two Edit calls set `vault_context_retrieved` and append a vault-context line, then redeploy via `Artifact` on the same `file_path` so the URL stays the same.
23
23
  5. **Decision extraction** — scans conversation for unrecorded decisions; prompts user via `AskUserQuestion` before invoking `/remember`.
24
- 6. **Session tidy** — audits `.html` files in the project folder for naming and frontmatter; auto-fixes minor issues.
24
+ 6. **Session tidy** — audits `.html` files in the project folder for naming and frontmatter; auto-fixes minor issues and redeploys via `Artifact`.
25
25
 
26
26
  ## Conventions
27
27
 
28
- - The `<!-- @publish-as-gist -->` marker must appear exactly as shown; each Edit re-fires the hook and produces a new gist ID.
29
- - Session reports use HTML; `.md` paths are blocked by `md_to_html_blocker` for session paths.
28
+ - Session reports use HTML the Artifact tool publishes HTML or Markdown, and HTML gives the report designer more visual structure.
30
29
  - `write_existing_file_blocker` rejects Write on existing paths — use Edit for all vault-context updates.
30
+ - The `Artifact` tool redeploys to the same URL on repeat calls with the same `file_path` within the current run — edits made in steps 3 and 5 to the session created this run never mint a new URL.
31
31
  - Final step copies `/rename [Project] - [Primary Outcome]` to the clipboard via `pwsh Set-Clipboard`.
@@ -1,44 +1,30 @@
1
1
  ---
2
2
  name: session-log
3
3
  description: >-
4
- Log a session report by handing the HTML authorship to doc-gist (which designs fresh per session and auto-publishes via the `<!-- @publish-as-gist -->` marker hook), then track vault context, extract unrecorded decisions, tidy the project's session folder, and output a /rename command. Use when the user says /session-log, journal this session, log this work, session report, or any variation of "summarize/log/record this session". Also triggers on "save session", "capture session", or "document what we did".
4
+ Log a session report by composing a self-contained HTML page and publishing it with the Artifact tool, then track vault context, extract unrecorded decisions, tidy the project's session folder, and output a /rename command. Use when the user says /session-log, journal this session, log this work, session report, or any variation of "summarize/log/record this session". Also triggers on "save session", "capture session", or "document what we did".
5
5
  ---
6
6
 
7
7
  # Session Log
8
8
 
9
9
  ## Overview
10
10
 
11
- The HTML artifact is doc-gist's job end-to-end. Session-log owns everything around it: where the file lives in the vault, what number it gets, the frontmatter metadata contract, post-write vault tracking, decision extraction, project-folder hygiene, and the closing `/rename` hand-off.
11
+ Session-log composes the HTML report and publishes it directly with the `Artifact` tool. The skill owns the whole flow: where the file lives in the vault, what number it gets, the frontmatter metadata contract, HTML composition and publishing, post-write vault tracking, decision extraction, project-folder hygiene, and the closing `/rename` hand-off.
12
12
 
13
13
  **Announce at start:** "I'm logging this session."
14
14
 
15
- ## Why this skill delegates HTML to doc-gist
15
+ ## Why this report is designed fresh per session
16
16
 
17
- Sessions come in many shapes — convergence loops, feature builds, research dives, incidents, refactors, decisions. A single h2-emoji-list template forces every session into the same form regardless of fit, and the artifact reads as a process log rather than a substance log. Doc-gist's principle: *"design fresh per request, drawing on a gallery of 20 HTML shape patterns."* Each session report gets the shape that fits the session.
18
-
19
- The gallery lives at `~/.claude/skills/doc-gist/references/examples/`. Patterns that usually fit session reports:
20
-
21
- | Session character | Gallery shape to study |
22
- |---|---|
23
- | Feature build / PR ships | `17-pr-writeup.html` |
24
- | Incident, debugging arc, convergence loop | `12-incident-report.html` |
25
- | Status update / weekly progress | `11-status-report.html` |
26
- | Implementation plan or decision record | `16-implementation-plan.html` |
27
- | Exploration of multiple approaches | `01-exploration-code-approaches.html` |
28
- | Code-explainer with module map | `04-code-understanding.html` |
29
-
30
- The session designer reads the matching gallery file, then designs the report in that shape. **Adapt, do not copy.**
17
+ Sessions come in many shapes — convergence loops, feature builds, research dives, incidents, refactors, decisions. A single h2-emoji-list template forces every session into the same form regardless of fit, and the artifact reads as a process log rather than a substance log. Load the `artifact-design` skill before composing any page content — it calibrates the design investment and shape to the session's character: a feature build reads naturally as a PR writeup, an incident or convergence loop as a timeline, a status update as a progress summary, a plan or decision as a decision record, an exploration as a multi-approach walkthrough.
31
18
 
32
19
  ## Gotchas
33
20
 
34
- - **Doc-gist's auto-publish hook fires on Write/Edit of any HTML containing `<!-- @publish-as-gist -->`.** Session-log composes the HTML with the marker so auto-publish runs by default sessions are intended for sharing with collaborators. The hook prints the gist + preview URLs to tool output; capture both.
35
- - **`gh` must be authenticated.** Auto-publish runs `gh gist create`. If `gh` is unauthenticated, `gh gist create` writes its error message; `gist_upload.py` surfaces it from stderr when present and falls back to stdout when stderr is empty (so the error always appears somewhere in the tool result). The hook exits 0 (does not block the Write). Look at the full tool result, then surface the error to the user; the local vault HTML is still the canonical artifact, so the remaining steps still run.
36
- - **Vault paths sit outside `.claude/`.** Headless vault paths (e.g., `$OBSIDIAN_VAULT_PATH`) resolve outside the project tree. The `md_to_html_blocker` PreToolUse hook blocks `.md` writes unless the path is exempt exemptions include any path containing `/.claude/` and README/CHANGELOG files at repo root. Session reports use HTML, which the hook ignores entirely.
21
+ - **Load the `artifact-design` skill before writing page content.** The `Artifact` tool needs this step first it is not optional polish.
22
+ - **The `Artifact` tool wraps the file in a document skeleton at publish time.** It adds `<!doctype html>…<head>…</head><body>` around whatever the file holds write page content only (a `<title>`, a `<style>` block, and the body markup). Do not include `<!DOCTYPE>`, `<html>`, `<head>`, or `<body>` tags in the file itself.
23
+ - **The `Artifact` tool redeploys to the same URL only within the current run.** Editing the session's HTML file in a later step of this same skill run and calling `Artifact` again does not mint a new URL — it updates the same published page in place. A fresh session has no memory of an artifact's URL from an earlier run, so republishing a session report written in a prior session always mints a new URL (there is no other way to target the old one without the user supplying it).
24
+ - **Vault paths sit outside `.claude/`.** Headless vault paths (e.g., `$OBSIDIAN_VAULT_PATH`) resolve outside the project tree. Session reports use HTML regardless of vault location — the Artifact tool needs a written file to publish.
37
25
  - **Sessions describe current state by convention.** The state_description_blocker hook does not scan .html, but the rule at `~/.claude/rules/no-historical-clutter.md` applies as a writing standard — skip historical and comparative language when composing the report; the rule file lists the full trigger set.
38
26
  - **`write_existing_file_blocker` rejects Write on existing paths.** Use Write only when creating a fresh session report; use Edit for the vault-context append in step 3.
39
- - **Each Write/Edit of the marked HTML creates a fresh gist with a new ID.** `gist_upload.py` calls `gh gist create` with no lookup of any prior gist. Step 3 performs two Edits and Step 5's tidy may Edit the current session a third time — each Edit produces a different gist URL than its predecessor. Quote the URLs from the FINAL publish (the most recent auto-publish run for the session being created — the second Step-3 Edit when Step 5 does not touch the current session, or the Step 5 Edit when it does) to the user; never embed a URL inside the HTML that a later Edit then re-publishes.
40
27
  - **Obsidian frontmatter index is HTML-blind.** Obsidian's native YAML-frontmatter parser reads only `.md` files. HTML files do not appear in Obsidian's frontmatter index. Search by content still works; search by `type: session-report` does not.
41
- - **Auto-published gists carry the default `gist_upload.py` description (`HTML artifact`), not a session-specific title.** The auto-publish hook invokes `gist_upload.py` with only `--input` and `--no-open` — it has no session-title context to pass as `--description`. Browsing or sharing gists, operators see "HTML artifact" rather than `Session [N] — [Title] — session-log — [Project]`. Workaround: after the canonical Edit completes, edit the existing gist's description in place with `gh gist edit <gist-id> --desc "Session [N] — [Title] — session-log — [Project]"` (this updates the existing gist's metadata; no new gist ID is created) if a meaningful title matters for that share. The HTML frontmatter inside the file remains the authoritative session metadata regardless of the gist's external description.
42
28
 
43
29
  ## Backend Detection (run before Step 1)
44
30
 
@@ -87,27 +73,25 @@ tags: [session, [project-tag], [topic-tags]]
87
73
 
88
74
  Every session report carries this metadata block verbatim so vault search and the tidy step in step 5 work. **Initial values for Step 2's Write:** substitute concrete values for every placeholder — for `session_id`, write the value read from `CLAUDE_CODE_SESSION_ID` in step 1 (or `unknown` when the variable is unset); for `vault_context_retrieved`, write the literal value `false` (the safe default before Step 3's vault-MCP-tool scan completes). Step 3 then Edits `vault_context_retrieved` to `true` if any of the three vault MCP tools fired this session.
89
75
 
90
- ## Step 2: Compose the HTML via doc-gist's shape principles
76
+ ## Step 2: Compose and Publish the HTML via the Artifact Tool
91
77
 
92
- Design the artifact for **this session's character**, drawing on the doc-gist gallery patterns listed above. The report must answer for a cold reader, from the H2 headers alone, three questions: *what shipped*, *why it matters*, *what impact it had*. Process narration (commit-by-commit walks, agent gotchas, retry counts) belongs at the end, not in the opening sections.
78
+ Load the `artifact-design` skill before writing any content. Design the artifact for **this session's character** a feature build reads naturally as a PR writeup, an incident or convergence loop as a timeline, a status update as a progress summary, a plan or decision as a decision record, an exploration as a multi-approach walkthrough. The report must answer for a cold reader, from the section headers alone, three questions: *what shipped*, *why it matters*, *what impact it had*. Process narration (commit-by-commit walks, agent gotchas, retry counts) belongs at the end, not in the opening sections.
93
79
 
94
- **Required somewhere in the HTML (commonly in `<head>`):** the auto-publish marker.
80
+ **Required as the first content line:** the frontmatter HTML comment from step 1.
95
81
 
96
- ```html
97
- <!-- @publish-as-gist -->
98
- ```
82
+ **Required somewhere in the content:** a `<title>` element naming the session — it names the browser tab and the artifact gallery entry.
99
83
 
100
- The marker triggers the PostToolUse hook after Write or Edit the hook scans the entire HTML for the literal sentinel string and uploads the file to a secret gist, then prints the gist + preview URLs to your tool output. The marker must be the literal comment text exactly; whitespace inside breaks it.
84
+ **Required as the first content section (after the frontmatter comment):** an opening "What this session shipped" paragraph + bullets written so a reader with zero prior context understands the outcome. For continuation sessions (where the substantive work landed in a prior session), recap the parent session's outcome briefly so the report stands alone.
101
85
 
102
- **Required at the top of `<body>`:** the frontmatter HTML comment from step 1.
86
+ **Required: self-contained, responsive, theme-aware HTML.** Inline all CSS in a `<style>` block and all JS inline; embed any images as data URIs — the `Artifact` tool's content security policy blocks external CDN scripts, stylesheets, fonts, and network requests. Use relative units so the layout holds at any width, and support both light and dark via `prefers-color-scheme` (or `:root[data-theme]` overrides).
103
87
 
104
- **Required as the first content section:** an opening "What this session shipped" paragraph + bullets — written so a reader with zero prior context understands the outcome. For continuation sessions (where the substantive work landed in a prior session), recap the parent session's outcome briefly so the report stands alone.
88
+ **No document wrapper tags.** The `Artifact` tool wraps the file content in a `<!doctype html>…<head>…</head><body>` skeleton at publish time write the `<title>`, `<style>`, and body markup directly, with no `<!DOCTYPE>`, `<html>`, `<head>`, or `<body>` tags of your own.
105
89
 
106
- **Required: self-contained HTML.** Embed all styles in a `<style>` block inside `<head>` (inline `style="..."` attributes are also fine if preferred); no `./relative/paths` to local assets. Doc-gist's transport sends a single HTML file with no neighbors, so any relative-path reference (CSS, JS, images) cannot resolve and the asset will be missing from the preview. Absolute external URLs (CDN-hosted assets, image hotlinks) work but add an external dependency the report should not need — design the report to stand alone with no external dependencies.
90
+ Beyond those requirements, design the shape that fits the session the `artifact-design` skill's guidance covers typography, palette, and layout choices.
107
91
 
108
- Beyond those four requirements, design the shape that fits. A convergence loop session reads naturally as an incident timeline (`12-incident-report.html`); a feature build reads as a PR writeup (`17-pr-writeup.html`); a research session reads as a feature explainer (`14-research-feature-explainer.html`). Read the matching gallery entry for typography, palette, spatial idioms — adapt, do not copy.
92
+ **Write the file** via the Write tool to the vault path. Create the project directory via `mkdir -p` if it does not exist.
109
93
 
110
- **Write the file** via the Write tool to the vault path. Create the project directory via `mkdir -p` if it does not exist. The auto-publish hook fires after the Write completes and prints a gist + preview URL pair to tool output (the bare preview URL on stdout; both labeled `Gist: <url>` and `Preview: <url>` lines on stderr — both streams appear in the agent's tool-result). Step 3 performs **two Edit calls** and each one re-fires the hook with a fresh URL pair — only the URL pair from the second (final) Step-3 Edit is canonical for the just-created session (the step-2 pair and the first step-3 pair are orphaned the moment the next Edit lands). Always quote the URL pair from the **most recent auto-publish run for the session being created**. Note: Step 5's tidy audits every `.html` file in the project folder including the just-created session, so if Step 5's frontmatter auto-fix touches the current session, the Step 5 republish URL pair becomes the new canonical pair for that session (re-quote it to the user with a "Session republished — new preview: <url>" line). The second Step-3 Edit's URL pair stays canonical only when Step 5 does not touch the current session.
94
+ **Publish the file** by calling the `Artifact` tool with `file_path` set to the vault path just written, `favicon` set to the fixed session-log favicon `📓` this favicon stays the same across every session-log report so the series reads as one consistent collection; never swap it per session and `description` set to a one-sentence subtitle summarizing the session. Capture the returned URL: it is the canonical URL for this session report, and it stays the same across every later `Artifact` call on this same `file_path` within the current run (steps 3 and 5 redeploy to it rather than minting a new one).
111
95
 
112
96
  **If the Write fails**, output the HTML content in the conversation so the user can copy it manually. Before emitting the HTML to chat, resolve the `vault_context_retrieved` placeholder to `true` or `false` based on the same vault-MCP-tool scan that Step 3 would have run, and include the matching vault-context `<li>` line (Retrieved or Not retrieved) so the emitted HTML is a valid copy-paste artifact with complete frontmatter. Skip Step 3 and continue at step 4.
113
97
 
@@ -121,10 +105,10 @@ Review the conversation history for any use of these vault MCP tools (look only
121
105
  - `mcp__obsidian__read_note`
122
106
  - `mcp__obsidian__read_multiple_notes`
123
107
 
124
- Edit the vault HTML via two Edit calls (each Edit re-fires the auto-publish hook and creates a fresh gist; **the URL pair from the second/final Edit is canonical** — the first Edit's URLs are orphaned the moment the second Edit lands):
108
+ Edit the vault HTML via two Edit calls:
125
109
 
126
110
  1. Set the frontmatter `vault_context_retrieved` field to `true` when any of the three tools fired this session, `false` otherwise.
127
- 2. Append one fact — vault-context status — into whatever section the report designer placed for notes / metadata / references. If the report has no such section, append a fresh `<h2>Notes</h2>` block before `</body>`:
111
+ 2. Append one fact — vault-context status — into whatever section the report designer placed for notes / metadata / references. If the report has no such section, append a fresh `<h2>Notes</h2>` block at the end of the content:
128
112
 
129
113
  ```html
130
114
  <h2>Notes</h2>
@@ -137,7 +121,7 @@ Edit the vault HTML via two Edit calls (each Edit re-fires the auto-publish hook
137
121
 
138
122
  If the report already has a notes / references section, use Edit to insert one matching child element at the end of that section. The element shape mirrors whatever the section already uses: an extra `<li>` before the closing `</ul>` for a list, an extra `<dt>Vault context</dt><dd>…</dd>` pair before the closing `</dl>` for a description list, an extra `<p><strong>Vault context:</strong> …</p>` before the section's closing tag for a paragraph-based section. Pick the form that matches the surrounding markup.
139
123
 
140
- The gist URL stays out of the HTML body on purpose: each Edit re-fires the auto-publish hook and produces a brand-new gist ID, so any URL embedded in the file becomes stale the instant the next Edit lands. The canonical gist + preview URL is the pair from **the most recent auto-publish run that touched the current session report** — typically the second (final) Step-3 Edit, but the Step 5 Edit takes over as canonical when Step 5's frontmatter auto-fix edits the current session (re-quote the Step 5 pair with a "Session [N] republished — new preview: <url>" line per the Step 2 guidance at line 107). Quote whichever pair is most recent when announcing the report.
124
+ After both Edits land, call the `Artifact` tool again with the same `file_path` and the same `favicon` used in step 2 to redeploy the updated content. This updates the URL captured in step 2 in place; no new URL is minted.
141
125
 
142
126
  ## Step 4: Decision Extraction
143
127
 
@@ -160,7 +144,7 @@ Scope: the current project's session folder only.
160
144
  - Missing frontmatter fields that can be inferred (e.g., `blocked: false` when status is `completed`; `vault_context_retrieved: false` when the field is absent, since the field defaults to false in pre-existing sessions)
161
145
  - `type` field set to a wrong value (correct to `session-report`)
162
146
 
163
- Each Edit on a marked HTML file re-fires doc-gist's auto-publish hook and produces a fresh gist + preview URL pair in the agent's tool output (the bare preview URL on stdout; both labeled `Gist: <url>` and `Preview: <url>` lines on stderr) — the prior gist URL becomes orphaned. Surface a `Session [N] republished new preview: <url>` line per Edit so the user can update any prior shares.
147
+ When the Edit touches the session report created in this run, call `Artifact` again with the same `file_path` and `favicon` from step 2 to redeploy — the URL captured in step 2 stays unchanged. When the Edit touches an older session report published in a prior run, call `Artifact` on that `file_path` with no `url` argument, since this skill keeps no record of that file's earlier URL this publishes the older report at a new URL. Surface a `Session [N] republished at a new URL: <url>` line so the user can update any prior shares.
164
148
  4. **Report issues that need user input:**
165
149
  - Files with wrong naming convention (propose new name)
166
150
  - Stale statuses (propose update to `completed` or ask)
@@ -190,14 +174,13 @@ The primary outcome comes from the session title resolved in step 1.
190
174
 
191
175
  - [ ] Backend detected and announced
192
176
  - [ ] Session number resolved from `[N]. *.html` and `[N]. *.md` files (both parsed to preserve sequence across the format migration)
193
- - [ ] HTML composed via doc-gist's shape principles (gallery-anchored)
194
- - [ ] `<!-- @publish-as-gist -->` marker present somewhere in the HTML
195
- - [ ] Frontmatter HTML comment present at top of `<body>`
177
+ - [ ] `artifact-design` skill loaded before composing page content
178
+ - [ ] HTML composed for this session's character (no document wrapper tags; self-contained, responsive, theme-aware)
179
+ - [ ] Frontmatter HTML comment present as the first content line
196
180
  - [ ] `session_id` frontmatter field set from `CLAUDE_CODE_SESSION_ID` (the authoring agent's own session), or `unknown` when the variable is unset
197
181
  - [ ] Opening section answers "what shipped / why / impact" for a cold reader
198
- - [ ] Self-contained HTML (no relative-path asset refs; avoid external dependencies)
199
- - [ ] Auto-publish URLs captured from step 2 and step 3 (or HTML emitted to chat when step 2 Write failed)
200
- - [ ] Vault-context line appended via Edit (step 3); URL pair from the most recent auto-publish run for the current session quoted to the user (typically the final Step-3 Edit, but the Step 5 republish takes over when Step 5 edits the current session)
182
+ - [ ] Published via the `Artifact` tool with the fixed favicon `📓`; URL captured (or HTML emitted to chat when step 2 Write failed)
183
+ - [ ] Vault-context line appended via Edit (step 3); `Artifact` redeployed on the same URL
201
184
  - [ ] Decision extraction surfaced any unrecorded items
202
185
  - [ ] Session tidy reported anomalies or stayed silent
203
186
  - [ ] `/rename` command copied to clipboard via `pwsh Set-Clipboard`