mirror of https://github.com/garrytan/gstack.git
Merge 7d0a136515 into a3259400a3
This commit is contained in:
commit
2e15f49ea7
|
|
@ -43,6 +43,7 @@ Invoke them by name (e.g., `/office-hours`).
|
|||
|
||||
| Skill | What it does |
|
||||
|-------|-------------|
|
||||
| `/pr-prep` | Pre-PR upstream duplicate audit. Scores each commit against upstream issues + PRs; blocks on exact duplicates. Hooks into `/ship` as Step 0. |
|
||||
| `/ship` | Run tests, review, push, open PR. Workspace-aware version queue. |
|
||||
| `/land-and-deploy` | Merge the PR, wait for CI and deploy, verify production health. |
|
||||
| `/canary` | Post-deploy monitoring loop using the browse daemon. |
|
||||
|
|
|
|||
|
|
@ -0,0 +1,199 @@
|
|||
# Preamble Bloat — Findings & Safe Trim Strategy
|
||||
|
||||
Date: 2026-07-05. Investigated on branch `feat/pr-prep-skill`
|
||||
(merge-base with `upstream/main` = `11de390b`, v1.58.5.0).
|
||||
|
||||
**Verdict: do NOT trim locally.** The bloat is upstream-owned, generated
|
||||
content, churned in every upstream release. Any fork-side edit to the
|
||||
source (resolvers or templates) or to the committed generated files
|
||||
guarantees rebase conflicts on every `/gstack-upgrade` (this fork is
|
||||
maintained by rebasing onto `upstream/main`). The safe path is an
|
||||
upstream PR that extends the repo's own `sections/` carving mechanism
|
||||
to the preamble. Details below.
|
||||
|
||||
---
|
||||
|
||||
## 1. Where the bytes come from
|
||||
|
||||
Every `~/.claude/skills/<name>/SKILL.md` is a **symlink** into this repo.
|
||||
Each `SKILL.md` here is **generated** by `scripts/gen-skill-docs.ts` from
|
||||
`<skill>/SKILL.md.tmpl`: placeholders (`{{PREAMBLE}}`, `{{SLUG_SETUP}}`,
|
||||
`{{QA_METHODOLOGY}}`, …) are resolved from `scripts/resolvers/**`.
|
||||
|
||||
The dominant placeholder is `{{PREAMBLE}}`, composed in
|
||||
`scripts/resolvers/preamble.ts` from ~24 generator files under
|
||||
`scripts/resolvers/preamble/`, gated by `preamble-tier: 1-4` in each
|
||||
template's frontmatter (missing tier defaults to 4).
|
||||
|
||||
Rendered preamble size (measured by invoking `generatePreamble()`
|
||||
directly; host=claude, model=claude, interactive):
|
||||
|
||||
| Tier | Bytes | ~Tokens (4 B/tok) | Skills at this tier |
|
||||
|------|-------|-------------------|---------------------|
|
||||
| 1 | 25,690 | ~6.4k | 6 |
|
||||
| 2 | 45,295 | ~11.3k | 16 |
|
||||
| 3 | 46,336 | ~11.6k | 15 |
|
||||
| 4 | 46,336 | ~11.6k | 7 (+ untiered, e.g. `spec`) |
|
||||
|
||||
So a tier-2 skill like `context-save` (54,971 B total) is **84% preamble**
|
||||
(46,112 B before the first body heading). Across the whole install,
|
||||
~1.9 MB of the 3.57 MB of installed SKILL.md bytes is the same preamble
|
||||
duplicated ~44 times (~53%).
|
||||
|
||||
Per-section breakdown of the tier-4 preamble (rendered bytes):
|
||||
|
||||
| Section | Bytes | Nature |
|
||||
|---|---|---|
|
||||
| ask-user-format | 10,546 | prose — interaction framework |
|
||||
| preamble-bash | 6,169 | **functional** — session/telemetry bootstrap |
|
||||
| brain-sync-block | 5,785 | **functional** — gbrain sync bash |
|
||||
| plan-mode-info | 2,888 | prose + env contract |
|
||||
| question-tuning | 2,494 | prose |
|
||||
| context-recovery | 2,378 | prose |
|
||||
| first-run-guidance | 1,715 | one-time onboarding gate |
|
||||
| routing-injection | 1,624 | one-time onboarding gate |
|
||||
| voice-directive | 1,350 | prose |
|
||||
| upgrade-check | 1,186 | **functional** — bash |
|
||||
| writing-style | 1,113 | prose |
|
||||
| vendoring-deprecation | 975 | one-time gate |
|
||||
| model-overlay | 947 | behavioural patch |
|
||||
| continuous-checkpoint | 922 | prose |
|
||||
| telemetry-prompt | 829 | one-time gate |
|
||||
| 9 further sections | ~4,182 | mixed, ≤700 B each |
|
||||
| **Total** | **~45.1k** | |
|
||||
|
||||
## 2. Ten largest installed SKILL.md files (symlink-resolved bytes)
|
||||
|
||||
```txt
|
||||
126,959 spec (untiered -> T4)
|
||||
105,796 review (T4)
|
||||
105,734 design-review (T4)
|
||||
101,167 land-and-deploy (T4)
|
||||
100,590 autoplan (T3)
|
||||
97,744 office-hours (T3)
|
||||
93,248 retro (T2)
|
||||
90,397 setup-gbrain
|
||||
90,000 codex (T3)
|
||||
89,827 plan-ceo-review (T3)
|
||||
```
|
||||
|
||||
(Also notable: `qa` 83,941; `context-save` 54,971; `browse` 54,983.)
|
||||
Non-gstack skills are far smaller: `graphify` 37,070, `impeccable`
|
||||
19,981, `undercover-agent` 12,653 — the bloat is specifically the
|
||||
gstack preamble plus a handful of intentionally large bodies.
|
||||
|
||||
## 3. Why fork-side trimming is unsafe (the evidence)
|
||||
|
||||
1. **Upstream owns and churns every layer.** The last three upstream
|
||||
releases (v1.57.5.0 `45cc95d5`, v1.58.1.0 `c7ae6320`, v1.58.5.0
|
||||
`11de390b`) each modified `scripts/resolvers/preamble/` AND the
|
||||
committed generated `SKILL.md` files (e.g. `context-save/SKILL.md`
|
||||
changed in all three). A single release delta
|
||||
(`upstream/main~1..upstream/main`) touched **51 files / 1,469
|
||||
insertions** across `*/SKILL.md`, `*/SKILL.md.tmpl`, and
|
||||
`scripts/resolvers/`. A local diff in those paths conflicts on
|
||||
every rebase.
|
||||
2. **CI freshness gate pins generated output to default flags.**
|
||||
`gen-skill-docs.ts --dry-run` (used by `skill:check` / CI) exits 1
|
||||
if committed SKILL.md ≠ generator output. A committed trim therefore
|
||||
cannot live only in the generated files — it must be sourced in the
|
||||
resolvers/templates, which are exactly the upstream-churned files.
|
||||
3. **This fork's own discipline confirms the pain.** The 12 local
|
||||
commits ahead of upstream confine themselves to a new fork-owned
|
||||
skill (`pr-prep/`) plus a ~50-line `ship/SKILL.md.tmpl` addition;
|
||||
none touch `scripts/resolvers/`. That boundary is what keeps
|
||||
rebases cheap today.
|
||||
4. **Preamble composition is behaviour-sensitive upstream territory.**
|
||||
`preamble.ts` documents ordering constraints in-line (e.g.
|
||||
AskUserQuestion Format must render before the model overlay;
|
||||
"reversing this order regresses plan-review cadence (v1.6.4.0
|
||||
bug)"). Relocating sections is not a mechanical move.
|
||||
5. **Upstream's stated stance tolerates the size.** The generator's
|
||||
token-ceiling guardrail (gen-skill-docs.ts, ~line 1013) warns only
|
||||
above 160 KB/file and explicitly defends 25-35k-token skills as
|
||||
intentional. A quiet local fork of that philosophy would fight
|
||||
upstream on every release.
|
||||
|
||||
## 4. The safe trim strategy
|
||||
|
||||
**A. Upstream PR (recommended, durable).** The machinery already
|
||||
exists: carved skills render on-demand `sections/*.md` for the Claude
|
||||
host (`discoverSectionTemplates` in `scripts/discover-skills.ts`,
|
||||
section generation in `gen-skill-docs.ts`; live examples:
|
||||
`plan-eng-review/sections/`, `qa/references/`, `qa/templates/`).
|
||||
Extend it to the preamble:
|
||||
|
||||
- Move the tier-2+ interaction-framework prose — ask-user-format,
|
||||
question-tuning, context-recovery, writing-style, completeness,
|
||||
confusion-protocol, continuous-checkpoint, context-health, plus the
|
||||
tier-3 repo-mode and search-before-building blocks (~20.5 KB
|
||||
rendered) — into a generated shared section file (e.g.
|
||||
`<skill>/sections/interaction-framework.md`), leaving a 2-3 line
|
||||
pointer in the inline preamble ("Read
|
||||
`~/.claude/skills/gstack/<skill>/sections/interaction-framework.md`
|
||||
before your first AskUserQuestion / when the framework applies").
|
||||
- Keep byte-identical inline: the functional bash bootstrap
|
||||
(preamble-bash, upgrade-check, brain-sync-block, telemetry), the
|
||||
one-time onboarding gates, model overlay, and frontmatter/triggers.
|
||||
- Non-Claude hosts already inline sections via `{{SECTION:id}}`, so
|
||||
the change is Claude-host-only, mirroring the existing carve.
|
||||
|
||||
Run `/pr-prep` first (built in this fork for exactly this) to check
|
||||
upstream for an existing issue/PR on preamble slimming before opening.
|
||||
|
||||
**B. Zero-conflict local interim (nothing committed).** Render a
|
||||
user-local variant to an untracked directory with the existing
|
||||
`--out-dir` flag and re-point the `~/.claude/skills/<name>/SKILL.md`
|
||||
symlinks there. Supported knob today: `--explain-level=terse`
|
||||
compresses four prose sections to pointer lines — but it saves only
|
||||
~2.2 KB (46,336 → 44,179 B), which is why A is the real fix. Note the
|
||||
working tree already carries expected uncommitted SKILL.md dirt from
|
||||
`gen:skill-docs:user` (gbrain detection); an out-dir render avoids
|
||||
adding to it.
|
||||
|
||||
**C. Not recommended.** Fork-local edits to
|
||||
`scripts/resolvers/preamble/**` or committing regenerated SKILL.md
|
||||
files: recurring semantic conflicts against ~50 files/1.5k lines of
|
||||
upstream churn per release.
|
||||
|
||||
## 5. Estimated savings (strategy A)
|
||||
|
||||
- Per invocation, tier 2-4 skill: ~20.5 KB relocated ≈ **~5.1k tokens
|
||||
saved** (at the generator's own 4-chars/token heuristic), i.e. the
|
||||
preamble drops ~44% (46.3 KB → ~25.8 KB) and e.g. `context-save`
|
||||
goes 55 KB → ~34 KB, `qa` 84 KB → ~63 KB.
|
||||
- Applies to 38 tier-2+ skills; tier-1 skills (browse, benchmark, …)
|
||||
are unaffected by design.
|
||||
- Install-wide: ~0.8 MB less duplicated preamble on disk; every
|
||||
gstack skill invocation on this machine starts ~5k tokens lighter.
|
||||
- Getting the top offenders under ~15 KB would additionally require
|
||||
carving their bodies (spec 95 KB body, review ~60 KB body) — that is
|
||||
upstream-owned, intentionally-tuned behaviour per the token-ceiling
|
||||
comment, so propose it upstream per-skill via the same `sections/`
|
||||
mechanism rather than forking it.
|
||||
|
||||
---
|
||||
|
||||
## 6. Upstream duplicate check (2026-07-05, Opus session)
|
||||
|
||||
Ran the check the strategy said to do first. Findings on garrytan/gstack:
|
||||
|
||||
- **#1572 (open) — "skill: cache preamble bash output within session to
|
||||
reduce duplication"** is the closest existing issue: same preamble-duplication
|
||||
concern, no PR carving the interaction-framework prose yet. Our proposal is
|
||||
complementary, not a duplicate.
|
||||
- Active adjacent preamble work (do NOT collide): #2001/#2022 gate
|
||||
upgrade-handling prose; #1150/#1188 gate telemetry session tracking; #1982
|
||||
surface failed update-checks; #1972 shrink skill descriptions (codex budget).
|
||||
- No open PR implements a `sections/` carve of the preamble prose.
|
||||
|
||||
Verification blockers confirming proposal-first:
|
||||
- `bun run skill:check` is **red on a clean `11de390b` checkout** — unrelated
|
||||
cause: `.gbrain/skills/gstack-*/SKILL.md` stale under `gen:skill-docs --host
|
||||
gbrain` detection. A fork can't cleanly prove Claude-host freshness in
|
||||
isolation against that baseline.
|
||||
- Real behaviour gate is `test:evals` (EVALS=1, live model calls) — API-gated.
|
||||
|
||||
Deliverable: `~/worktrees/gstack-preamble-trim/PR-PROPOSAL.md` — maintainer-ready
|
||||
text to post on #1572 for buy-in before implementing. Branch `pr/preamble-trim`
|
||||
sits on clean upstream; no code committed (proposal-first, per above).
|
||||
|
|
@ -399,6 +399,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -450,6 +452,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ allowed-tools:
|
|||
- Bash
|
||||
- Read
|
||||
- AskUserQuestion
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ allowed-tools:
|
|||
- Bash
|
||||
- Read
|
||||
- AskUserQuestion
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ allowed-tools:
|
|||
- Write
|
||||
- Glob
|
||||
- AskUserQuestion
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ allowed-tools:
|
|||
- Write
|
||||
- Glob
|
||||
- AskUserQuestion
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
# /bin/bash, not env bash: Homebrew bash 5.3 heredocs >511B deadlock on macOS (512-byte pipe buffers, no F_GETPIPE_SZ)
|
||||
# gstack-artifacts-init — set up ~/.gstack/ as a git repo synced to a private
|
||||
# git host (GitHub or GitLab) so a remote gbrain can ingest your artifacts
|
||||
# (CEO plans, designs, /investigate reports) as a federated source.
|
||||
|
|
@ -48,7 +49,7 @@ while [ $# -gt 0 ]; do
|
|||
--remote) REMOTE_URL="$2"; shift 2 ;;
|
||||
--host) HOST_PREF="$2"; shift 2 ;;
|
||||
--url-form-supported) URL_FORM_SUPPORTED="$2"; shift 2 ;;
|
||||
--help|-h) sed -n '2,32p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
|
||||
--help|-h) sed -n '3,33p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
|
||||
*) echo "Unknown flag: $1" >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
# /bin/bash, not env bash: Homebrew bash 5.3 heredocs >511B deadlock on macOS (512-byte pipe buffers, no F_GETPIPE_SZ)
|
||||
# gstack-brain-consumer — manage the consumer (reader) registry.
|
||||
#
|
||||
# DEPRECATED in v1.17.0.0. This binary targets a gbrain HTTP /ingest-repo
|
||||
|
|
@ -196,6 +197,6 @@ case "${1:-}" in
|
|||
list) sub_list ;;
|
||||
remove) shift; sub_remove "$@" ;;
|
||||
test) shift; sub_test "$@" ;;
|
||||
--help|-h|"") sed -n '2,20p' "$0" | sed 's/^# \{0,1\}//' ;;
|
||||
--help|-h|"") sed -n '3,21p' "$0" | sed 's/^# \{0,1\}//' ;;
|
||||
*) echo "Unknown subcommand: $1" >&2; exit 1 ;;
|
||||
esac
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
# /bin/bash, not env bash: Homebrew bash 5.3 heredocs >511B deadlock on macOS (512-byte pipe buffers, no F_GETPIPE_SZ)
|
||||
# gstack-brain-restore — bootstrap a new machine from an existing brain repo.
|
||||
#
|
||||
# Usage:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
# /bin/bash, not env bash: Homebrew bash 5.3 heredocs >511B deadlock on macOS (512-byte pipe buffers, no F_GETPIPE_SZ)
|
||||
# gstack-brain-sync — drain queue, commit allowlisted paths, push to remote.
|
||||
#
|
||||
# Usage:
|
||||
|
|
@ -487,7 +488,7 @@ case "${1:-}" in
|
|||
--drop-queue) shift; subcmd_drop_queue "${1:-}" ;;
|
||||
--discover-new) subcmd_discover_new ;;
|
||||
--help|-h)
|
||||
sed -n '2,18p' "$0" | sed 's/^# \{0,1\}//'
|
||||
sed -n '3,19p' "$0" | sed 's/^# \{0,1\}//'
|
||||
;;
|
||||
*)
|
||||
echo "Unknown subcommand: $1" >&2
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
# /bin/bash, not env bash: Homebrew bash 5.3 heredocs >511B deadlock on macOS (512-byte pipe buffers, no F_GETPIPE_SZ)
|
||||
# gstack-distill-free-text — Layer 8 "dream cycle" batch distiller.
|
||||
#
|
||||
# Reads auq-other free-text events from this project's question-log.jsonl,
|
||||
|
|
@ -37,7 +38,7 @@ case "${1:-}" in
|
|||
--dry-run) MODE="dry-run" ;;
|
||||
--status) MODE="status" ;;
|
||||
--help|-h)
|
||||
sed -n '1,/^set -euo/p' "$0" | sed 's|^# \?||'
|
||||
sed -n '3,/^set -euo/p' "$0" | sed 's|^# \?||'
|
||||
exit 0
|
||||
;;
|
||||
'') ;;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
# /bin/bash, not env bash: Homebrew bash 5.3 heredocs >511B deadlock on macOS (512-byte pipe buffers, no F_GETPIPE_SZ)
|
||||
# gstack-jsonl-merge — git merge driver for append-only JSONL files.
|
||||
#
|
||||
# Usage (called by git, not by users):
|
||||
|
|
|
|||
|
|
@ -0,0 +1,153 @@
|
|||
#!/usr/bin/env bun
|
||||
/**
|
||||
* gstack-pr-prep-score — pure collision scorer for the /pr-prep audit.
|
||||
*
|
||||
* Extracts the Step 4 bucketing rules from pr-prep/SKILL.md into one
|
||||
* deterministic, unit-tested place (the v0.2.0 seed the skill flags). The
|
||||
* skill's inline bash remains the spec; this is the canonical implementation
|
||||
* it points to. No network, no git — pure function of its JSON input.
|
||||
*
|
||||
* Input (stdin or --file <path>), one commit's candidate set:
|
||||
* {
|
||||
* "commitKeywords": ["reindex", "cli", "fix"],
|
||||
* "changedFiles": ["src/reindex.ts"],
|
||||
* "candidates": [
|
||||
* { "state": "open_pr", "titleKeywords": [...], "changedFiles": [...] },
|
||||
* { "state": "open_issue", "titleKeywords": [...] },
|
||||
* { "state": "merged_recent", "titleKeywords": [...] },
|
||||
* { "state": "closed_issue", "titleKeywords": [...] }
|
||||
* ]
|
||||
* }
|
||||
*
|
||||
* Output (stdout): { "bucket", "topScore", "openIssueCount", "reasons": [...] }
|
||||
* Buckets: EXACT_DUP | OVERLAP | SIBLING | CLEAN (precedence in that order).
|
||||
* Exit 0 always; the bucket is the signal (the skill maps EXACT_DUP -> exit 1).
|
||||
*/
|
||||
|
||||
export type CandidateState = 'open_pr' | 'open_issue' | 'merged_recent' | 'closed_issue';
|
||||
|
||||
export interface Candidate {
|
||||
state: CandidateState;
|
||||
titleKeywords?: string[];
|
||||
changedFiles?: string[];
|
||||
ref?: string; // e.g. "#1358" — passed through into reasons
|
||||
}
|
||||
|
||||
export interface ScoreInput {
|
||||
commitKeywords?: string[];
|
||||
changedFiles?: string[];
|
||||
candidates?: Candidate[];
|
||||
}
|
||||
|
||||
export type Bucket = 'EXACT_DUP' | 'OVERLAP' | 'SIBLING' | 'CLEAN';
|
||||
|
||||
export interface ScoreResult {
|
||||
bucket: Bucket;
|
||||
topScore: number;
|
||||
openIssueCount: number;
|
||||
reasons: string[];
|
||||
}
|
||||
|
||||
// State weighting from SKILL.md Step 4.
|
||||
const STATE_WEIGHT: Record<CandidateState, number> = {
|
||||
open_pr: 1.0,
|
||||
open_issue: 0.7,
|
||||
merged_recent: 0.6,
|
||||
closed_issue: 0.2,
|
||||
};
|
||||
|
||||
function norm(tokens: string[] | undefined): Set<string> {
|
||||
return new Set((tokens ?? []).map((t) => t.toLowerCase().trim()).filter(Boolean));
|
||||
}
|
||||
|
||||
export function jaccard(a: string[] | undefined, b: string[] | undefined): number {
|
||||
const sa = norm(a);
|
||||
const sb = norm(b);
|
||||
if (sa.size === 0 || sb.size === 0) return 0;
|
||||
let inter = 0;
|
||||
for (const x of sa) if (sb.has(x)) inter++;
|
||||
const union = sa.size + sb.size - inter;
|
||||
return union === 0 ? 0 : inter / union;
|
||||
}
|
||||
|
||||
export function score(input: ScoreInput): ScoreResult {
|
||||
const candidates = input.candidates ?? [];
|
||||
const reasons: string[] = [];
|
||||
let topScore = 0;
|
||||
let exactDup = false;
|
||||
let overlap = false;
|
||||
let sibling = false;
|
||||
let openIssueCount = 0;
|
||||
let hasOpenPr = false;
|
||||
let onlyClosed = candidates.length > 0;
|
||||
|
||||
for (const c of candidates) {
|
||||
const titleJ = jaccard(input.commitKeywords, c.titleKeywords);
|
||||
// File overlap only meaningful for open PRs (we can read their diff).
|
||||
const fileJ =
|
||||
c.state === 'open_pr' ? jaccard(input.changedFiles, c.changedFiles) : 0;
|
||||
const overlapJ = Math.max(titleJ, fileJ);
|
||||
const s = overlapJ * STATE_WEIGHT[c.state];
|
||||
if (s > topScore) topScore = s;
|
||||
if (c.state !== 'closed_issue') onlyClosed = false;
|
||||
if (c.state === 'open_issue') openIssueCount++;
|
||||
if (c.state === 'open_pr') hasOpenPr = true;
|
||||
|
||||
const ref = c.ref ? `${c.ref} ` : '';
|
||||
// EXACT_DUP: any OPEN PR with title Jaccard >=0.6 OR file overlap >=0.6.
|
||||
if (c.state === 'open_pr' && (titleJ >= 0.6 || fileJ >= 0.6)) {
|
||||
exactDup = true;
|
||||
reasons.push(
|
||||
`${ref}EXACT_DUP: open PR titleJ=${titleJ.toFixed(2)} fileJ=${fileJ.toFixed(2)}`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
// OVERLAP: any OPEN PR/issue with score >=0.3.
|
||||
if ((c.state === 'open_pr' || c.state === 'open_issue') && s >= 0.3) {
|
||||
overlap = true;
|
||||
reasons.push(`${ref}OVERLAP: open ${c.state} score=${s.toFixed(2)}`);
|
||||
continue;
|
||||
}
|
||||
// SIBLING: merged-recently with any overlap.
|
||||
if (c.state === 'merged_recent' && overlapJ > 0) {
|
||||
sibling = true;
|
||||
reasons.push(`${ref}SIBLING: merged-recent overlap=${overlapJ.toFixed(2)}`);
|
||||
}
|
||||
}
|
||||
|
||||
// OVERLAP also triggers on >=3 OPEN issues even when none individually scores high.
|
||||
if (openIssueCount >= 3) {
|
||||
overlap = true;
|
||||
reasons.push(`OVERLAP: ${openIssueCount} open issues`);
|
||||
}
|
||||
// SIBLING: OPEN issues present but no OPEN PR (and not already EXACT_DUP/OVERLAP).
|
||||
if (openIssueCount > 0 && !hasOpenPr) sibling = true;
|
||||
|
||||
let bucket: Bucket;
|
||||
if (exactDup) bucket = 'EXACT_DUP';
|
||||
else if (overlap) bucket = 'OVERLAP';
|
||||
else if (sibling) bucket = 'SIBLING';
|
||||
else bucket = 'CLEAN';
|
||||
|
||||
if (bucket === 'CLEAN' && reasons.length === 0) {
|
||||
reasons.push(onlyClosed ? 'only closed issues' : 'no hits above threshold');
|
||||
}
|
||||
return { bucket, topScore: Number(topScore.toFixed(4)), openIssueCount, reasons };
|
||||
}
|
||||
|
||||
// CLI entry — skip when imported by the test.
|
||||
if (import.meta.main) {
|
||||
const fileArg = process.argv.indexOf('--file');
|
||||
const raw =
|
||||
fileArg !== -1
|
||||
? await Bun.file(process.argv[fileArg + 1]).text()
|
||||
: await Bun.stdin.text();
|
||||
let input: ScoreInput;
|
||||
try {
|
||||
input = JSON.parse(raw || '{}');
|
||||
} catch {
|
||||
console.error('gstack-pr-prep-score: input is not valid JSON');
|
||||
process.exit(2);
|
||||
}
|
||||
process.stdout.write(JSON.stringify(score(input)) + '\n');
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
# /bin/bash, not env bash: Homebrew bash 5.3 heredocs >511B deadlock on macOS (512-byte pipe buffers, no F_GETPIPE_SZ)
|
||||
# gstack-settings-hook — manage Claude Code hooks in ~/.claude/settings.json
|
||||
#
|
||||
# Two shapes:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
# /bin/bash, not env bash: Homebrew bash 5.3 heredocs >511B deadlock on macOS (512-byte pipe buffers, no F_GETPIPE_SZ)
|
||||
# gstack-team-init — generate repo-level bootstrap files for team mode
|
||||
#
|
||||
# Usage:
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ triggers:
|
|||
- monitor after deploy
|
||||
- canary check
|
||||
- watch for errors post-deploy
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
@ -391,6 +392,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -442,6 +445,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ triggers:
|
|||
- monitor after deploy
|
||||
- canary check
|
||||
- watch for errors post-deploy
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ hooks:
|
|||
- type: command
|
||||
command: "bash $HOME/.claude/skills/gstack/careful/bin/check-careful.sh"
|
||||
statusMessage: "Checking for destructive commands..."
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ hooks:
|
|||
command: "bash $HOME/.claude/skills/gstack/careful/bin/check-careful.sh"
|
||||
statusMessage: "Checking for destructive commands..."
|
||||
sensitive: true
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
# /careful — Destructive Command Guardrails
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ allowed-tools:
|
|||
- Glob
|
||||
- Grep
|
||||
- AskUserQuestion
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
@ -394,6 +395,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -445,6 +448,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ allowed-tools:
|
|||
- Glob
|
||||
- Grep
|
||||
- AskUserQuestion
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -395,6 +395,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -446,6 +448,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -394,6 +394,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -445,6 +447,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ triggers:
|
|||
- security audit
|
||||
- check for vulnerabilities
|
||||
- owasp review
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
@ -397,6 +398,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -448,6 +451,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ triggers:
|
|||
- security audit
|
||||
- check for vulnerabilities
|
||||
- owasp review
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -417,6 +417,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -468,6 +470,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ allowed-tools:
|
|||
- Grep
|
||||
- Agent
|
||||
- AskUserQuestion
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
@ -398,6 +399,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -449,6 +452,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ allowed-tools:
|
|||
- Grep
|
||||
- Agent
|
||||
- AskUserQuestion
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -395,6 +395,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -446,6 +448,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ gbrain:
|
|||
sort: mtime_desc
|
||||
limit: 3
|
||||
render_as: "## Recent design docs"
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
@ -412,6 +413,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -463,6 +466,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ gbrain:
|
|||
sort: mtime_desc
|
||||
limit: 3
|
||||
render_as: "## Recent design docs"
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ allowed-tools:
|
|||
- Bash
|
||||
- AskUserQuestion
|
||||
- WebSearch
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
@ -397,6 +398,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -448,6 +451,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ allowed-tools:
|
|||
- Bash
|
||||
- AskUserQuestion
|
||||
- WebSearch
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ triggers:
|
|||
- diagram this
|
||||
- visualize this flow
|
||||
- architecture diagram
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
@ -392,6 +393,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -443,6 +446,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ triggers:
|
|||
- diagram this
|
||||
- visualize this flow
|
||||
- architecture diagram
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ Detailed guides for every gstack skill — philosophy, workflow, and examples.
|
|||
| [`/qa-only`](#qa) | **QA Reporter** | Same methodology as /qa but report only. Use when you want a pure bug report without code changes. |
|
||||
| [`/scrape`](#scrape) | **Browser Data Extractor** | Pull data from a web page. First call prototypes via `$B`; subsequent calls on a matching intent run a codified browser-skill in ~200ms. |
|
||||
| [`/skillify`](#skillify) | **Skill Codifier** | Walks back through your conversation, finds the last `/scrape` prototype, synthesizes script + test + fixture, runs the test, asks before committing. |
|
||||
| [`/pr-prep`](#pr-prep) | **PR Auditor** | Pre-PR upstream duplicate audit. Walks `git log base..HEAD`, queries upstream issues + PRs, scores each commit (EXACT_DUP / OVERLAP / SIBLING / CLEAN), and refuses to proceed on exact duplicates. Hooks into `/ship` as Step 0. |
|
||||
| [`/ship`](#ship) | **Release Engineer** | Sync main, run tests, audit coverage, push, open PR. Bootstraps test frameworks if you don't have one. One command. |
|
||||
| [`/land-and-deploy`](#land-and-deploy) | **Release Engineer** | Merge the PR, wait for CI and deploy, verify production health. One command from "approved" to "verified in production." |
|
||||
| [`/canary`](#canary) | **SRE** | Post-deploy monitoring loop. Watches for console errors, performance regressions, and page failures using the browse daemon. |
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ triggers:
|
|||
- write a how-to
|
||||
- explain this module
|
||||
- docs for this project
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
@ -397,6 +398,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -448,6 +451,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ triggers:
|
|||
- write a how-to
|
||||
- explain this module
|
||||
- docs for this project
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ triggers:
|
|||
- update docs after ship
|
||||
- document what changed
|
||||
- post-ship docs
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
@ -395,6 +396,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -446,6 +449,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ triggers:
|
|||
- update docs after ship
|
||||
- document what changed
|
||||
- post-ship docs
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ hooks:
|
|||
- type: command
|
||||
command: "bash $HOME/.claude/skills/gstack/freeze/bin/check-freeze.sh"
|
||||
statusMessage: "Checking freeze boundary..."
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ hooks:
|
|||
command: "bash $HOME/.claude/skills/gstack/freeze/bin/check-freeze.sh"
|
||||
statusMessage: "Checking freeze boundary..."
|
||||
sensitive: true
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
# /freeze — Restrict Edits to a Directory
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ allowed-tools:
|
|||
- Read
|
||||
- Write
|
||||
- AskUserQuestion
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ allowed-tools:
|
|||
- Read
|
||||
- Write
|
||||
- AskUserQuestion
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
# /gstack-upgrade
|
||||
|
|
|
|||
|
|
@ -97,23 +97,24 @@ fi
|
|||
|
||||
# Ask once (idempotent: if journal exists from a prior partial run, skip ask).
|
||||
if [ ! -f "$JOURNAL" ]; then
|
||||
cat >&2 <<EOF
|
||||
|
||||
[v1.27.0.0] gstack-brain has been renamed to gstack-artifacts.
|
||||
This is a clearer name for what it actually holds: CEO plans, designs,
|
||||
/investigate reports, retros (i.e. artifacts, not behavioral memory).
|
||||
|
||||
This migration will:
|
||||
1. Rename your private GitHub/GitLab repo "$OLD_REPO_NAME" → "$NEW_REPO_NAME"
|
||||
2. mv ~/.gstack-brain-remote.txt → ~/.gstack-artifacts-remote.txt
|
||||
3. Rename gbrain_sync_mode → artifacts_sync_mode in ~/.gstack/config.yaml
|
||||
4. Update any "## GBrain Configuration" block in CLAUDE.md
|
||||
5. Update gbrain federated source registration (local CLI mode)
|
||||
OR print commands for your brain admin (remote MCP mode)
|
||||
|
||||
Each step is journaled so a Ctrl-C mid-flight is safe to re-run.
|
||||
|
||||
EOF
|
||||
# printf, not a heredoc: bash 5.3 heredocs >512B deadlock on macOS when the
|
||||
# kernel grants 512-byte pipe buffers (pipe-KVA pressure; no F_GETPIPE_SZ).
|
||||
printf '%s\n' \
|
||||
'' \
|
||||
' [v1.27.0.0] gstack-brain has been renamed to gstack-artifacts.' \
|
||||
' This is a clearer name for what it actually holds: CEO plans, designs,' \
|
||||
' /investigate reports, retros (i.e. artifacts, not behavioral memory).' \
|
||||
'' \
|
||||
' This migration will:' \
|
||||
" 1. Rename your private GitHub/GitLab repo \"$OLD_REPO_NAME\" → \"$NEW_REPO_NAME\"" \
|
||||
' 2. mv ~/.gstack-brain-remote.txt → ~/.gstack-artifacts-remote.txt' \
|
||||
' 3. Rename gbrain_sync_mode → artifacts_sync_mode in ~/.gstack/config.yaml' \
|
||||
' 4. Update any "## GBrain Configuration" block in CLAUDE.md' \
|
||||
' 5. Update gbrain federated source registration (local CLI mode)' \
|
||||
' OR print commands for your brain admin (remote MCP mode)' \
|
||||
'' \
|
||||
' Each step is journaled so a Ctrl-C mid-flight is safe to re-run.' \
|
||||
'' >&2
|
||||
if [ -t 0 ]; then
|
||||
printf " Proceed? [Y/n/skip-for-now]: " >&2
|
||||
read -r REPLY || REPLY=""
|
||||
|
|
|
|||
|
|
@ -70,22 +70,23 @@ is_local_engine_missing() {
|
|||
}
|
||||
|
||||
if is_remote_http_mcp && is_local_engine_missing; then
|
||||
cat <<'NOTICE'
|
||||
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ gstack v1.37.0.0 — split-engine gbrain │
|
||||
│ │
|
||||
│ Symbol-aware code search is now available on this machine. │
|
||||
│ Your remote brain at gbrain MCP keeps working as today; you can │
|
||||
│ add a tiny local PGLite (~30s, no accounts) for `gbrain │
|
||||
│ code-def` / `code-refs` / `code-callers` queries per worktree. │
|
||||
│ │
|
||||
│ Run /setup-gbrain to opt in at Step 4.5. Or skip this notice │
|
||||
│ permanently: │
|
||||
│ gstack-config set local_code_index_offered true │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
|
||||
NOTICE
|
||||
# printf, not a heredoc: bash 5.3 heredocs >512B deadlock on macOS when the
|
||||
# kernel grants 512-byte pipe buffers (pipe-KVA pressure; no F_GETPIPE_SZ).
|
||||
printf '%s\n' \
|
||||
'' \
|
||||
' ┌──────────────────────────────────────────────────────────────────┐' \
|
||||
' │ gstack v1.37.0.0 — split-engine gbrain │' \
|
||||
' │ │' \
|
||||
' │ Symbol-aware code search is now available on this machine. │' \
|
||||
' │ Your remote brain at gbrain MCP keeps working as today; you can │' \
|
||||
' │ add a tiny local PGLite (~30s, no accounts) for `gbrain │' \
|
||||
' │ code-def` / `code-refs` / `code-callers` queries per worktree. │' \
|
||||
' │ │' \
|
||||
' │ Run /setup-gbrain to opt in at Step 4.5. Or skip this notice │' \
|
||||
' │ permanently: │' \
|
||||
' │ gstack-config set local_code_index_offered true │' \
|
||||
' └──────────────────────────────────────────────────────────────────┘' \
|
||||
''
|
||||
fi
|
||||
|
||||
# Always touch done so we don't print again, regardless of state-match outcome.
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ Conventions:
|
|||
- [/plan-devex-review](plan-devex-review/SKILL.md): Interactive developer experience plan review.
|
||||
- [/plan-eng-review](plan-eng-review/SKILL.md): Eng manager-mode plan review.
|
||||
- [/plan-tune](plan-tune/SKILL.md): Self-tuning question sensitivity + developer psychographic for gstack (v1: observational).
|
||||
- [/pr-prep](pr-prep/SKILL.md): Pre-PR upstream duplicate audit.
|
||||
- [/qa](qa/SKILL.md): Systematically QA test a web application and fix bugs found.
|
||||
- [/qa-only](qa-only/SKILL.md): Report-only QA testing.
|
||||
- [/retro](retro/SKILL.md): Weekly engineering retrospective.
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ hooks:
|
|||
- type: command
|
||||
command: "bash $HOME/.claude/skills/gstack/freeze/bin/check-freeze.sh"
|
||||
statusMessage: "Checking freeze boundary..."
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ hooks:
|
|||
command: "bash $HOME/.claude/skills/gstack/freeze/bin/check-freeze.sh"
|
||||
statusMessage: "Checking freeze boundary..."
|
||||
sensitive: true
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
# /guard — Full Safety Mode
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ allowed-tools:
|
|||
- Glob
|
||||
- Grep
|
||||
- AskUserQuestion
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
@ -393,6 +394,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -444,6 +447,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ allowed-tools:
|
|||
- Glob
|
||||
- Grep
|
||||
- AskUserQuestion
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -432,6 +432,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -483,6 +485,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ triggers:
|
|||
- clean the ios debug bridge
|
||||
- remove debugbridge
|
||||
- strip the gstack ios instrumentation
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
@ -395,6 +396,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -446,6 +449,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ triggers:
|
|||
- clean the ios debug bridge
|
||||
- remove debugbridge
|
||||
- strip the gstack ios instrumentation
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ triggers:
|
|||
- review the ios design
|
||||
- audit the iphone app visuals
|
||||
- design qa the ios app
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
@ -397,6 +398,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -448,6 +451,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ triggers:
|
|||
- review the ios design
|
||||
- audit the iphone app visuals
|
||||
- design qa the ios app
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ triggers:
|
|||
- fix this ios bug
|
||||
- patch the iphone app
|
||||
- auto-fix the ios issue
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
@ -398,6 +399,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -449,6 +452,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ triggers:
|
|||
- fix this ios bug
|
||||
- patch the iphone app
|
||||
- auto-fix the ios issue
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ triggers:
|
|||
- test my ios app
|
||||
- find bugs on the device
|
||||
- qa the ios app
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
@ -401,6 +402,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -452,6 +455,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ triggers:
|
|||
- test my ios app
|
||||
- find bugs on the device
|
||||
- qa the ios app
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ triggers:
|
|||
- resync the ios debug bridge
|
||||
- regenerate ios accessors
|
||||
- update the gstack ios instrumentation
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
@ -395,6 +396,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -446,6 +449,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ triggers:
|
|||
- resync the ios debug bridge
|
||||
- regenerate ios accessors
|
||||
- update the gstack ios instrumentation
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -390,6 +390,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -441,6 +443,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ triggers:
|
|||
allowed-tools:
|
||||
- Bash
|
||||
- Read
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
@ -391,6 +392,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -442,6 +445,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ allowed-tools:
|
|||
- Bash
|
||||
- Read
|
||||
sensitive: false
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
# /landing-report — Version Queue Dashboard
|
||||
|
|
|
|||
|
|
@ -393,6 +393,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -444,6 +446,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ allowed-tools:
|
|||
- Bash
|
||||
- Read
|
||||
- AskUserQuestion
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ allowed-tools:
|
|||
- Bash
|
||||
- Read
|
||||
- AskUserQuestion
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -428,6 +428,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -479,6 +481,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ allowed-tools:
|
|||
- Read
|
||||
- AskUserQuestion
|
||||
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
@ -390,6 +391,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -441,6 +444,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ allowed-tools:
|
|||
- Read
|
||||
- AskUserQuestion
|
||||
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ allowed-tools:
|
|||
- Read
|
||||
- AskUserQuestion
|
||||
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
@ -392,6 +393,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -443,6 +446,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ allowed-tools:
|
|||
- Read
|
||||
- AskUserQuestion
|
||||
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -422,6 +422,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -473,6 +475,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -394,6 +394,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -445,6 +447,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ triggers:
|
|||
- developer experience review
|
||||
- dx plan review
|
||||
- check developer onboarding
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
@ -400,6 +401,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -451,6 +454,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ triggers:
|
|||
- developer experience review
|
||||
- dx plan review
|
||||
- check developer onboarding
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -398,6 +398,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -449,6 +451,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ allowed-tools:
|
|||
- AskUserQuestion
|
||||
- Glob
|
||||
- Grep
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
@ -403,6 +404,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -454,6 +457,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ allowed-tools:
|
|||
- AskUserQuestion
|
||||
- Glob
|
||||
- Grep
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,411 @@
|
|||
---
|
||||
name: pr-prep
|
||||
preamble-tier: 4
|
||||
version: 0.1.0
|
||||
description: |
|
||||
Pre-PR upstream duplicate audit. Walks `git log base..HEAD`, derives
|
||||
search keywords from commit subjects + changed file paths, queries
|
||||
upstream issues + PRs via `gh`, scores each commit against upstream
|
||||
collisions (EXACT_DUP / OVERLAP / SIBLING / CLEAN), and refuses to
|
||||
proceed when EXACT_DUP found. Use when asked to "audit my PR",
|
||||
"check for duplicates", "pr-prep", "is this already filed",
|
||||
"upstream check before PR", or "pre-PR audit".
|
||||
Proactively invoke this skill (do NOT skip the audit) before any
|
||||
`gh pr create` against a tracked upstream repo. Hooks into /ship
|
||||
as Step 0. (gstack)
|
||||
allowed-tools:
|
||||
- Bash
|
||||
- Read
|
||||
- Grep
|
||||
- Glob
|
||||
- AskUserQuestion
|
||||
triggers:
|
||||
- pr-prep
|
||||
- audit my PR
|
||||
- check for duplicates
|
||||
- upstream check
|
||||
- pre-PR audit
|
||||
- is this already filed
|
||||
- dup PR check
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
||||
{{BASE_BRANCH_DETECT}}
|
||||
|
||||
# pr-prep: Pre-PR Upstream Duplicate Audit
|
||||
|
||||
You are running the `/pr-prep` workflow. This is a **read-only audit** that
|
||||
verifies your branch's commits against upstream issues + PRs before you
|
||||
file a duplicate. Refuses to proceed only on hard duplicates; everything
|
||||
else is informational.
|
||||
|
||||
**Why this exists:** every contributor faces the upstream-dup risk.
|
||||
Open issues sit for weeks. Multiple PRs converge on the same surface.
|
||||
Filing a dup wastes reviewer time, contributor goodwill, and your own
|
||||
branch cleanup. This skill catches dups in ~30s of `gh` queries
|
||||
*before* the PR exists.
|
||||
|
||||
**Output:** per-commit collision report with severity buckets +
|
||||
recommended action.
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Pre-flight
|
||||
|
||||
1. Run `git status` (never with `-uall`). Working tree must be clean
|
||||
or have only the commits-being-audited. Abort cleanly if the
|
||||
working tree has unrelated mid-edit state.
|
||||
|
||||
2. Determine the base branch (already set by `{{BASE_BRANCH_DETECT}}`
|
||||
into `$BASE_BRANCH`). Honor `--base <name>` flag override.
|
||||
|
||||
3. Resolve the upstream repo via `gh repo view --json nameWithOwner -q .nameWithOwner`.
|
||||
Default uses `origin`; override via `--repo owner/name`.
|
||||
|
||||
4. **Read the upstream `CONTRIBUTING.md` (if present)** and surface its
|
||||
pre-push gates + test requirements so the agent knows what must
|
||||
pass BEFORE filing. Cache to `/tmp/pr-prep-contributing.md` for
|
||||
the rest of the run.
|
||||
|
||||
```bash
|
||||
gh api "repos/$REPO/contents/CONTRIBUTING.md" --jq .content 2>/dev/null \
|
||||
| base64 -d > /tmp/pr-prep-contributing.md || \
|
||||
gh api "repos/$REPO/contents/contributing.md" --jq .content 2>/dev/null \
|
||||
| base64 -d > /tmp/pr-prep-contributing.md || \
|
||||
echo "" > /tmp/pr-prep-contributing.md
|
||||
```
|
||||
|
||||
Extract + echo at this step (no need to dump the whole file in the
|
||||
final report — the agent uses it inline when writing PR bodies):
|
||||
- Required pre-push commands (e.g. `bun run verify`, `npm test`,
|
||||
`cargo test`). Look for "before pushing", "pre-push", "verify",
|
||||
"must pass", "required" headings.
|
||||
- Test layout conventions (where do unit / e2e / regression tests
|
||||
belong). Look for "Writing tests", "test structure" sections.
|
||||
- Branch naming / commit message conventions. Look for "branch
|
||||
name", "commit format", "conventional commits". If
|
||||
`CONTRIBUTING.md` is silent on commit format, infer the
|
||||
de-facto standard from real history:
|
||||
`git log upstream/$BASE_BRANCH --no-merges -20 --format='%s%n%b%n--'`.
|
||||
Note the subject shape (e.g. `type(scope): subject`), whether
|
||||
bodies are prose or bullets, and any required trailer (e.g. a
|
||||
`Co-Authored-By:` line). This is the **authoritative** commit
|
||||
style for the PR — see Step 4.6.
|
||||
- Welcomed PR areas (if listed). Skips contributions that conflict
|
||||
with the repo's roadmap.
|
||||
- Banned patterns (e.g. "never add to allowlist", "no new mocks",
|
||||
"no breaking changes"). Treat as hard gates.
|
||||
|
||||
5. Sanity-check: at least 1 commit in `$BASE_BRANCH..HEAD`. If zero,
|
||||
abort with "no commits to audit; you're already on $BASE_BRANCH".
|
||||
|
||||
```bash
|
||||
BASE="${BASE_BRANCH:-main}"
|
||||
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner 2>/dev/null)
|
||||
COMMITS=$(git log "$BASE"..HEAD --pretty='%H' 2>/dev/null)
|
||||
if [ -z "$COMMITS" ]; then
|
||||
echo "No commits to audit: $(git branch --show-current) is at $BASE."
|
||||
exit 0
|
||||
fi
|
||||
echo "Auditing $(echo "$COMMITS" | wc -l | tr -d ' ') commits against $REPO@$BASE"
|
||||
```
|
||||
|
||||
## Step 2: Walk each commit, extract search signals
|
||||
|
||||
For each commit hash:
|
||||
- **Subject**: `git show -s --format=%s <sha>` — strip conventional-commit
|
||||
prefix (`fix(scope):`, `feat:`, `chore(deps):`, etc).
|
||||
- **Changed files**: `git show --stat --name-only --format= <sha>`.
|
||||
- **Keywords**: from subject, drop stop words + verbs (fix/add/update/
|
||||
bump/remove). Keep 3-6 meaningful tokens.
|
||||
|
||||
Build a search query per commit by joining keywords. Example:
|
||||
- Subject: `fix(synopsis): tail-truncate documentText for small-model chat handlers`
|
||||
- Keywords: `synopsis tail-truncate documentText small-model chat`
|
||||
- Query: `synopsis documentText truncate`
|
||||
|
||||
Cap query to ~5 tokens. Too long → zero matches. Too short → noisy
|
||||
matches.
|
||||
|
||||
## Step 3: Query upstream issues + PRs
|
||||
|
||||
For each commit's query, run:
|
||||
|
||||
```bash
|
||||
# Open issues + PRs (highest collision risk)
|
||||
gh issue list --repo "$REPO" --state open --search "$QUERY" --limit 8 --json number,title,url,labels
|
||||
gh pr list --repo "$REPO" --state open --search "$QUERY" --limit 8 --json number,title,url,headRefName,author
|
||||
|
||||
# Closed in last 90 days (might be unreleased master fix)
|
||||
gh issue list --repo "$REPO" --state closed --search "$QUERY" --limit 5 --json number,title,url,closedAt
|
||||
gh pr list --repo "$REPO" --state merged --search "$QUERY" --limit 5 --json number,title,url,mergedAt
|
||||
```
|
||||
|
||||
Hard guard: skip if the search call returns rate-limit (HTTP 429).
|
||||
Print warning + suggest `gh auth refresh`. Don't false-clear on
|
||||
rate-limit silence.
|
||||
|
||||
## Step 4: Score each upstream hit
|
||||
|
||||
For every issue/PR returned, compute a collision score:
|
||||
|
||||
- **Title token overlap (Jaccard)**: intersect commit-subject keywords
|
||||
with upstream-title keywords. ≥0.5 = strong match.
|
||||
- **File overlap (open PRs only)**: `gh pr diff <number> --name-only`
|
||||
vs the commit's changed files. ≥0.5 = strong match.
|
||||
- **State weighting**:
|
||||
- OPEN PR → 1.0× (highest dup risk)
|
||||
- OPEN issue → 0.7× (someone's tracking it)
|
||||
- MERGED last 14 days → 0.6× (might be unreleased)
|
||||
- CLOSED issue → 0.2× (low risk, but useful context)
|
||||
|
||||
Final severity bucket per commit:
|
||||
|
||||
| Bucket | Trigger |
|
||||
|---|---|
|
||||
| **EXACT_DUP** | Any OPEN PR with title Jaccard ≥0.6 OR file overlap ≥0.6 |
|
||||
| **OVERLAP** | Any OPEN PR/issue with score ≥0.3, or ≥3 OPEN issues |
|
||||
| **SIBLING** | OPEN issues but no PR; or merged-recently with overlap |
|
||||
| **CLEAN** | No hits, or only old closed issues |
|
||||
|
||||
This bucketing is implemented deterministically in `bin/gstack-pr-prep-score`
|
||||
(pure function, unit-tested in `test/pr-prep-score.test.ts`) — the canonical
|
||||
scorer. Pipe each commit's candidate set through it as JSON rather than
|
||||
re-deriving the thresholds inline:
|
||||
|
||||
```bash
|
||||
echo "$CANDIDATE_JSON" | ~/.claude/skills/gstack/bin/gstack-pr-prep-score
|
||||
# -> {"bucket":"EXACT_DUP","topScore":1,"openIssueCount":0,"reasons":[...]}
|
||||
```
|
||||
|
||||
## Step 4.4: Second-opinion review via codex (CLEAN commits only)
|
||||
|
||||
For each commit bucketed CLEAN (i.e. not duplicating upstream work),
|
||||
run an independent second-opinion code review BEFORE the PR is opened.
|
||||
Catches bugs the author missed without spending reviewer attention
|
||||
upstream.
|
||||
|
||||
The skill assumes `codex` CLI is on PATH (OpenAI's official CLI;
|
||||
`brew install codex` on macOS). If absent, emit a soft warning + skip
|
||||
this step — don't block. Different model family from Claude gives
|
||||
genuine independent signal.
|
||||
|
||||
```bash
|
||||
if command -v codex >/dev/null 2>&1; then
|
||||
for sha in $CLEAN_COMMIT_SHAS; do
|
||||
diff=$(git show "$sha" --stat --pretty=format:"%s")
|
||||
subject=$(git log -1 --format=%s "$sha")
|
||||
codex review "Review commit ${sha:0:8} '${subject}' for correctness,
|
||||
edge cases, and CONTRIBUTING.md compliance. Focus on: regression
|
||||
risk on adjacent code paths, missing tests, hash/version-bump
|
||||
invariants if touching cache keys, ordering bugs if touching
|
||||
conditionals or dispatchers. Flag P0/P1/P2 issues with file:line."
|
||||
done
|
||||
else
|
||||
echo "[pr-prep] codex CLI not found — skipping second-opinion review.
|
||||
Install via 'brew install codex' or pin a fork-specific reviewer in
|
||||
your skill config."
|
||||
fi
|
||||
```
|
||||
|
||||
Surface findings in the report under each commit as a `Codex P{N}`
|
||||
line. P0/P1 findings escalate the commit's severity to OVERLAP at
|
||||
minimum (don't file as CLEAN until addressed). P2 findings stay
|
||||
CLEAN — author decides whether to fix-before-file or note-in-PR-body.
|
||||
|
||||
Real-world example (2026-05-26 motivating case):
|
||||
- PR #1427 (synopsis doc truncate) → codex P2: env-overridable cap
|
||||
not folded into `computeCorpusGeneration` hash. Different caps
|
||||
produce same `corpus_generation` → cache invalidation breaks.
|
||||
Fixed pre-merge, pushed as follow-up commit, comment posted to PR.
|
||||
- PR #1428 (models doctor args[0]) → codex P2: `--help` regressed
|
||||
into running network probes. Reorder ternary so `hasHelp` checked
|
||||
first. Fixed pre-merge.
|
||||
|
||||
Both findings were structural, not stylistic. Author missed them
|
||||
during own write-up. Net cost avoided: 2 review-cycle ping-pongs
|
||||
upstream + a follow-up fix PR per finding.
|
||||
|
||||
## Step 4.5: Surface CONTRIBUTING.md pre-push gates per commit
|
||||
|
||||
For each commit that survives audit (CLEAN / OVERLAP / SIBLING — not
|
||||
EXACT_DUP), check whether the changed files trigger any
|
||||
CONTRIBUTING.md-stated test path. Example: a commit touching
|
||||
`src/core/search/*` should run the eval-replay loop per the gbrain
|
||||
CONTRIBUTING.md "Trigger paths" section.
|
||||
|
||||
Annotate each CLEAN/OVERLAP/SIBLING row with:
|
||||
|
||||
```
|
||||
Pre-push gate: bun run verify (from CONTRIBUTING.md)
|
||||
Trigger paths matched: none (no retrieval / no special test required)
|
||||
Tests added in commit: yes / no / not required
|
||||
```
|
||||
|
||||
If `Tests added: no` AND `not required` is unclear, surface as a
|
||||
soft warning in the report but don't block — let the human decide.
|
||||
|
||||
## Step 4.6: Commit-message style conformance
|
||||
|
||||
You are contributing to someone else's repo. Match THEIR commit-message
|
||||
convention, never your own (or your global `CLAUDE.md`) house style. A
|
||||
PR whose commits read in a different voice than the project signals
|
||||
"drive-by fork" and costs reviewer goodwill before a line is read.
|
||||
|
||||
Establish the authoritative style once, from Step 1.4 (in priority
|
||||
order): the upstream `CONTRIBUTING.md` commit rules if present; else the
|
||||
de-facto shape sampled from `git log upstream/$BASE_BRANCH --no-merges`;
|
||||
else the conventional-commits baseline (`type(scope): imperative
|
||||
subject`, blank line, prose body explaining what + why).
|
||||
|
||||
Then check each commit in `$BASE_BRANCH..HEAD` against it:
|
||||
|
||||
- **Subject**: matches the repo's shape (type/scope vocabulary, case,
|
||||
length, imperative mood). Flag a subject that promises content it
|
||||
doesn't contain (e.g. "+ tests" with no test files in the diff).
|
||||
- **Body**: present when the change is non-trivial; same form as the
|
||||
repo (prose vs bullets). Flag a personal template (emoji section
|
||||
headers, bullet glyphs) that the upstream history doesn't use.
|
||||
- **Trailer**: present if upstream requires one. If upstream commits
|
||||
carry a `Co-Authored-By:` (or `Signed-off-by:`) line, every commit
|
||||
here must carry the identical line; if upstream has none, add none.
|
||||
|
||||
Annotate each surviving commit row:
|
||||
|
||||
```
|
||||
Commit style: OK (matches upstream type(scope): + prose + Co-Authored-By)
|
||||
```
|
||||
|
||||
or, on mismatch:
|
||||
|
||||
```
|
||||
Commit style: NON-CONFORMANT
|
||||
- body uses 📝/• house template; upstream uses prose
|
||||
- missing Co-Authored-By trailer that upstream commits carry
|
||||
Fix: git rebase to reword these N commits before filing.
|
||||
```
|
||||
|
||||
Soft warning, never a block — style is not a duplicate. But surface it
|
||||
loudly: it is the cheapest reviewer-goodwill win in the whole audit, and
|
||||
re-wording is far cheaper before the PR exists than after review starts.
|
||||
|
||||
## Step 5: Render report
|
||||
|
||||
Markdown table per commit:
|
||||
|
||||
```
|
||||
## Audit: branch `feat/foo-bar` vs garrytan/gstack@main
|
||||
|
||||
### commit 20ed0eee fix(models): dispatch subcommand reads args[0] not args[1]
|
||||
|
||||
| Severity | # | Title | State | Author | Score |
|
||||
|---|---|---|---|---|---|
|
||||
| CLEAN | — | (no matches above threshold) | — | — | — |
|
||||
|
||||
Commit style: OK (matches upstream type(scope): + prose + Co-Authored-By)
|
||||
|
||||
**Action:** safe to file.
|
||||
|
||||
### commit ac213aa6 feat(synopsis): tail-truncate documentText
|
||||
|
||||
| Severity | # | Title | State | Author | Score |
|
||||
|---|---|---|---|---|---|
|
||||
| EXACT_DUP | #1358 | fix: allow contextual synopsis model env override | OPEN | lost9999 | 0.78 |
|
||||
| OVERLAP | #1356 | fix: classify contextual synopsis transient errors | OPEN | lost9999 | 0.34 |
|
||||
|
||||
**Action:** close mine, comment on #1358 with my angle. DO NOT file new PR.
|
||||
```
|
||||
|
||||
Print summary at end:
|
||||
|
||||
```
|
||||
Summary: 1 EXACT_DUP, 1 CLEAN. 1 commit blocked.
|
||||
```
|
||||
|
||||
## Step 6: Refusal on EXACT_DUP
|
||||
|
||||
If ANY commit is EXACT_DUP and `--force` is NOT set, exit non-zero
|
||||
with a pinpoint message:
|
||||
|
||||
```
|
||||
✗ Blocked: 1 commit duplicates open upstream work.
|
||||
|
||||
- ac213aa6 → #1358 (lost9999, OPEN 14d)
|
||||
|
||||
Resolutions:
|
||||
1. Close your version, comment on #1358 with your angle.
|
||||
2. Cherry-pick the unique parts to a new branch + file separately.
|
||||
3. Override with `/pr-prep --force` if you've coordinated with
|
||||
the existing PR author.
|
||||
```
|
||||
|
||||
Always exit 0 on OVERLAP / SIBLING / CLEAN — those are informational.
|
||||
|
||||
## Step 7: /ship integration
|
||||
|
||||
When invoked by `/ship` (env `GSTACK_FROM_SHIP=1`):
|
||||
- Skip the interactive AskUserQuestion confirmations
|
||||
- Exit 0 on CLEAN/OVERLAP/SIBLING
|
||||
- Exit 1 on EXACT_DUP (blocks /ship)
|
||||
- Print machine-readable JSON to a known path so /ship can render
|
||||
collisions in the PR body
|
||||
|
||||
## Flags
|
||||
|
||||
| Flag | Default | Effect |
|
||||
|---|---|---|
|
||||
| `--base <name>` | `main` | Base branch for commit walk |
|
||||
| `--repo owner/name` | from `gh repo view` | Upstream repo for queries |
|
||||
| `--force` | off | Proceed past EXACT_DUP (still print report) |
|
||||
| `--json` | off | Machine-readable output, no markdown table |
|
||||
| `--limit N` | 8 | Per-query result cap |
|
||||
| `--no-file-diff` | off | Skip `gh pr diff` calls (faster, less accurate) |
|
||||
|
||||
## Cost + speed
|
||||
|
||||
- ~30-60s for a 5-commit branch
|
||||
- 4 `gh` calls per commit (open issues, open PRs, closed issues, merged PRs)
|
||||
- 1 extra `gh pr diff` per OPEN PR hit (capped at 5)
|
||||
- ~25-50 `gh` calls total on a typical branch
|
||||
- gh CLI personal rate limit: 5000/hr authenticated. Safe headroom.
|
||||
|
||||
## Real-world example (motivating case 2026-05-26)
|
||||
|
||||
User's branch on `garrytan/gbrain` had 8 commits ready for upstream
|
||||
PRs. Without pr-prep, 4 of 4 unverified commits would have been
|
||||
duplicates:
|
||||
- `e96332c5` (reindex CLI_ONLY one-char fix) → #913 OPEN 14 days, same fix
|
||||
- `74819cec` (sourceId fallback) → #836 OPEN, threads sourceId
|
||||
- `787da2af` + `829099f9` (synopsis env-override) → #1358 OPEN, same env-override
|
||||
- `e0133d8a` (LM Studio recipe) → #1051 + #1329, crowded space
|
||||
|
||||
Cost avoided: 4 noise PRs, 4 reviewer triage rounds, contributor
|
||||
goodwill hit, 4 branch closures. pr-prep catches all 4 in ~45s.
|
||||
|
||||
---
|
||||
|
||||
## Implementation note for future maintainers
|
||||
|
||||
Two reasonable build modes:
|
||||
1. **Inline bash in SKILL.md** (current) — agent walks the steps,
|
||||
composes `gh` calls, computes Jaccard via `comm` + `wc`. Slower,
|
||||
more transparent.
|
||||
2. **Helper script `bin/gstack-pr-prep`** — bash entry point that
|
||||
does the heavy lifting, agent just orchestrates + renders.
|
||||
Faster, more testable. Migration path when v0.2.0 lands tests.
|
||||
|
||||
v0.1.0 ships mode 1 because it's reviewable in a single file. v0.2.0
|
||||
should move the Jaccard math + report rendering into `bin/`.
|
||||
|
||||
## Out of scope (v0.1.0)
|
||||
|
||||
- Diff-content (not just file-name) similarity scoring. Useful but
|
||||
expensive (`gh pr diff` × N × full body).
|
||||
- Cross-repo audit (e.g., fix in fork A applies to upstream B).
|
||||
- LLM-judged semantic dup detection. Out of scope for a deterministic
|
||||
pre-flight check.
|
||||
- Auto-comment on the upstream PR. Owner must decide what to say.
|
||||
|
||||
These belong in a v0.2+ wave once the deterministic gate proves out.
|
||||
|
|
@ -393,6 +393,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -444,6 +446,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -399,6 +399,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -450,6 +452,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ gbrain:
|
|||
glob: "~/.gstack/projects/{repo_slug}/learnings.jsonl"
|
||||
tail: 10
|
||||
render_as: "## Recent learnings"
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
@ -410,6 +411,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -461,6 +464,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ gbrain:
|
|||
glob: "~/.gstack/projects/{repo_slug}/learnings.jsonl"
|
||||
tail: 10
|
||||
render_as: "## Recent learnings"
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -395,6 +395,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -446,6 +448,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ triggers:
|
|||
- pull from
|
||||
- extract from
|
||||
- what is on
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
@ -391,6 +392,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -442,6 +445,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ triggers:
|
|||
- pull from
|
||||
- extract from
|
||||
- what is on
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -208,6 +208,11 @@
|
|||
"routing": "Review which AskUserQuestion prompts fire across gstack skills, set per-question preferences\n(never-ask / always-ask / ask-only-for-one-way), inspect the dual-track\nprofile (what you declared vs what your behavior suggests), and enable/disable\nquestion tuning. Conversational interface — no CLI syntax required.\n\nUse when asked to \"tune questions\", \"stop asking me that\", \"too many questions\",\n\"show my profile\", \"what questions have I been asked\", \"show my vibe\",\n\"developer profile\", or \"turn off question tuning\". \n\nProactively suggest when the user says the same gstack question has come up before,\nor when they explicitly override a recommendation for the Nth time.",
|
||||
"voice_line": null
|
||||
},
|
||||
"pr-prep": {
|
||||
"lead": "Pre-PR upstream duplicate audit.",
|
||||
"routing": "Walks `git log base..HEAD`, derives\nsearch keywords from commit subjects + changed file paths, queries\nupstream issues + PRs via `gh`, scores each commit against upstream\ncollisions (EXACT_DUP / OVERLAP / SIBLING / CLEAN), and refuses to\nproceed when EXACT_DUP found. Use when asked to \"audit my PR\",\n\"check for duplicates\", \"pr-prep\", \"is this already filed\",\n\"upstream check before PR\", or \"pre-PR audit\".\nProactively invoke this skill (do NOT skip the audit) before any\n`gh pr create` against a tracked upstream repo. Hooks into /ship\nas Step 0.",
|
||||
"voice_line": null
|
||||
},
|
||||
"qa": {
|
||||
"lead": "Systematically QA test a web application and fix bugs found.",
|
||||
"routing": "Runs QA testing,\nthen iteratively fixes bugs in source code, committing each fix atomically and\nre-verifying. Use when asked to \"qa\", \"QA\", \"test this site\", \"find bugs\",\n\"test and fix\", or \"fix what's broken\".\nProactively suggest when the user says a feature is ready for testing\nor asks \"does this work?\". Three tiers: Quick (critical/high only),\nStandard (+ medium), Exhaustive (+ cosmetic). Produces before/after health scores,\nfix evidence, and a ship-readiness summary. For report-only mode, use /qa-only.",
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use \`Completeness: N/10\` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: \`Note: options differ in kind, not coverage — no completeness score.\`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set \`multiSelect: true\` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score \`Completeness: <atom>=X/10\` per atom. Bundles or combinations of the same underlying items (\`E1+E3\`, \`All three\`, \`E1 only\`, \`Defer all\`) are mutually exclusive by construction — \`multiSelect: false\`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: \`✅ No cons — this is a hard-stop choice\`.
|
||||
|
||||
Neutral posture: \`Recommendation: <default> — this is a taste call, no strong preference either way\`; \`(recommended)\` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -115,6 +117,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] \`multiSelect: false\` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ allowed-tools:
|
|||
- Bash
|
||||
- Read
|
||||
- AskUserQuestion
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ allowed-tools:
|
|||
- Bash
|
||||
- Read
|
||||
- AskUserQuestion
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ allowed-tools:
|
|||
- Glob
|
||||
- Grep
|
||||
- AskUserQuestion
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
@ -394,6 +395,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -445,6 +448,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ allowed-tools:
|
|||
- Glob
|
||||
- Grep
|
||||
- AskUserQuestion
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ allowed-tools:
|
|||
- Glob
|
||||
- Grep
|
||||
- AskUserQuestion
|
||||
disable-model-invocation: true
|
||||
---
|
||||
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
|
||||
<!-- Regenerate: bun run gen:skill-docs -->
|
||||
|
|
@ -393,6 +394,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -444,6 +447,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ allowed-tools:
|
|||
- Glob
|
||||
- Grep
|
||||
- AskUserQuestion
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
|
|
|||
|
|
@ -395,6 +395,8 @@ ELI10 is always present, in plain English, not function names. Recommendation is
|
|||
|
||||
Completeness: use `Completeness: N/10` only when options differ in coverage. 10 = complete, 7 = happy path, 3 = shortcut. If options differ in kind, write: `Note: options differ in kind, not coverage — no completeness score.`
|
||||
|
||||
Single-select is the DEFAULT — options are mutually exclusive. Set `multiSelect: true` only when every option is an independently-selectable atom whose pro/con/effort stands alone; then score `Completeness: <atom>=X/10` per atom. Bundles or combinations of the same underlying items (`E1+E3`, `All three`, `E1 only`, `Defer all`) are mutually exclusive by construction — `multiSelect: false`, score per option LETTER, and never write "Multi-select" into the question text. Tell: a defer/none option or a do-everything option in the list proves the question is single-select. With 5+ independent atoms use the split chain below, not multiSelect.
|
||||
|
||||
Pros / cons: use ✅ and ❌. Minimum 2 pros and 1 con per option when the choice is real; Minimum 40 characters per bullet. Hard-stop escape for one-way/destructive confirmations: `✅ No cons — this is a hard-stop choice`.
|
||||
|
||||
Neutral posture: `Recommendation: <default> — this is a taste call, no strong preference either way`; `(recommended)` STAYS on the default option for AUTO_DECIDE.
|
||||
|
|
@ -446,6 +448,7 @@ Before calling AskUserQuestion, verify:
|
|||
- [ ] ELI10 paragraph present (stakes line too)
|
||||
- [ ] Recommendation line present with concrete reason
|
||||
- [ ] Completeness scored (coverage) OR kind-note present (kind)
|
||||
- [ ] `multiSelect: false` unless every option is an independently-selectable atom (bundles/combinations ⇒ single-select)
|
||||
- [ ] Every option has ≥2 ✅ and ≥1 ❌, each ≥40 chars (or hard-stop escape)
|
||||
- [ ] (recommended) label on one option (even for neutral-posture)
|
||||
- [ ] Dual-scale effort labels on effort-bearing options (human / CC)
|
||||
|
|
@ -969,7 +972,55 @@ If CEO Review is missing, mention as informational ("CEO Review not run — reco
|
|||
|
||||
For Design Review: run `source <(~/.claude/skills/gstack/bin/gstack-diff-scope <base> 2>/dev/null)`. If `SCOPE_FRONTEND=true` and no design review (plan-design-review or design-review-lite) exists in the dashboard, mention: "Design Review not run — this PR changes frontend code. The lite design check will run automatically in Step 9, but consider running /design-review for a full visual audit post-implementation." Still never block.
|
||||
|
||||
Continue to Step 2 — do NOT block or ask. Ship runs its own review in Step 9.
|
||||
Continue to Step 1.5 — do NOT block or ask. Ship runs its own review in Step 9.
|
||||
|
||||
---
|
||||
|
||||
## Step 1.5: Upstream duplicate audit (pr-prep gate)
|
||||
|
||||
Catches the case where a contributor's branch would file a PR that
|
||||
duplicates an already-open upstream PR or issue. Without this gate
|
||||
the duplicate gets filed and is closed days later, costing reviewer
|
||||
time + contributor goodwill.
|
||||
|
||||
Skip on:
|
||||
- Forks that don't have a tracked upstream remote
|
||||
- Branches where the base is the user's own fork (no upstream to dup)
|
||||
- Explicit `--skip-pr-prep` flag
|
||||
|
||||
Otherwise run `/pr-prep` inline with `GSTACK_FROM_SHIP=1`:
|
||||
|
||||
```bash
|
||||
# Skip if no upstream remote configured (solo-repo case)
|
||||
if ! gh repo view --json nameWithOwner -q .nameWithOwner >/dev/null 2>&1; then
|
||||
echo "[ship] no upstream repo detected, skipping pr-prep audit"
|
||||
else
|
||||
GSTACK_FROM_SHIP=1 ~/.claude/skills/gstack/bin/gstack-skill pr-prep --base "$BASE_BRANCH" --json > /tmp/ship-pr-prep.json 2>&1
|
||||
PR_PREP_EXIT=$?
|
||||
if [ "$PR_PREP_EXIT" -eq 1 ]; then
|
||||
# EXACT_DUP found
|
||||
cat /tmp/ship-pr-prep.json
|
||||
echo ""
|
||||
echo "✗ Ship aborted: pr-prep found exact duplicate upstream work."
|
||||
echo " Resolution paths:"
|
||||
echo " 1. Close your version, comment on the upstream PR with your angle"
|
||||
echo " 2. Cherry-pick unique parts to a new branch + file separately"
|
||||
echo " 3. Override with /ship --skip-pr-prep if coordinated with the upstream PR author"
|
||||
exit 1
|
||||
fi
|
||||
# CLEAN / OVERLAP / SIBLING — render summary, continue
|
||||
jq -r '.summary' /tmp/ship-pr-prep.json 2>/dev/null || true
|
||||
fi
|
||||
```
|
||||
|
||||
Note: the JSON report path (`/tmp/ship-pr-prep.json`) is read again in
|
||||
Step 19 (PR body assembly) to surface SIBLING / OVERLAP findings as a
|
||||
collapsed "Upstream context" section in the PR body. SIBLING context
|
||||
helps reviewers triage faster; it does NOT block ship.
|
||||
|
||||
If the pr-prep skill is not installed (older gstack install), fall
|
||||
through with a stderr warn and continue. Don't hard-fail ship on a
|
||||
missing skill.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -97,7 +97,55 @@ If CEO Review is missing, mention as informational ("CEO Review not run — reco
|
|||
|
||||
For Design Review: run `source <(~/.claude/skills/gstack/bin/gstack-diff-scope <base> 2>/dev/null)`. If `SCOPE_FRONTEND=true` and no design review (plan-design-review or design-review-lite) exists in the dashboard, mention: "Design Review not run — this PR changes frontend code. The lite design check will run automatically in Step 9, but consider running /design-review for a full visual audit post-implementation." Still never block.
|
||||
|
||||
Continue to Step 2 — do NOT block or ask. Ship runs its own review in Step 9.
|
||||
Continue to Step 1.5 — do NOT block or ask. Ship runs its own review in Step 9.
|
||||
|
||||
---
|
||||
|
||||
## Step 1.5: Upstream duplicate audit (pr-prep gate)
|
||||
|
||||
Catches the case where a contributor's branch would file a PR that
|
||||
duplicates an already-open upstream PR or issue. Without this gate
|
||||
the duplicate gets filed and is closed days later, costing reviewer
|
||||
time + contributor goodwill.
|
||||
|
||||
Skip on:
|
||||
- Forks that don't have a tracked upstream remote
|
||||
- Branches where the base is the user's own fork (no upstream to dup)
|
||||
- Explicit `--skip-pr-prep` flag
|
||||
|
||||
Otherwise run `/pr-prep` inline with `GSTACK_FROM_SHIP=1`:
|
||||
|
||||
```bash
|
||||
# Skip if no upstream remote configured (solo-repo case)
|
||||
if ! gh repo view --json nameWithOwner -q .nameWithOwner >/dev/null 2>&1; then
|
||||
echo "[ship] no upstream repo detected, skipping pr-prep audit"
|
||||
else
|
||||
GSTACK_FROM_SHIP=1 ~/.claude/skills/gstack/bin/gstack-skill pr-prep --base "$BASE_BRANCH" --json > /tmp/ship-pr-prep.json 2>&1
|
||||
PR_PREP_EXIT=$?
|
||||
if [ "$PR_PREP_EXIT" -eq 1 ]; then
|
||||
# EXACT_DUP found
|
||||
cat /tmp/ship-pr-prep.json
|
||||
echo ""
|
||||
echo "✗ Ship aborted: pr-prep found exact duplicate upstream work."
|
||||
echo " Resolution paths:"
|
||||
echo " 1. Close your version, comment on the upstream PR with your angle"
|
||||
echo " 2. Cherry-pick unique parts to a new branch + file separately"
|
||||
echo " 3. Override with /ship --skip-pr-prep if coordinated with the upstream PR author"
|
||||
exit 1
|
||||
fi
|
||||
# CLEAN / OVERLAP / SIBLING — render summary, continue
|
||||
jq -r '.summary' /tmp/ship-pr-prep.json 2>/dev/null || true
|
||||
fi
|
||||
```
|
||||
|
||||
Note: the JSON report path (`/tmp/ship-pr-prep.json`) is read again in
|
||||
Step 19 (PR body assembly) to surface SIBLING / OVERLAP findings as a
|
||||
collapsed "Upstream context" section in the PR body. SIBLING context
|
||||
helps reviewers triage faster; it does NOT block ship.
|
||||
|
||||
If the pr-prep skill is not installed (older gstack install), fall
|
||||
through with a stderr warn and continue. Don't hard-fail ship on a
|
||||
missing skill.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue