📝 Summary:
• add `disable-model-invocation: true` to the frontmatter of every
gstack skill that is only ever user-invoked, so their descriptions
drop out of Claude Code's always-loaded prompt (~1,050 tokens per
request on this machine)
• flag lives in each `SKILL.md.tmpl`; generated `SKILL.md` files
regenerated via `bun run gen:skill-docs` (claude host is denylist
frontmatter mode, so the key passes through untouched)
🔧 Technical Improvements:
• flagged (36): benchmark, benchmark-models, canary, careful, codex,
cso, design-html, design-shotgun, devex-review, diagram,
document-generate, document-release, freeze, gstack-upgrade,
guard, health, ios-clean, ios-design-review, ios-fix, ios-qa,
ios-sync, landing-report, make-pdf, open-gstack-browser
(covers the connect-chrome alias), pair-agent, plan-devex-review,
plan-tune, pr-prep, retro, scrape, setup-browser-cookies,
setup-deploy, setup-gbrain, skillify, spec, unfreeze
• kept model-invocable on purpose — every skill named in the
CLAUDE.md skill-routing tables (here and in consumer repos):
autoplan, browse, context-restore/save, design-consultation,
design-review, investigate, land-and-deploy, learn, office-hours,
plan-ceo/design/eng-review, qa, qa-only, review, ship,
sync-gbrain, plus the `_gstack-command` router
• verified: `bun test` tier-1 suites green (733 pass, 0 fail);
`browse/test/sidebar-ux.test.ts` failures reproduce with this
change stashed (73/176 fail on the base tree — pre-existing,
needs a live browse daemon)
📊 Code Changes: 72 insertions, 0 deletions (net +72)
📦 Files Modified:
• 36 × `<skill>/SKILL.md.tmpl` (minor updates — one frontmatter line)
• 36 × `<skill>/SKILL.md` (minor updates — regenerated)
📝 Summary:
• re-run `bun run gen:skill-docs` on unmodified templates and commit
the drift — the working tree had stale generated output (blank-line
churn) left uncommitted by an earlier regen
• 326 deletions across 10 SKILL.md + 6 sections files, whitespace and
section-render drift only; no template changed in this commit
📊 Code Changes: 0 insertions, 326 deletions (net -326)
urlBlocklistFilter compared URLs against the exfiltration blocklist with
case-sensitive substring checks, so an uppercased sink (https://WEBHOOK.SITE/x)
bypassed the guard and reached the scoped browser agent. Normalize the page URL
and extracted content URLs to lowercase before comparing, and make URL
extraction scheme-insensitive so HTTPS:// links are still caught.
Fixes#2190
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Parses package.json overrides + every resolved basic-ftp specifier in bun.lock
(including nested paths like get-uri/basic-ftp) and fails if any is below 5.3.1.
Deterministic and offline. Fires on the pre-fix tree (basic-ftp@5.2.0) and would
also catch a direct-dependency-only bump that leaves a nested vulnerable copy.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
basic-ftp reaches the tree only transitively:
puppeteer-core > @puppeteer/browsers > proxy-agent > pac-proxy-agent > get-uri > basic-ftp
Versions <= 5.3.0 carry four HIGH advisories, all fixed in 5.3.1:
- GHSA-chqc-8p9q-pq6q (CVE-2026-39983) FTP command injection via CRLF
- GHSA-6v7q-wjvx-w8wg incomplete CRLF protection (USER/PASS + MKD bypass)
- GHSA-rpmf-866q-6p89 DoS via unbounded multiline control-response buffering
- GHSA-rp42-5vxx-qpwr DoS via unbounded memory in Client.list()
Pin via a bun `overrides` entry rather than a phantom direct dependency.
Overriding forces every basic-ftp in the tree to 5.3.1, including get-uri's
nested copy; `bun audit` then reports zero basic-ftp advisories (total 37 -> 33,
HIGH 13 -> 9). A direct-dependency bump leaves get-uri/basic-ftp at the
vulnerable version and audit still flags all four.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
endpoint-hash returns "local" for stdio/PGLite, but validators only
allowed hex suffixes, so setup-gbrain could not persist trust policy.
Co-authored-by: Cursor <cursoragent@cursor.com>
Exercise resultFromGeminiStream against current stream-json fixtures
(including empty-success hardening). Recognize GEMINI_API_KEY and map
IneligibleTierError to auth — personal OAuth free-tier is no longer
supported by gemini CLI.
Co-authored-by: Cursor <cursoragent@cursor.com>
GeminiAdapter was reading message.text and result.usage, so current CLI
content/stats events produced empty $0 success rows. Accept content with
an assistant role guard, stats token fallbacks, init model, and treat
empty exit-0 output as an error (#2159).
Co-authored-by: Cursor <cursoragent@cursor.com>
📝 Summary:
• Add a `multiSelect` rule to the shared AskUserQuestion decision-brief
preamble, plus a matching self-check bullet
• Regenerate the 44 SKILL.md surfaces that inline the preamble
🔧 Technical Improvements:
• `generate-ask-user-format.ts` now states that options are mutually
exclusive by DEFAULT, and `multiSelect: true` is legal only when
every option is an independently-selectable atom whose pro/con and
effort stand alone
• Bundles or combinations of the same underlying items (`E1+E3`,
`All three`, `E1 only`, `Defer all`) are mutually exclusive by
construction, so they take `multiSelect: false` and score
`Completeness:` per option LETTER, not per sub-item
• Names the diagnostic tell: a defer/none option or a do-everything
option sitting in the list proves the question is single-select
• Routes 5+ independent atoms to the existing split chain rather than
to `multiSelect`, so the 4-option cap is never silently exceeded
🏗 Architecture:
• The rule lives in the preamble resolver, not in any one skill, so
every skill that renders a decision brief inherits it from one
source; the 44 regenerated `SKILL.md` files are build output
🧾 Reports:
• Regenerated with `gen:skill-docs:user` to match how this branch's
`SKILL.md` were produced (gbrain blocks inlined); the pure-form
`gen:skill-docs` variant strips them and would have carried 326
unrelated deletions
• `bun test test/host-config.test.ts test/skill-validation.test.ts
test/audit-compliance.test.ts test/question-log-hook.test.ts
test/gstack-question-preference.test.ts` — 387 pass, 0 fail across
the four non-golden files
• The three `golden-file regression` tests were ALREADY red at HEAD:
`test/fixtures/golden/*-ship-SKILL.md` are pure-form while the
committed `ship/SKILL.md` is brain-form. Left untouched — a
pre-existing defect, not this change
📊 Code Changes:
• 138 insertions, 0 deletions (net +138)
📦 Files Modified:
• `scripts/resolvers/preamble/generate-ask-user-format.ts`
(substantial changes) — add the single-select rule paragraph and
the `multiSelect: false` self-check bullet
• 44 × `**/SKILL.md` (minor updates) — regenerated preamble
Root cause of months of silent local failure: the sandbox copied skill dirs to
the repo root, but claude >= 2.x resolves slash commands strictly from
registered skills, so /autoplan short-circuited with 'Unknown command' (0
turns, ~1s) on every attempt. Install /autoplan + review skills at
project-level .claude/skills/ (same pattern as skill-routing-e2e).
Also: the transcript filter matched entry.type === 'tool_use', a shape that
never appears at the top level of raw stream-json, so assertions only ever saw
the final result text; filter on assistant/user events instead. Hang
protection accepts the Phase 1 review dispatch (Agent/Task tool call carrying
review instructions) as progress evidence, since full Phase 1 completion is
15+ min of subagent work. Budget raised to 10 min / 40 turns.
Invisible in CI: the file is in neither evals.yml nor evals-periodic.yml
matrices (coverage decision filed in TODOS.md).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
proc.kill() only signals the sh -c wrapper; the claude child survives as an
orphan that inherited our stdout/stderr pipes, blocking the stream drain until
it exits (observed: a 600s spawn timeout stretching to 1431s and tripping bun's
per-test timeout with no result). On timeout, cancel the stdout reader; race
the stderr drain against child exit + 5s grace. Streamed transcript lines
survive the cancel, so callers still get their evidence.
Regression test: test/session-runner-timeout.test.ts (fake claude spawns a
pipe-holding orphan; fails in 30s without the fix, passes in 8s with it).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
📝 Summary:
• Investigated 46KB `{{PREAMBLE}}` injected into every generated
`SKILL.md` by `scripts/gen-skill-docs.ts` resolvers
• Upstream churns resolvers + generated files every release (51
files / 1,469 insertions in one delta) — fork-side trim would
conflict on every rebase, so no edit made
• Documented safe path: upstream PR extending the existing
`sections/` carve to relocate ~20.5KB of tier-2+ interaction
prose on-demand (~5.1k tokens saved per invocation)
➕ Files Added:
• `PREAMBLE-BLOAT-NOTES.md` (per-tier preamble sizes, section
breakdown, top-10 offender table, trim strategy A/B/C)
The Step 4 bucketing (title/file Jaccard, state weighting, EXACT_DUP /
OVERLAP / SIBLING / CLEAN precedence) lived only as inline bash in the
skill, so it had no behavioral coverage. Extract it into a pure,
deterministic CLI, `bin/gstack-pr-prep-score`, and pin every bucket
threshold in `test/pr-prep-score.test.ts` (13 cases, free, gate-tier).
The skill's Step 4 now points at the scorer as the canonical
implementation rather than re-deriving the thresholds inline, and the
coverage matrix gates pr-prep on the new behavioral test. This is the
v0.2.0 extraction the skill flagged, scoped to the scoring core.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The coverage gate (skill-coverage-matrix + skill-coverage-floor)
requires every skill on disk to have a registry entry with at least one
gate-tier test. The new pr-prep skill had none, failing both checks.
Register it with the structural floor test as its gate-tier minimum,
matching how other audit/report skills (qa-only, investigate) are
covered until a behavioral E2E is written.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The golden-file regression check pins the generated per-host ship skill
(Claude, Codex, Factory) against committed snapshots. Adding the Step
1.5 pr-prep gate to `ship/SKILL.md.tmpl` changed all three generated
outputs, so the snapshots no longer matched. Regenerate them via
`gen:skill-docs --host all` and re-capture; the diff is exactly the
Step 1.5 block, identical across hosts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add Step 4.6: a per-commit conformance check that holds the branch's
commit messages to the UPSTREAM repo's convention, not the
contributor's own house style. A fork PR whose commits read in a
different voice than the project reads as a drive-by and burns reviewer
goodwill before the diff is read.
The authoritative style is resolved once (Step 1.4): 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. Step 4.6 then flags subject-shape drift,
a personal body template (emoji/bullets) where upstream uses prose, a
subject that promises content it lacks (e.g. "+ tests" with no tests),
and a missing-or-extra trailer relative to upstream (e.g. a
`Co-Authored-By:` line upstream carries on every commit). Surfaced as a
soft warning in the report, never a block — style is not a duplicate,
but it is the cheapest goodwill win in the audit and far cheaper to fix
before the PR exists.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adding the skill left its entry in `scripts/proactive-suggestions.json`
unwritten. Regenerate the registry so `/pr-prep` is wired into
proactive routing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The committed `pr-prep/SKILL.md` was generated against an older
preamble and had drifted from `bun run gen:skill-docs` output.
Regenerate it so it picks up the current shared resolvers: the
`SESSION_KIND` and `GSTACK_PLAN_MODE` preamble lines, the `/spec`
routing entry, the AskUserQuestion failure fallback, the 5+-option
split rule, and the Boil-the-Ocean rename.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The doc-inventory cross-check requires every skill directory to appear
in both `AGENTS.md` and `docs/skills.md`. Add a `/pr-prep` row to each
so the new skill is documented and the check passes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>