mirror of https://github.com/garrytan/gstack.git
docs(docs): add preamble-bloat findings — trim deferred to upstream
📝 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)
This commit is contained in:
parent
29e4c17bfa
commit
823aaecfb5
|
|
@ -0,0 +1,173 @@
|
|||
# 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.
|
||||
Loading…
Reference in New Issue