@agentsfleet/orly 0.5.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 (112) hide show
  1. package/.githooks/pre-commit +42 -0
  2. package/.githooks/pre-push +67 -0
  3. package/AGENTS.md +348 -0
  4. package/LICENSE +21 -0
  5. package/README.md +249 -0
  6. package/SOUL.md +90 -0
  7. package/audits/agents-md.md +497 -0
  8. package/audits/agents-md.sh +353 -0
  9. package/audits/cross-tier-rates.sh +105 -0
  10. package/audits/data.sh +185 -0
  11. package/audits/deinit-pairs.sh +224 -0
  12. package/audits/design-tokens.sh +143 -0
  13. package/audits/doc-read.sh +183 -0
  14. package/audits/error-codes.sh +221 -0
  15. package/audits/fixtures/clean.diff +15 -0
  16. package/audits/fixtures/dirty.diff +16 -0
  17. package/audits/lifecycle-anchors.sh +22 -0
  18. package/audits/logging.sh +217 -0
  19. package/audits/msid-ui.sh +144 -0
  20. package/audits/parity-dispatch.sh +51 -0
  21. package/audits/rule-ledger-lib.sh +264 -0
  22. package/audits/rule-ledger.sh +225 -0
  23. package/audits/rule-paths.sh +108 -0
  24. package/audits/spec-template.sh +258 -0
  25. package/audits/sql-mod.sh +102 -0
  26. package/audits/ufs.sh +303 -0
  27. package/bin/orly +26 -0
  28. package/core/operating-model.md +256 -0
  29. package/dispatch/edit_rules.md +69 -0
  30. package/dispatch/lib.sh +213 -0
  31. package/dispatch/lifecycle.md +187 -0
  32. package/dispatch/name_architecture.md +93 -0
  33. package/dispatch/verify.md +111 -0
  34. package/dispatch/write_any.md +740 -0
  35. package/dispatch/write_any.sh +49 -0
  36. package/dispatch/write_auth.md +36 -0
  37. package/dispatch/write_changelog.md +64 -0
  38. package/dispatch/write_documentation.md +45 -0
  39. package/dispatch/write_go.md +24 -0
  40. package/dispatch/write_http.md +45 -0
  41. package/dispatch/write_mdx.md +7 -0
  42. package/dispatch/write_python.md +8 -0
  43. package/dispatch/write_rust.md +38 -0
  44. package/dispatch/write_shell.md +8 -0
  45. package/dispatch/write_spec.md +105 -0
  46. package/dispatch/write_sql.md +112 -0
  47. package/dispatch/write_sql.sh +36 -0
  48. package/dispatch/write_ts_adhere_bun.md +493 -0
  49. package/dispatch/write_ts_adhere_bun.sh +37 -0
  50. package/dispatch/write_zig.md +852 -0
  51. package/dispatch/write_zig.sh +40 -0
  52. package/docs/CHANGELOG_VOICE.md +18 -0
  53. package/docs/DISPATCH_ARCHITECTURE.md +664 -0
  54. package/docs/DISPATCH_REVIEW_DISPOSITION.md +65 -0
  55. package/docs/DOCUMENTATION_RULES.md +209 -0
  56. package/docs/EXECUTE_DOC_READS.md +29 -0
  57. package/docs/HARNESS_VERIFY_OUTPUT.md +40 -0
  58. package/docs/LIFECYCLE_PATTERNS.md +316 -0
  59. package/docs/LOGGING_STANDARD.md +397 -0
  60. package/docs/ORLY_ARCHITECTURE.md +129 -0
  61. package/docs/REST_API_DESIGN_GUIDELINES.md +783 -0
  62. package/docs/RULE_ENFORCEMENT.md +41 -0
  63. package/docs/SCHEMA_CONVENTIONS.md +93 -0
  64. package/docs/TEMPLATE.md +411 -0
  65. package/docs/VERIFY_TIERS.md +57 -0
  66. package/docs/greptile-learnings/README.md +51 -0
  67. package/docs/greptile-learnings/RULES.md +1045 -0
  68. package/fixtures/registry-invalid.json +1 -0
  69. package/fixtures/registry-valid.json +18 -0
  70. package/fixtures/unclosed-pack-block.md +8 -0
  71. package/package.json +63 -0
  72. package/packs/language/go/rules.md +24 -0
  73. package/packs/language/mdx/rules.md +7 -0
  74. package/packs/language/python/rules.md +8 -0
  75. package/packs/language/rust/rules.md +38 -0
  76. package/packs/language/shell/rules.md +8 -0
  77. package/registry.json +405 -0
  78. package/schemas/evidence.schema.json +43 -0
  79. package/schemas/profile.schema.json +12 -0
  80. package/schemas/registry.schema.json +12 -0
  81. package/skills/orly-babysit-prs/SKILL.md +326 -0
  82. package/skills/orly-spec-new/SKILL.md +157 -0
  83. package/skills/orly-write-integration-test/SKILL.md +470 -0
  84. package/skills/orly-write-unit-test/SKILL.md +520 -0
  85. package/src/cli.test.ts +70 -0
  86. package/src/cli.ts +287 -0
  87. package/src/config.test.ts +226 -0
  88. package/src/config.ts +288 -0
  89. package/src/criteria.test.ts +137 -0
  90. package/src/criteria.ts +166 -0
  91. package/src/criteria_spec.ts +127 -0
  92. package/src/criteria_support.ts +53 -0
  93. package/src/gates.test.ts +183 -0
  94. package/src/gates.ts +169 -0
  95. package/src/gates_spec.test.ts +98 -0
  96. package/src/gates_test_support.ts +194 -0
  97. package/src/git_env.ts +20 -0
  98. package/src/install.test.ts +514 -0
  99. package/src/install.ts +447 -0
  100. package/src/install_nested.test.ts +32 -0
  101. package/src/model.test.ts +31 -0
  102. package/src/model.ts +245 -0
  103. package/src/references.test.ts +47 -0
  104. package/src/references.ts +147 -0
  105. package/src/render.test.ts +60 -0
  106. package/src/render.ts +94 -0
  107. package/src/surfaces.test.ts +43 -0
  108. package/src/surfaces.ts +89 -0
  109. package/src/validation.test.ts +11 -0
  110. package/src/validation.ts +87 -0
  111. package/src/verify.test.ts +13 -0
  112. package/src/verify.ts +59 -0
@@ -0,0 +1,326 @@
1
+ ---
2
+ name: orly-babysit-prs
3
+ description: |
4
+ Post-push follow-up for PRs/MRs: backoff-cadence polls over CI check runs
5
+ (fix every failure your diff caused), every greptile inline thread, and the
6
+ PR-level summary; classifies via gstack greptile-triage, suppresses via
7
+ greptile-history, stops after two consecutive empty polls with CI green.
8
+ Forge-aware (gh PR / glab MR). Use after `gh pr create` / `glab mr create`,
9
+ after every push to a branch with an open PR/MR, or on "babysit", "watch
10
+ greptile", "poll the PR/MR", "watch reviews", "follow up on review
11
+ feedback". Cross-agent: Claude, Codex, OpenCode, Amp.
12
+ ---
13
+
14
+ # orly-babysit-prs
15
+
16
+ Review bots (greptile on GitHub; greptile or another review bot on GitLab)
17
+ post auto-reviews **asynchronously**. They land as PR review comments / MR
18
+ discussion threads, not check runs, so `gh pr checks --watch` (or the glab
19
+ equivalent) doesn't observe them. Without explicit polling on a backoff
20
+ cadence, findings arrive after the human stops checking — so they get missed.
21
+
22
+ This skill is the **polling cadence + walk-every-review-thread loop**. The
23
+ fetch, classify, and reply mechanics live in gstack's `greptile-triage.md` —
24
+ open and follow it; do not paraphrase from memory. This skill never
25
+ duplicates the triage helper's logic; it adds (a) the cadence, (b) the
26
+ multi-thread walk, and (c) the **forge abstraction** so the same loop runs on
27
+ GitHub and GitLab.
28
+
29
+ ## STEP 0 — Open greptile-triage.md every cycle
30
+
31
+ Before doing anything else in a polling cycle, read the triage helper:
32
+
33
+ ```bash
34
+ GREPTILE_TRIAGE="$HOME/.local/share/gstack/review/greptile-triage.md"
35
+ [ -r "$GREPTILE_TRIAGE" ] || GREPTILE_TRIAGE="$HOME/Projects/dotfiles/.unified-skills/review/greptile-triage.md"
36
+ [ -r "$GREPTILE_TRIAGE" ] || { echo "BABYSIT: greptile-triage.md missing — abort cycle"; exit 1; }
37
+ ```
38
+
39
+ Then walk it section by section:
40
+
41
+ | Triage section | What this skill triggers |
42
+ |---|---|
43
+ | `## Fetch` | Run per detected review thread (multi-thread loop below), via the forge layer |
44
+ | `## Suppressions Check` | Read `$HOME/.gstack/projects/<slug>/greptile-history.md`; skip lines tagged `fp` matching `repo + file-pattern + category` |
45
+ | `## Classify` | Read file ±10 lines around each comment's `path:line`; classify VALID & ACTIONABLE / VALID BUT ALREADY FIXED / FALSE POSITIVE / SUPPRESSED |
46
+ | `## Reply APIs` | Tier 1 first response, Tier 2 on re-flag — via the forge layer |
47
+ | `## Reply Templates` | Use Tier 1 / Tier 2 template verbatim — do not invent new wording |
48
+ | `## Severity Assessment & Re-ranking` | Re-rank the bot's severity against the project's actual risk profile |
49
+ | `## History File Writes` | Append to BOTH per-project and global history files (see below) |
50
+ | `## Output Format` | Use the triage helper's report shape, augmented with our cadence line |
51
+
52
+ If the triage helper is missing on the host, abort with `BABYSIT: greptile-triage.md missing` rather than guessing — the abort is visible, a silent re-implementation is not.
53
+
54
+ ## STEP 0.5 — Detect the forge
55
+
56
+ `git remote` decides which CLI + review-object model to use. Everything
57
+ downstream branches on `$FORGE`.
58
+
59
+ ```bash
60
+ ORIGIN=$(git remote get-url origin 2>/dev/null)
61
+ case "$ORIGIN" in
62
+ *github.com*) FORGE=github ;;
63
+ *) FORGE=gitlab ;; # gitlab.com OR self-hosted (e.g. awakeninggit.e2enetworks.net)
64
+ esac
65
+ echo "BABYSIT: forge=$FORGE origin=$ORIGIN"
66
+ ```
67
+
68
+ | Concept | GitHub (`gh`) | GitLab (`glab`) |
69
+ |---|---|---|
70
+ | Change unit | Pull Request (PR) | Merge Request (MR) |
71
+ | Create cmd | `gh pr create` | `glab mr create` |
72
+ | Review object | a *review* with line comments | a *discussion* (thread) with notes |
73
+ | "walk every…" | every review id | every discussion thread id |
74
+ | Reply | reply to the review comment | post a note to the discussion |
75
+
76
+ Both forges' bots are filtered by author name matching `greptile` (or the
77
+ project's configured review bot — see the per-project history `bot:` note if
78
+ present).
79
+
80
+ ## STEP 0.75 — CI checks must go green (poll + fix)
81
+
82
+ Greptile is not the only async signal: the PR/MR's **CI check runs** land on
83
+ their own schedule and are part of "done". The loop is not finished until CI is
84
+ green **and** the review bot is quiet. This is the one place `gh pr checks`
85
+ (NOT `--watch`) is the right tool — it observes *check runs*, which is exactly
86
+ what CI is. (The "never `gh pr checks --watch` for greptile" rule stands:
87
+ greptile posts review comments, not checks, so `pr checks` never sees it. CI
88
+ jobs are the opposite — `pr checks` is precisely how you see them.)
89
+
90
+ Each cycle, after the review-thread walk, poll CI and act by cause:
91
+
92
+ ### GitHub
93
+
94
+ ```bash
95
+ gh pr checks "$PR_NUMBER" --json name,state,bucket,link 2>/dev/null \
96
+ | jq -r '.[] | "\(.bucket)\t\(.state)\t\(.name)\t\(.link)"' # bucket ∈ pass|fail|pending|skipping|cancel
97
+ ```
98
+
99
+ ### GitLab
100
+
101
+ ```bash
102
+ glab ci status 2>/dev/null \
103
+ || glab api "projects/$PROJ_ENC/merge_requests/$MR_IID/pipelines" \
104
+ | jq -r '.[0] | "\(.status)\t\(.web_url)"' # status ∈ success|failed|running|canceled|pending
105
+ ```
106
+
107
+ | CI state | Action |
108
+ |---|---|
109
+ | all `pass`/`skipping` (GitLab `success`) | Record `ci=green`. A done-declaration is now allowed (if greptile is also quiet). |
110
+ | any `pending`/`running` | Record `ci=pending`; re-poll on the cadence. **Never declare done while a check is still running.** |
111
+ | any `fail`/`cancel` **from your changes** | In-scope finding you OWN — treat like a greptile fix. Fetch the failing log (`gh run view <run-id> --log-failed`, run id from the check `link`; GitLab `glab ci trace <job-id>`), fix the code, re-verify with the relevant `make` target, commit, push, re-poll. |
112
+ | any `fail` **NOT from your changes** (pre-existing red, infra flake, unrelated job) | Surface to the user with job name + link. Do **not** fix blindly, do **not** edit CI config. Pause the done-declaration until they decide. |
113
+
114
+ CI failures caused by your commit are not "surface and wait" — they are the
115
+ same contract as a greptile P0: diagnose, fix the code (never the CI config),
116
+ push, and re-poll until green.
117
+
118
+ ## Triggers
119
+
120
+ - After `gh pr create` / `glab mr create` for a feature branch.
121
+ - After every `git push` to a branch with an open PR/MR.
122
+ - User says: "babysit", "watch greptile", "poll the PR", "poll the MR",
123
+ "watch reviews", "follow up on review feedback", "what did greptile say".
124
+
125
+ ## Output contract
126
+
127
+ Per cycle, print one line (`PR` on GitHub, `MR` on GitLab):
128
+
129
+ ```
130
+ BABYSIT <PR|MR> #<n> @ <SHA>: poll <i> | reviews=<count> | new=<m> | actioned=<k> | ci=<green|pending|red> | next=<delay>
131
+ ```
132
+
133
+ `actioned` = findings whose code fix landed in this cycle (greptile OR CI).
134
+ `ci` = the aggregate check-run state from STEP 0.75.
135
+
136
+ ## Cadence (backoff)
137
+
138
+ | Time since last push (or last review) | Poll interval |
139
+ |---|---|
140
+ | 0–10 min | +180 s after each push |
141
+ | 10–30 min | +300 s |
142
+ | 30–60 min | +600 s |
143
+ | > 60 min | +1200 s, then stop after 2 consecutive empty polls |
144
+
145
+ Claude Code: use `ScheduleWakeup(delaySeconds, "re-poll review on <PR|MR>
146
+ #<n> <SHA>")`. Other agents: `sleep <delay>` in a shell loop, or schedule
147
+ via the agent's native cron/wakeup mechanism.
148
+
149
+ ## Polling loop
150
+
151
+ ### GitHub (`FORGE=github`)
152
+
153
+ ```bash
154
+ REPO=$(gh repo view --json nameWithOwner --jq '.nameWithOwner')
155
+ PR_NUMBER=$(gh pr view --json number --jq '.number')
156
+
157
+ # Walk EVERY review id — greptile may post more than one review per push.
158
+ REVIEW_IDS=$(gh api "repos/$REPO/pulls/$PR_NUMBER/reviews" \
159
+ --jq '.[] | select(.user.login | test("greptile"; "i")) | .id')
160
+
161
+ for rid in $REVIEW_IDS; do
162
+ # Follow greptile-triage.md (STEP 0): fetch line+top-level comments for THIS
163
+ # review id; Suppressions Check; Classify; Reply (Tier 1/Tier 2); history write.
164
+ # Fetch: gh api "repos/$REPO/pulls/$PR_NUMBER/reviews/$rid/comments"
165
+ # Reply: gh api -X POST "repos/$REPO/pulls/$PR_NUMBER/comments/<cid>/replies" -f body="..."
166
+ :
167
+ done
168
+
169
+ # ALSO triage greptile's SUMMARY feedback — it puts actionable findings in two
170
+ # places the line-comment walk above misses:
171
+ # (1) the review BODY (the review's own summary text), and
172
+ # (2) the top-level PR issue comment (greptile's "description reply" / summary,
173
+ # often with collapsible per-file sections listing concerns inline).
174
+ # Run each through greptile-triage.md exactly like a line comment.
175
+ gh api "repos/$REPO/pulls/$PR_NUMBER/reviews" \
176
+ --jq '.[] | select(.user.login|test("greptile";"i")) | select(.body != "") | .body'
177
+ gh api "repos/$REPO/issues/$PR_NUMBER/comments" \
178
+ --jq '.[] | select(.user.login|test("greptile";"i")) | {id, body}'
179
+ # Reply to a summary issue comment: gh api -X POST "repos/$REPO/issues/$PR_NUMBER/comments" -f body="..."
180
+ ```
181
+
182
+ ### GitLab (`FORGE=gitlab`)
183
+
184
+ ```bash
185
+ # Project full path (e.g. gpu/console), URL-encoded for the API.
186
+ PROJECT_PATH=$(glab repo view -F json 2>/dev/null | jq -r '.path_with_namespace' \
187
+ || git remote get-url origin | sed -E 's#.*[:/]([^:/]+/[^/]+)$#\1#; s#\.git$##')
188
+ PROJ_ENC=$(printf '%s' "$PROJECT_PATH" | sed 's#/#%2F#g')
189
+ MR_IID=$(glab mr view -F json | jq -r '.iid')
190
+
191
+ # Walk EVERY discussion thread from the review bot. GitLab has no "review"
192
+ # object — a bot posts discussion threads (each with notes[]).
193
+ THREAD_IDS=$(glab api "projects/$PROJ_ENC/merge_requests/$MR_IID/discussions" --paginate \
194
+ | jq -r '.[] | select(any(.notes[]; .author.username | test("greptile"; "i"))) | .id')
195
+
196
+ for tid in $THREAD_IDS; do
197
+ # Follow greptile-triage.md (STEP 0): fetch the thread's notes (body +
198
+ # position.new_path/new_line for line-level); Suppressions Check; Classify;
199
+ # Reply (Tier 1/Tier 2); history write.
200
+ # Fetch: glab api "projects/$PROJ_ENC/merge_requests/$MR_IID/discussions/$tid"
201
+ # Reply: glab api -X POST "projects/$PROJ_ENC/merge_requests/$MR_IID/discussions/$tid/notes" -f body="..."
202
+ :
203
+ done
204
+
205
+ # ALSO triage greptile's SUMMARY feedback — the MR-level notes greptile posts
206
+ # outside a positioned discussion thread (the "description reply" / overview
207
+ # note, often with inline per-file concerns). Run each through greptile-triage.md.
208
+ glab api "projects/$PROJ_ENC/merge_requests/$MR_IID/notes" \
209
+ --jq '.[] | select(.author.username|test("greptile";"i")) | select(.type == null) | {id, body}'
210
+ # Reply to a summary note: glab api -X POST "projects/$PROJ_ENC/merge_requests/$MR_IID/notes" -f body="..."
211
+ ```
212
+
213
+ ### History paths (forge-independent)
214
+
215
+ ```bash
216
+ REMOTE_SLUG=$(~/.claude/skills/gstack/browse/bin/remote-slug 2>/dev/null \
217
+ || basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)")
218
+ PROJECT_HISTORY="$HOME/.gstack/projects/$REMOTE_SLUG/greptile-history.md"
219
+ GLOBAL_HISTORY="$HOME/.gstack/greptile-history.md"
220
+ mkdir -p "$(dirname "$PROJECT_HISTORY")" "$(dirname "$GLOBAL_HISTORY")"
221
+ ```
222
+
223
+ **Critical: walk every review thread.** Greptile (or the bot) may post
224
+ multiple reviews/threads per push (one structural, one security, etc.). The
225
+ triage helper fetches once per call; the multi-thread walk lives here, on
226
+ both forges.
227
+
228
+ ## History file discipline
229
+
230
+ Every triaged comment writes one line to BOTH:
231
+
232
+ | File | Purpose |
233
+ |---|---|
234
+ | `$HOME/.gstack/projects/<slug>/greptile-history.md` | Per-project. Drives Suppressions Check on next cycle — `fp` lines suppress matching comments forever. |
235
+ | `$HOME/.gstack/greptile-history.md` | Global aggregate. Cross-project retro / pattern-mining. |
236
+
237
+ Line format (from the triage helper's "History File Writes" section):
238
+
239
+ ```
240
+ <YYYY-MM-DD> | <owner/repo> | <type:fp|fix|already-fixed> | <file-pattern> | <category>
241
+ ```
242
+
243
+ - **`fp`** — false positive. Suppressed on future polls.
244
+ - **`fix`** — real issue, fixed in this cycle. Not suppressed.
245
+ - **`already-fixed`** — real issue, fixed in a prior commit on this branch. Not suppressed.
246
+
247
+ The categories are a fixed set: `race-condition`, `null-check`, `error-handling`, `style`, `type-safety`, `security`, `performance`, `correctness`, `other`. Don't invent new categories — if a finding doesn't fit, use `other` and mention the actual concern in the reply, not the history line.
248
+
249
+ ## After a fix lands
250
+
251
+ 1. Fix the code per the triage helper's classification.
252
+ 2. Re-verify with `make lint` + `make test` (or relevant tier).
253
+ 3. Reply via the triage helper's "Reply APIs" section (Tier 1 / Tier 2
254
+ templates) through the forge layer above. Include the fix SHA in the body.
255
+ 4. Commit and push.
256
+ 5. Append the history line(s) to both files.
257
+ 6. If the finding generalizes beyond this PR/MR (recurring pattern, new
258
+ class of bug), capture as a named rule in the project's
259
+ `docs/greptile-learnings/RULES.md` in the same commit as the fix.
260
+ Otherwise the history line alone is the durable record.
261
+ 7. Re-schedule the next poll using the cadence table above.
262
+
263
+ ## Stop conditions
264
+
265
+ - **Done = two consecutive empty polls AND CI green.** Both must hold: no new
266
+ reviews/threads/summary findings for two polls **and** STEP 0.75 reports
267
+ `ci=green`. A quiet bot with a still-`pending` or red CI is NOT done — keep
268
+ polling on the cadence.
269
+ - **PR/MR merged or closed** → stop, report.
270
+ - **CI red FROM your changes** → fix it (STEP 0.75): diagnose, fix the code,
271
+ push, re-poll. Not a stop condition — it's work to do.
272
+ - **CI red and NOT from your changes** → surface to the user; pause the
273
+ done-declaration until they decide.
274
+ - **User says stop / pause** → print one final
275
+ `BABYSIT <PR|MR> #<n>: paused per user` line and stop.
276
+
277
+ ## Report format
278
+
279
+ At end of each cycle:
280
+
281
+ ```
282
+ BABYSIT REPORT — <PR|MR> #<n> @ <SHA>
283
+ Polls run: <i>
284
+ Reviews seen: <count> (line: <l>, summary/description: <s>)
285
+ Findings actioned: <k> (P0: <a>, P1: <b>)
286
+ Findings deferred: <d> (with reasons)
287
+ CI: <green | pending: <job…> | red: <job> — <fixed SHA | surfaced to user>>
288
+ Rules added/updated: <list of RULE refs> # via triage helper's history-write
289
+ Next poll: in <delay>s OR stopped (<reason>)
290
+ ```
291
+
292
+ ## What this skill does NOT do
293
+
294
+ - Does **not** re-implement fetch/classify/reply — see
295
+ `~/.local/share/gstack/review/greptile-triage.md`.
296
+ - Does **not** merge the PR/MR — use `/land-and-deploy` after the bot is green.
297
+ - Does **not** modify CI configuration or skip the review bot.
298
+ - Does **not** apply P2/P3/nit findings without explicit user approval
299
+ (the triage helper's classification drives this).
300
+
301
+ ## Failure modes
302
+
303
+ | Surface | Action |
304
+ |---|---|
305
+ | `gh api` / `glab api` rate-limited | Back off the poll interval by 2× and retry next cycle |
306
+ | Review missing on a push | Re-poll once at +180 s; if still missing, surface to user |
307
+ | `gh pr view` / `glab mr view` returns nothing (PR/MR not yet visible) | Skip cycle; retry next interval |
308
+ | `glab` not authed for a self-hosted host | Surface `BABYSIT: glab not authed for <host> — run glab auth login`; pause |
309
+ | Multiple reviews with conflicting suggestions | Apply the union; surface conflict only if both can't coexist |
310
+ | Finding is in code the agent did not author | Surface to user before fixing — never edit changes the agent did not create |
311
+
312
+ ## References
313
+
314
+ - `~/.local/share/gstack/review/greptile-triage.md` — fetch / classify /
315
+ reply / suppressions / history-write mechanics. Also at
316
+ `~/Projects/dotfiles/.unified-skills/review/greptile-triage.md`.
317
+ - `$HOME/.gstack/projects/<slug>/greptile-history.md` — per-project
318
+ history; drives Suppressions Check.
319
+ - `$HOME/.gstack/greptile-history.md` — global aggregate.
320
+ - `docs/greptile-learnings/RULES.md` — project-level named rules
321
+ (durable principles). New rule added here only when the finding
322
+ generalizes; per-incident rows go to greptile-history.md.
323
+ - `~/Projects/dotfiles/AGENTS.md` — CHORE(close) skill chain step 4
324
+ cites this skill.
325
+ - `gh api` docs: https://cli.github.com/manual/gh_api
326
+ - `glab api` docs: https://gitlab.com/gitlab-org/cli (`glab api --help`)
@@ -0,0 +1,157 @@
1
+ ---
2
+ name: orly-spec-new
3
+ description: |
4
+ Author a milestone/workstream spec the executing agent (Orly) ships into a
5
+ deterministic, review-clean, reported Pull Request — intent capture and
6
+ review-readiness first, file mechanics last. Use on "create a spec", "new
7
+ milestone", "start M{N}_{NNN}", "spec out X", or any TODO.md attempt
8
+ (forbidden — every non-trivial intent becomes a spec). Cross-agent,
9
+ self-contained markdown.
10
+ ---
11
+
12
+ # orly-spec-new
13
+
14
+ A spec is the **rulebook** the executing agent (Orly) plans and ships from. This
15
+ skill makes me author one whose Pull Request (PR) lands **deterministic, review-clean, and
16
+ reported** — without a 20-questions loop. It is written for my reasoning, not as
17
+ a file-naming guide: the mechanics (naming, layout) are demoted to the end
18
+ because they are the easy part.
19
+
20
+ > **The trio stays coherent.** This skill (*how to author*) ← `docs/TEMPLATE.md`
21
+ > (*the section shape*) → `audits/spec-template.sh` (*the enforcer*). If a
22
+ > step here demands something, the template carries the section and the audit
23
+ > asserts it. Drift between the three is a bug.
24
+
25
+ A spec is an *instance*; `AGENTS.md` and `docs/greptile-learnings/RULES.md` are
26
+ the *constants*. When the spec contradicts a rule, amend the spec — never weaken
27
+ the rule.
28
+
29
+ ## What a good spec guarantees
30
+
31
+ The three outcomes every step below serves:
32
+
33
+ - **Deterministic / invariant** — the agent plans and builds with no `[?]`; every claim is a test; every invariant is enforced by code, not review discipline.
34
+ - **Review-clean** — the code it produces trips no greptile finding, because the spec pre-commits to the exact `RULES.md` rule IDs and gates the diff touches.
35
+ - **Reported** — Discovery (consult log), the Acceptance Rubric's Graded column, and skill-chain outcomes are populated as the work proceeds.
36
+
37
+ ## Triggers
38
+
39
+ - User says: "create a spec", "spec this out", "new milestone", "draft M{N}_{NNN}", "start on M{N}", "track this as a milestone".
40
+ - The user attempts a `TODO.md` or any ad-hoc task list — convert it into a spec. **`TODO.md` is forbidden.**
41
+ - A `plan-eng-review` / `plan-ceo-review` / `plan-design-review` produced a plan that should be tracked durably.
42
+
43
+ ---
44
+
45
+ ## Step 1 — Capture intent (the hard part — do it before any file)
46
+
47
+ Determinism starts here. Before copying the template:
48
+
49
+ - **Testable goal** — one sentence that could be a test name. "Implement streaming" is not a goal; "SSE handler streams pubsub as `text/event-stream`, p95 < 200ms" is.
50
+ - **PR title + intent** — what the merged PR is called (imperative, ≤72 chars) and the one-sentence user-facing *why*.
51
+ - **Comprehension handshake** — restate the intent in my own words and list `ASSUMPTIONS I'M MAKING: …`. If my restatement and the requester's ask diverge, STOP and reconcile before drafting.
52
+ - **Golden-path walk** — trace the concrete end-to-end (every lookup, data source, secret store). Any `[?]` left in the walk blocks the spec from leaving `pending/`.
53
+ - **Product Clarity — Indy's ten product questions, answered in order** (successful user moment · preserved user behaviour · optimal-way check · rebuild-vs-iterate · what we build · what we do NOT build · fit with existing features · surface order · dashboard restraint · confused-user next step). They are answered BEFORE any implementation section is drafted; internal-only work may answer 8–10 as "N/A — no user surface" with the reason.
54
+
55
+ → Fills the template's **PR Intent & comprehension handshake**, **Overview**, and **Product Clarity (authoring record)**.
56
+
57
+ ## Step 2 — Lock review-readiness (so the PR ships clean)
58
+
59
+ This is the step that prevents greptile findings — the spec becomes a pre-commitment to the rules its code must obey:
60
+
61
+ - **Applicable Rules** — name the *specific* `docs/greptile-learnings/RULES.md` rule IDs the diff will trip (e.g. NDC, NLR, NLG, UFS), plus the per-surface dispatch façades / rule files: `dispatch/write_zig.md` (`*.zig`), `docs/REST_API_DESIGN_GUIDELINES.md` (`src/http/handlers/**`), `docs/SCHEMA_CONVENTIONS.md` (`schema/*`), `dispatch/write_ts_adhere_bun.md`, `docs/LOGGING_STANDARD.md`, `docs/LIFECYCLE_PATTERNS.md`. Generic "follow RULES.md" earns a greptile finding; named IDs the implementer obeys by construction do not. Cite rule docs by their repo-local `docs/…` paths — the selected packs materialise them into every repository; cite only files that exist here (`test -f` each).
62
+ - **Applicable Gates** — which Action-Triggered Guards fire (ZIG, PUB, LENGTH, UFS, UI, DESIGN TOKEN, LOGGING, LIFECYCLE, SCHEMA, ERROR REGISTRY) and the satisfaction strategy for each. Rules ≠ gates: rules are knowledge to read; gates fire on edits.
63
+ - **Prior-Art / Reference Implementations** — the reference codebase to mirror (CLI → the "7 Pillars" of CLI DX in `docs/TEMPLATE.md` Prior-Art; API → REST guide + nearest handler). No reinventing what a known-good pattern already solves.
64
+
65
+ → Fills **Applicable Rules**, **Applicable Gates**, **Prior-Art / Reference Implementations**.
66
+
67
+ ## Step 3 — Make it provable & reported
68
+
69
+ - Decompose **Sections** into numbered **Dimensions** (3.1, 3.2 …) — the unit of DONE. **Every Dimension → one Test** (tiered: unit/integration/e2e per `/orly-write-unit-test`; any user-facing Category gets a user-centric `test-e2e*` scenario).
70
+ - **Every Failure Mode → a negative test.** **Every Invariant → enforced by code** (compiler, lint, comptime assertion, runtime check) — never by review discipline.
71
+ - **Every Metrics row → event/test proof.** User-facing or operator-facing specs declare product/operator signals, privacy guards, and analytics/funnel playbook updates; internal-only cleanup explicitly says no signal changed.
72
+ - **Rubric = 5–12 outcome rows** — one per Section outcome, failure class, or hygiene gate (never per Dimension); each with a copy-paste Verify command and a mechanically checkable Expected (exit code / literal substring / match count). Standard rows come pre-filled in the template — prune to the touched surface.
73
+ - **Reporting spine** — **Discovery (consult log)** carries consults, skill-chain outcomes, and Indy-acked deferral quotes; the **Acceptance Rubric's Graded column** carries the VERIFY verdicts (✅/❌ + one decisive output line each). Both empty at creation, populated as work proceeds.
74
+
75
+ → Fills **Sections (+ Dimensions)**, **Metrics & Observability**, **Failure Modes**, **Invariants**, **Test Specification (tiered)**, **Acceptance Rubric**, **Discovery**.
76
+
77
+ ## Step 4 — Mechanics (the easy part)
78
+
79
+ Now the file. Pick the ID and copy the template:
80
+
81
+ ```bash
82
+ # next free M{N}_{WS}
83
+ ls docs/v*/pending/ docs/v*/active/ docs/v*/done/ 2>/dev/null \
84
+ | grep -oE 'M[0-9]+_[0-9]+' | sort -u | tail -5
85
+ cp docs/TEMPLATE.md docs/v{N}/pending/M{N}_{WS}_P{P}_{CATEGORIES}_{NAME}.md
86
+ ```
87
+
88
+
89
+ **Fill grammar** — the template body is ordered for the *executing* agent (execution read order), not for authoring; fill sections in the order of Steps 1–3 above, not top-to-bottom. Replace every `{…}` slot with instance content, then **delete every `<!-- tpl: … -->` guidance comment** — the SPEC TEMPLATE GATE BLOCKs any survivor, unfilled slot sentinels, and missing required sections. The SPEC AUTHORING RULES banner is the one comment that stays.
90
+
91
+ **Inputs** — Milestone `M{N}` (next free, sortable) · Workstream `{WS}` zero-padded (`001`…) · Priority (**P0** blocking · **P1** customer/operator-facing · **P2** tooling · **P3** deferrable) · Category set alphabetised (`API` Zig/Go · `CLI` agentsfleet/Node · `UI` Next.js · `OBS` Grafana · `SKILL` SKILL.md · `INFRA` Terraform) · Name UPPER_SNAKE_CASE ≤6 words describing the outcome (`BUN_VENDOR_UTILITIES`, not `BUMP_BUN_DEPS`) · Prototype tag (`v1.0.0`, `v2.0.0` — drives `docs/v1/` vs `docs/v2/`).
92
+
93
+ **File naming:** `docs/v{N}/{pending|active|done}/M{Milestone}_{Workstream}_P{Priority}_{CATEGORIES}_{NAME}.md` (e.g. `docs/v2/pending/M52_001_P2_API_BUN_VENDOR_UTILITIES.md`). Do NOT rename existing legacy-form files under `docs/v1/` or `docs/v2/done/`.
94
+
95
+ **Terminology — binding for everything that lands in a file** (conversational replies are exempt):
96
+
97
+ | Use | Do NOT use |
98
+ |---|---|
99
+ | Prototype (v1.0.0) | Release, Version train, Program |
100
+ | Milestone (M{N}) | Sprint, waterfall stage, Quarter |
101
+ | Workstream (M{N}_{WS}) | Ticket, Task, Story, Issue |
102
+ | Section (§3) | Waterfall stage, Step, Chapter |
103
+ | Dimension (3.4) | Acceptance criterion, AC, Checkbox |
104
+ | Batch (B2) | Wave, Tranche, Iteration |
105
+
106
+ **Directory movement** is lifecycle-driven: created → `pending/` (`Status: PENDING`); begin implementation → `active/` (CHORE(open)); all Dimensions DONE + PR opened → `done/`; parked → stay in `active/`.
107
+
108
+ ## Step 5 — Self-review gate, then commit
109
+
110
+ Before the spec leaves `pending/`, it must pass this checklist — the deterministic/invariant guarantee:
111
+
112
+ - [ ] intent handshake done; golden-path walk has **no `[?]`**
113
+ - [ ] **Product Clarity answered** — ten items, in order, `[?]`-free
114
+ - [ ] **zero `tpl:` guidance comments remain** — the body carries only instance content
115
+ - [ ] **Applicable Rules names specific greptile rule IDs**; Applicable Gates populated with satisfaction strategy
116
+ - [ ] **Metrics & Observability declares events or explicitly says no product/operator signal changed**; any analytics/funnel playbook update is listed
117
+ - [ ] **every Dimension has a Test**; **every Failure Mode has a negative test**; every Invariant is code-enforceable
118
+ - [ ] Prior-Art reference named (or "greenfield — shape in `docs/architecture/`")
119
+ - [ ] reporting sections present (Discovery; Acceptance Rubric with Graded column empty)
120
+ - [ ] `bash audits/spec-template.sh --staged` is clean (it BLOCKs missing required sections and unfilled `{placeholders}`)
121
+
122
+ Then commit in the current authoring context:
123
+
124
+ - If the skill is running inside an existing branch/worktree, author and commit the spec there.
125
+ - If there is no branch/worktree context, use the repo's `main` branch as the fallback.
126
+
127
+ ```bash
128
+ git add docs/v{N}/pending/M{N}_{WS}_*_{NAME}.md
129
+ git commit -m "docs(m{N}): add spec — {short title}"
130
+ ```
131
+
132
+ The spec lands in `pending/` on the branch/worktree where the skill was invoked. CHORE(open) moves it to `active/` and creates any needed worktree — handled by the lifecycle, not this skill.
133
+
134
+ ---
135
+
136
+ ## What this skill does NOT do
137
+
138
+ - It does **not** start coding, create a worktree, or move the spec to `active/`. That's CHORE(open), when implementation begins.
139
+ - It does **not** modify any rule file, ARCHITECTURE doc, or changelog.
140
+ - It does **not** create a branch just to author a spec. Spec creation uses the current branch/worktree, falling back to `main` only when no branch/worktree exists.
141
+
142
+ ## Failure modes
143
+
144
+ | Surface | What you do |
145
+ |---|---|
146
+ | User insists on `TODO.md` | Decline. Convert the intent into a spec via this skill. |
147
+ | Spec name collides with a `done/` entry | Pick the next workstream number; never reuse. |
148
+ | Spec depends on something still in `pending/` | Allowed — list it in `Depends on:` and surface it. |
149
+ | Spec proposes work that violates a rule | Amend the spec text or scope before committing. Rules are the constants. |
150
+ | Can't write the goal as a test name | Intent is not understood yet — go back to Step 1; do not draft sections. |
151
+
152
+ ## References
153
+
154
+ - `docs/TEMPLATE.md` — the section shape this skill fills (materialised per-repo by `workflow.specifications`; canonical source: the orly repository).
155
+ - `audits/spec-template.sh` — the enforcer (`--staged` BLOCKs an incomplete spec).
156
+ - `docs/greptile-learnings/RULES.md` — the rule IDs Step 2 pins for review-cleanliness.
157
+ - The repository's generated `AGENTS.md` — lifecycle stages, action-triggered guards, deterministic VERIFY/CHORE sequencing.