prehello 0.1.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,81 +4,87 @@
4
4
 
5
5
  <p align="center">
6
6
  <a href="https://github.com/PIYUSH-KUMAR1809/prehello/actions/workflows/ci.yml"><img src="https://github.com/PIYUSH-KUMAR1809/prehello/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
7
+ <a href="https://www.npmjs.com/package/prehello"><img src="https://img.shields.io/npm/v/prehello" alt="npm version"></a>
7
8
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green" alt="License: MIT"></a>
8
- <img src="https://img.shields.io/badge/node-%E2%89%A518-brightgreen" alt="Node 18 or newer">
9
+ <img src="https://img.shields.io/badge/node-%E2%89%A522-brightgreen" alt="Node 22 or newer">
9
10
  <img src="https://img.shields.io/badge/platform-linux%20%7C%20macos%20%7C%20windows-lightgrey" alt="Linux, macOS and Windows">
10
11
  </p>
11
12
 
12
- <p align="center">
13
- <img src="docs/sample-card-cursor.png" width="760" alt="A prehello share card: 'Skills and plugins cost ~3.9k tokens before hello', with a treemap of which plugins and files they come from">
14
- <br>
15
- <sub>A share card (<code>--card=card.png</code>). Sample data shaped like a real Cursor setup, not a real machine.</sub>
16
- </p>
17
-
18
- Every Claude Code, Cursor or Codex session starts with a pile of rules, skills, plugin listings and MCP servers already sitting
19
- in the context window, before you type a word. **prehello** scans your repo and your home-directory agent config and tells you
20
- **how many tokens that is, which plugin or skill folder is responsible, and roughly what removing the top few would save.**
13
+ Every **Claude Code, Cursor, Codex, GitHub Copilot and Gemini CLI** session starts with rules, skills, plugin listings and MCP servers already
14
+ in the context window, before you type a word. **prehello** scans your repo and your user-level agent config and tells you
15
+ **how many tokens that is, which plugin or file is responsible, and roughly what removing the top few would save.**
21
16
 
22
17
  - **Local and read-only.** No network, no telemetry, no API key, no child processes. Nothing leaves your machine.
23
- - **Honest numbers.** Every count is an estimate (`~`). What it cannot measure is listed, never shown as 0.
24
- - **Actionable.** A ranked "what to cut" list, a share card, a Markdown report, SARIF for code scanning, and a `--max-tokens` CI gate.
25
-
26
- ## Try it
18
+ - **Honest numbers.** Every count is an estimate (`~`) with a published error band. What it cannot measure is listed, never shown as 0.
19
+ - **Actionable.** A ranked "what to cut" list, a share card, a PR comment on every pull request, a badge, SARIF and a `--max-tokens` CI gate.
27
20
 
28
21
  ```sh
29
- git clone https://github.com/PIYUSH-KUMAR1809/prehello.git
30
- cd prehello
31
- npm ci && npm run build
32
- node dist/cli.js ~/code/your-project # scan a project plus your user-level agent config
33
- node dist/cli.js # or: scan the current folder
34
- node dist/cli.js ~/code/your-project --card=card.png # also write a PNG share card
22
+ npx prehello # this folder plus your user-level agent config
23
+ npx prehello ~/code/your-project # a specific project
24
+ npx prehello --card=card.png # also write a PNG share card
35
25
  ```
36
26
 
37
- Needs Node 18 or newer, on Linux, macOS or Windows. **npm release:** not published yet; once it is, this becomes `npx prehello`.
27
+ Needs Node 22 or newer, on Linux, macOS or Windows. `npm install -g prehello` installs it as `prehello`.
38
28
 
39
29
  ## What it prints
40
30
 
41
- A real run on bundled **fixture** data (`test/fixtures/plugin-heavy`: three invented plugins plus a few skills), not anyone's real numbers:
31
+ <p align="center"><img src="https://raw.githubusercontent.com/PIYUSH-KUMAR1809/prehello/main/docs/images/scan.png" width="760" alt="prehello terminal output: per-agent totals for Claude Code, Cursor, Codex, GitHub Copilot and Gemini CLI, the what-to-cut list, measured vs not measured, and top offenders"></p>
42
32
 
43
- ```text
44
- prehello 0.1.0 · this folder + user config · window 200k
45
- Token counts are ESTIMATES (o200k BPE with per-agent scaling priors), shown with
46
- ~. Not exact for any model.
33
+ <sub>A real run of prehello 1.0 on a demo setup built from the bundled test fixtures (`test/fixtures/`), not anyone's real machine.</sub>
47
34
 
48
- Before your first message: Cursor ~5k tokens
35
+ Below this first screen come a per-agent breakdown (always-on / conditional / deferred / on-demand), findings, and a Context Grade
36
+ (a heuristic of this tool, not a standard). The full output is in [docs/REFERENCE.md](docs/REFERENCE.md).
49
37
 
50
- What to cut (estimates)
51
- Cursor skills, plugins and MCP servers add ~4.5k tokens before hello: 90% of
52
- the measured always-on total, in 4 groups.
53
- Top 3 groups = 94% of that. Removing them would save about 4.2k tokens
54
- (2.1% of a 200k window); estimate, not a promise.
55
- 1. plugin analytics-kit (40 skills) ~2.2k 44%
56
- 2. plugin design-kit (24 skills) ~1.3k 26%
57
- 3. plugin cloud-kit (14 skills) ~719 14%
38
+ > **Read the numbers as "what YOUR config adds".** The agent's built-in system prompt and tool definitions are not on disk, so no static
39
+ > scanner can see them. prehello's total is the part *you* control. For the exact live total in one Claude Code session, use `/context`.
58
40
 
59
- Measured vs. not measured (always-on items)
60
- Cursor measured 4 of 4 (100%): 2 skills listings, 1 instruction file, 1 rule
61
- ...
62
- ```
41
+ **The share card** (`--card=card.png`) holds no paths or file contents:
63
42
 
64
- That is the first screen. Below it come a per-agent breakdown (always-on / conditional / deferred / on-demand), what could not be measured, and a
65
- Context Grade (a heuristic of this tool, not a standard). The full output is under [Reference](#reference) (collapsed).
43
+ <p align="center"><img src="https://raw.githubusercontent.com/PIYUSH-KUMAR1809/prehello/main/docs/images/card.png" width="640" alt="prehello share card: Skills and plugins cost at least ~4.9k tokens before hello, with a treemap of plugins"></p>
66
44
 
67
- > **Read the numbers as "what YOUR config adds".** The agent's own built-in system prompt and built-in tool definitions are **not** counted:
68
- > they are usually the largest fixed chunk of the context window and are not on disk, so no static scanner can see them. prehello's total is the part
69
- > *you* control. For the exact live total in one Claude Code session, use `/context`.
45
+ ## What 559 public repos load before hello
70
46
 
71
- ### On one real machine
47
+ The [State of agent context 2026](docs/BENCHMARK.md) benchmark checked 2,041 public GitHub repos; 559 ship agent files. prehello ran on each with an
48
+ empty HOME, so only the repo's own files count.
72
49
 
73
- The author's own Cursor setup, one run of prehello 0.1.0 on 2026-10-25. **One machine, estimates, not reproducible from this repo.**
50
+ - The median repo adds **~2.2k tokens** before hello. p90 is ~8.4k, the largest ~53k.
51
+ - **20.4%** have both CLAUDE.md and AGENTS.md at the root, so Claude Code ignores the AGENTS.md.
52
+ - **16.6%** have an instruction file longer than the agent's documented guideline; **3.4%** have an AGENTS.md chain Codex truncates at 32 KiB.
53
+ - Stars don't predict size (Spearman 0.05), but they do predict adoption: **47%** of 10k+ star repos ship agent files, vs **17%** at 20–99 stars.
74
54
 
75
- | What | Estimate, before hello |
76
- | --- | --- |
77
- | Skills, plugins and MCP servers | **at least ~14.3k tokens** (a lower bound: items prehello cannot measure, such as Cursor User Rules, are not in it) |
78
- | Cut list, top 3 of 6 groups | `plugin posthog` ~10.3k (72%), `plugin figma` ~1.7k, 18 Cursor-managed skills ~1.3k: removing them would save about **~13.2k** |
55
+ <p align="center">
56
+ <img src="https://raw.githubusercontent.com/PIYUSH-KUMAR1809/prehello/main/benchmark/charts/always-on-by-agent.png" width="420" alt="Always-on tokens per agent across 559 repos">
57
+ <img src="https://raw.githubusercontent.com/PIYUSH-KUMAR1809/prehello/main/benchmark/charts/mistakes.png" width="420" alt="Common agent-file mistakes across 559 repos">
58
+ </p>
59
+
60
+ Data, scripts and how to reproduce it are in [`benchmark/`](benchmark/) and [docs/BENCHMARK.md](docs/BENCHMARK.md).
61
+
62
+ ## A PR comment on every pull request
63
+
64
+ ```yaml
65
+ # .github/workflows/prehello.yml
66
+ on: pull_request
67
+ permissions: { contents: read, pull-requests: write }
68
+ jobs:
69
+ context-diff:
70
+ runs-on: ubuntu-latest
71
+ steps:
72
+ - uses: actions/checkout@v4
73
+ with: { fetch-depth: 0, persist-credentials: false }
74
+ - uses: PIYUSH-KUMAR1809/prehello@v1
75
+ with: { fail-above: 2k } # optional
76
+ ```
79
77
 
80
- Almost all of it is skill listings, mostly from one plugin. Every enabled skill puts its name and description in the context on every session,
81
- whether you use it or not. That is what the cut list is for, and removing a plugin you actually use costs you the plugin.
78
+ <p align="center"><img src="https://raw.githubusercontent.com/PIYUSH-KUMAR1809/prehello/main/docs/images/pr-comment.png" width="640" alt="The prehello PR comment: a table of base, head and change per agent"></p>
79
+
80
+ One sticky comment per PR, updated on every push. Fork PRs fall back to the job summary. Details, inputs and the README badge
81
+ (`--badge badge.json`, a shields.io endpoint) are in [docs/github-action.md](docs/github-action.md).
82
+
83
+ ## How accurate is it?
84
+
85
+ Counts use the o200k tokenizer with per-agent factors from published measurements. Bands: Codex ±3%, Claude Code ±15%,
86
+ Cursor and Copilot −3% to +15% (model unknown), Gemini CLI −3% to +64% (unvalidated). Sources and caveats are in [docs/ACCURACY.md](docs/ACCURACY.md).
87
+ `prehello calibrate --file ctx.txt` compares the estimate with your own Claude Code `/context` reading, per category.
82
88
 
83
89
  ## Outputs
84
90
 
@@ -90,28 +96,33 @@ whether you use it or not. That is what the cut list is for, and removing a plug
90
96
  | GitHub code scanning / IDEs | `--sarif=prehello.sarif` |
91
97
  | Machine-readable | `--json` (add `--redact` before sharing it: no paths or names) |
92
98
  | A budget gate in CI | `--max-tokens 16k` (exit code 2 above it) |
99
+ | What a PR changes | `--save base.json` / `--save head.json`, then `prehello diff base.json head.json` (`--markdown`, `--fail-above 2k`) |
100
+ | A PR comment on every pull request | the GitHub Action: `uses: PIYUSH-KUMAR1809/prehello@v1` ([docs/github-action.md](docs/github-action.md)) |
101
+ | A README badge | `--badge badge.json` (shields.io endpoint JSON; see [docs/github-action.md](docs/github-action.md#badge)) |
102
+ | Check the estimate against Claude Code | `prehello calibrate --file ctx.txt` (paste `/context` output; see [docs/ACCURACY.md](docs/ACCURACY.md)) |
93
103
  | Suggestions, changing nothing | `--fix` (dry run) |
94
104
  | Count Cursor "User Rules" you paste in | `--paste-user-rules rules.txt` |
95
- | Also count agent files inside test-fixture folders | `--include-fixtures` (skipped by default; see [Test-fixture folders](#reference)) |
105
+ | Also count agent files inside test-fixture folders | `--include-fixtures` (skipped by default; see [docs/REFERENCE.md](docs/REFERENCE.md)) |
96
106
 
97
107
  `node dist/cli.js --help` lists every flag. PNG cards need the optional package `@resvg/resvg-wasm`; if it is missing, prehello prints how to install it
98
108
  and exits 1 without a stack trace, and the SVG card and everything else keep working.
99
109
 
100
110
  ## Agents covered
101
111
 
102
- Claude Code, Cursor, Codex, and plain `AGENTS.md` files. Details of what is scanned for each are in the [reference](#reference). Not yet: Gemini CLI, Windsurf, Copilot, Cline.
112
+ Claude Code, Cursor, Codex, GitHub Copilot (CLI and VS Code), Gemini CLI, and plain `AGENTS.md` files. What is scanned for each is in [docs/REFERENCE.md](docs/REFERENCE.md). Not yet: Windsurf, Cline.
103
113
 
104
114
  ## FAQ
105
115
 
106
116
  **Does it send anything anywhere?** No. No network, no telemetry, no API key, no child processes. A test runs the CLI with a guard that blocks and records any
107
117
  network, DNS or child-process attempt. It writes only the output files you name (`--card=`, `--json=`, `--markdown=`, `--sarif=`).
108
118
 
109
- **Is the token count exact?** No, and it says so. It counts with the o200k tokenizer and applies a per-agent factor. The factors for Claude and Cursor are
110
- **priors, not validated** against those vendors' tokenizers, so every total carries an error band and a `~`.
119
+ **Is the token count exact?** No, and it says so. It counts with the o200k tokenizer and applies a per-agent factor. The Claude factors come from
120
+ published `count_tokens` measurements (a small sample, see [docs/ACCURACY.md](docs/ACCURACY.md)), not from prehello's own runs, so every
121
+ total carries an error band and a `~`. `prehello calibrate` compares the estimate with your own Claude Code `/context` reading.
111
122
 
112
123
  **Why is my total smaller than what `/context` shows?** `/context` also sees the built-in system prompt, built-in tool definitions and the conversation. prehello only sees what is on disk.
113
124
 
114
- **Why not just use `/context`?** If you only use Claude Code and want the true number for one live session, do. prehello works before a session, covers Cursor and Codex too,
125
+ **Why not just use `/context`?** If you only use Claude Code and want the true number for one live session, do. prehello works before a session, covers Cursor, Codex, Copilot and Gemini CLI too,
115
126
  runs in CI, and ranks *which plugin or skill folder* to remove.
116
127
 
117
128
  **Does it start my MCP servers?** No. It lists their names and counts. Sizes come only from a small measured catalog (`spec/mcp-weights.json`, 7 servers) or a file you give it; every other server stays "unmeasured".
@@ -122,16 +133,16 @@ runs in CI, and ranks *which plugin or skill folder* to remove.
122
133
 
123
134
  **Why does it say "Skipped N fixture folders"?** A repo that tests agent tooling keeps sample `AGENTS.md`, `CLAUDE.md`, `.cursor/rules` and skills under `test/fixtures/` and similar. No agent loads those, so prehello skips such folders by default and says how many it skipped (only folders where it found agent files). `--include-fixtures` counts them; scanning a folder that is itself inside a fixtures folder never skips anything.
124
135
 
125
- **Does it work on Windows?** Yes. CI runs the full suite on Ubuntu, Windows and macOS with Node 18, 20 and 22. See [Platforms](#reference).
136
+ **Does it work on Windows?** Yes. CI runs the full suite on Ubuntu, Windows and macOS with Node 22, 24 and 26. See [docs/REFERENCE.md](docs/REFERENCE.md).
126
137
 
127
138
  ## Limitations
128
139
 
129
- - Token counts are **estimates**; Claude and Cursor scaling factors are unvalidated.
140
+ - Token counts are **estimates**; the Claude factors rest on about 10 published measurements, and Cursor's model is unknown (see [docs/ACCURACY.md](docs/ACCURACY.md)).
130
141
  - The built-in system prompt, built-in tools, Cursor User and Team Rules (unless pasted), claude.ai connectors, hook output and anything injected at runtime are **never measured**.
131
142
  - Loading rules come from the agents' public docs and announcements, not from their source, and were **not re-verified against live installs**; items where sources disagree are labelled `assumed`.
132
- - Only three agents plus `AGENTS.md` are covered, and MCP server sizes exist for just 7 servers.
143
+ - Five agents plus `AGENTS.md` are covered (Copilot and Gemini CLI token factors are unvalidated), and MCP server sizes exist for just 7 servers.
133
144
 
134
- Full list: [reference](#reference).
145
+ Full list: [docs/REFERENCE.md](docs/REFERENCE.md).
135
146
 
136
147
  ## How it differs
137
148
 
@@ -148,364 +159,9 @@ What prehello focuses on: a per-plugin / per-skill-folder **cut list**, **unmeas
148
159
  (`documented`, `observed`, `assumed`), a share card that holds no paths or file contents, and a CI gate. What it does **not** do: live sessions, dollar cost,
149
160
  linting your instructions against your code, or exact token counts.
150
161
 
151
- ## Reference
152
-
153
- Long-form details, collapsed. Everything here describes the current CLI. Commands below say `prehello`; from a source checkout run `node dist/cli.js` instead (after the npm release, `npx prehello`).
154
-
155
- <details>
156
- <summary><b>Full sample output (fixture, not a real machine)</b></summary>
157
-
158
- ```text
159
- prehello 0.1.0 · this folder + user config · window 200k
160
- Token counts are ESTIMATES (o200k BPE with per-agent scaling priors), shown with
161
- ~. Not exact for any model.
162
-
163
- Before your first message: Cursor ~5k tokens
164
-
165
- What to cut (estimates)
166
- Cursor skills, plugins and MCP servers add ~4.5k tokens before hello: 90% of
167
- the measured always-on total, in 4 groups.
168
- Top 3 groups = 94% of that. Removing them would save about 4.2k tokens
169
- (2.1% of a 200k window); estimate, not a promise.
170
- 1. plugin analytics-kit (40 skills) ~2.2k 44%
171
- 2. plugin design-kit (24 skills) ~1.3k 26%
172
- 3. plugin cloud-kit (14 skills) ~719 14%
173
-
174
- Measured vs. not measured (always-on items)
175
- Cursor measured 4 of 4 (100%): 2 skills listings, 1 instruction file, 1 rule
176
-
177
- Top offenders (always on, estimates)
178
- 1. AGENTS.md 326 6.6% ████████████
179
- 2. .cursor/rules/always.mdc 164 3.3% ██████
180
- 3. skill "analytics-task-12" 59 1.2% ██
181
- 4. skill "analytics-task-26" 59 1.2% ██
182
- 5. skill "analytics-task-3" 59 1.2% ██
183
-
184
- ── Cursor ───────────────────────────────────────────────────────────── Grade A
185
- estimate model: o200k; model unknown, so midpoint of GPT-like (×1.0) and
186
- Claude-like (×1.5) priors; band wide: GPT-like −3% to Claude-like +20%
187
- ALWAYS ON before hello ~5k tokens (3.9k–7.1k) ≈ 2.5% of 200k
188
- Skills listing (78 skills from 3 plugins) 4,226 85% ████████████
189
- AGENTS.md 326 6.6% ▌
190
- Skills listing (5 user skills) 248 5.0% ▌
191
- .cursor/rules (alwaysApply) 164 3.3%
192
- DEFERRED (stub now, body on demand) ~4.7k tokens (3.6k–6.7k)
193
- Skill bodies (78 skills from 3 plugins) 4,383 94% ████████████
194
- Skill bodies (5 user) 280 6.0% ▌
195
- not measurable from disk: User Rules and Team Rules (stored in Cursor, not on
196
- disk; paste them with --paste-user-rules to count them) · built-in system
197
- prompt and tools · plugin install state (3 plugins found under
198
- ~/.cursor/plugins)
199
-
200
- Never measured: the agent's built-in system prompt and built-in tool
201
- definitions; server-side / org rules, Cursor User & Team Rules, claude.ai
202
- connectors; MCP servers whose tools are only known at runtime (no server is
203
- started by default); files outside the scanned locations; anything the agent
204
- injects dynamically (hooks, memory/RAG plugins).
205
- Context Grade (Cursor): A — heuristic, not a standard. See: prehello explain
206
- grade
207
- ```
208
-
209
- </details>
210
-
211
- <details>
212
- <summary><b>How to read the output</b></summary>
213
-
214
- - `~` means *estimated*. Ranges in brackets are the error band of the estimation model, not a confidence interval of truth.
215
- - **Measured vs. not measured.** Every agent gets a line saying how many always-on items were measured and which were not
216
- (for example MCP servers whose tool schemas only exist at runtime). `unmeasured` is **never shown as 0**.
217
- - If any always-on item is unmeasured, or the scan stopped at its budget, the always-on total becomes a **lower bound** (`≥` in the terminal, "at least" on the card)
218
- and the grade is **capped at B and marked provisional**. If nothing could be measured there is **no grade at all** and the output says so, instead of a flattering "A".
219
- - **Top offenders** ranks the biggest always-on items across agents (shown when there are at least three).
220
- - An agent that is installed but has nothing on disk gets an explicit "installed, but nothing that loads before hello was found.
221
- This is NOT a score of 0" message plus where prehello looked. An empty machine gets a "what I looked for / what to try" screen.
222
- - Agents found only inside the repo (for example an `AGENTS.md` committed by a teammate, with no sign you use that agent)
223
- are collapsed and excluded from the headline, card and grade (use `--agent` to include them).
224
- - **Running it from a folder that is not a project** (no `.git`, no agent files, for example your home folder) and with a huge tree:
225
- prehello warns and does **not** print token totals for random nested files it happened to find first.
226
-
227
- </details>
228
-
229
- <details>
230
- <summary><b>Test-fixture folders (<code>--include-fixtures</code>)</b></summary>
231
-
232
- The project walk (nested `AGENTS.md` / `CLAUDE.md`, `.cursor/rules`, `.cursor/skills`, `.claude/skills`, `.agents/skills`) **skips test-fixture folders by default**, for every agent, so a
233
- repository like prehello's own does not list its sample files as "conditional" context.
234
-
235
- | Folder name (any depth below the scanned folder, any letter case) | Skipped |
236
- | --- | --- |
237
- | `fixtures`, `__fixtures__`, `fixture`, `testdata`, `test-data`, `__mocks__`, `__snapshots__` | always |
238
- | `snapshots`, `golden`, `goldens` | only below a `test`, `tests`, `__tests__`, `spec`, `e2e` or `cypress` folder |
239
-
240
- - **Never skipped:** the scanned project's own top-level files, files found by walking *up* from the scanned folder, user-level config, and anything when the scanned folder is itself inside such a folder (so `prehello test/fixtures/x/project` works as before).
241
- - **Said out loud:** when at least one skipped folder held agent files, the terminal report, Markdown (full and compact) and SARIF (`runs[0].properties.prehello.fixtureFoldersSkipped`) carry one line / one number, never a path. `--json` gets `scan.fixturesSkipped` (a count; the field is absent when it is 0, so the JSON is otherwise unchanged). It is not a warning and does not change the exit code. Folders that held no agent files are not counted; looking inside a skipped folder to count it is bounded and reads no file.
242
- - `--include-fixtures` turns the skip off.
243
-
244
- </details>
245
-
246
- <details>
247
- <summary><b>Share cards (SVG and PNG), sample cards and how PNG works</b></summary>
248
-
249
- `--card=file.svg` or `--card=file.png` (the extension picks the format; `--card` alone writes `prehello-card.svg`, or `.png` with
250
- `--card-format png`). **Write the file name with `=`: `--card=card.png`.** `--card card.png` (a space) is not accepted: the name would be read as the
251
- project folder, so prehello stops with a hint before scanning. A card holds the same groups as the "What to cut" list on its treemap
252
- (`plugin <name>`, `18 Cursor-managed skills`, `MCP server <name>`), plus generic labels for your instruction files and rules
253
- (`CLAUDE.md`, `rule file x14`), counts, the version and a date. Small tiles are merged into `other (N smaller)`. It never contains paths or file contents.
254
- **Plugin and MCP server names are on the card by default** (they are what makes it readable); add `--card-anonymize` before sharing
255
- if a name is private, and they become `plugin 1`, `MCP server 1`.
256
-
257
- | Flag | Meaning |
258
- | --- | --- |
259
- | `--card-headline cut` (default) | Leads with "Skills & plugins cost ~X tokens before hello" and "cut the top N: save ~Y (estimate)". The always-on total is the first chip. |
260
- | `--card-headline total` | Leads with "~X tokens load before hello". |
261
- | `--card-theme dark\|light`, `--card-size og\|square` | Colours; 1200x630 link-preview shape or 1080x1080 square (square puts the headline on two lines). |
262
- | `--card-scale 1\|2` | PNG only. 1 = 1200x630 / 1080x1080, 2 = double that (default, sharper on phones). |
263
- | `--card-anonymize` | Show plugin and MCP server names as `plugin 1` / `MCP server 1` (implied by `--redact`). |
264
- | `--card-agent <id>` | Which agent the card is about (default: the one with the largest measured load). |
265
-
266
- The cut headline needs measured always-on data **and** a saving of at least 500 estimated tokens; otherwise the card silently
267
- uses the total headline (and an all-unmeasured setup says "N MCP servers load before hello, token cost unmeasured"). Every
268
- headline is checked before it is drawn: it keeps the `~`, says "estimate", and says "at least" when the total is a lower bound.
269
-
270
- **How PNG works.** The card SVG is rasterised locally with [`@resvg/resvg-wasm`](https://github.com/yisibl/resvg-js) (MPL-2.0; one
271
- package, about 2.5 MB, WebAssembly, so no native binaries, no build step and the same result on macOS, Linux and Windows).
272
- It is an *optional* dependency: if it is not installed (for example `npm install --omit=optional`), `--card=x.png` **never crashes**: it prints how to
273
- install it (to stderr), writes no card and exits 1, while everything else you asked for (the report, `--json`, `--markdown`) is still produced, and SVG cards keep working.
274
- The message marks how *this* copy of prehello was installed and lists the other ways:
275
-
276
- ```text
277
- prehello: PNG cards need the optional package @resvg/resvg-wasm, which is not installed here, so no card was written (...).
278
- Install it, then run the same command again:
279
- global install of prehello: npm install -g @resvg/resvg-wasm
280
- project install: npm install @resvg/resvg-wasm (run it in the project that has prehello in node_modules)
281
- one-off with npx: npx --package prehello --package @resvg/resvg-wasm -- prehello --card=card.png
282
- Or skip PNG: an SVG card needs no extra install, e.g. --card=card.svg
283
- ```
284
-
285
- A globally installed prehello also finds a globally installed engine (`npm install -g @resvg/resvg-wasm`, checked with the npm global layout). The text is drawn with a font that ships inside prehello
286
- (three weights of [Inter](https://github.com/rsms/inter), subsetted to about 31 KB each, SIL OFL 1.1, licence in `assets/fonts/OFL.txt`).
287
- System fonts are never used, so the glyphs are the same on every machine, and a test checks that every character on a card exists in those fonts.
288
- The PNG carries a `Software: prehello <version>` text chunk, which is how prehello recognises its own file before replacing it.
289
-
290
- Sample cards (regenerate with `node scripts/make-sample-cards.mjs docs` after `npm run build`). **These are made from test-fixture
291
- and synthetic data, not from a real machine; the numbers are illustrations of the format.**
292
-
293
- ![card from the plugin-heavy test fixture](docs/sample-card-fixture.png)
294
-
295
- Square, light theme, same fixture:
296
-
297
- ![square light card from the plugin-heavy test fixture](docs/sample-card-fixture-square-light.png)
298
-
299
- A synthetic Cursor setup shaped like a real Mac scan (one big plugin, a small one, 18 Cursor-managed skills). The treemap tiles are the same groups as the headline and the "What to cut" list:
300
-
301
- ![card from a synthetic Cursor setup](docs/sample-card-cursor.png)
302
-
303
- A synthetic "heavy" Claude Code setup (35 own skills, 6 plugins, 14 rules, 8 unmeasured MCP servers), which shows the lower-bound wording:
304
-
305
- ![card from a synthetic heavy setup](docs/sample-card-heavy.png)
306
-
307
- An SVG version of the first card is in `docs/sample-card-fixture.svg`.
308
-
309
- </details>
310
-
311
- <details>
312
- <summary><b>Markdown report (<code>--markdown</code>)</b></summary>
313
-
314
- `--markdown` prints a report you can paste into a GitHub issue or PR, Slack, or a README; `--markdown=report.md` writes it to a file instead
315
- (the file name must end in `.md` or `.markdown`; the same safe-write rules as `--card` and `--json` apply: no symlinks, no replacing a file prehello did
316
- not write unless `--force`, never a file it scanned). On stdout it *replaces* the terminal report, so it composes with other output files
317
- (`--markdown --json=out.json`), but `--json` and `--fix` cannot share stdout with it. With a file name the normal terminal report still prints.
318
-
319
- It contains: a title, the headline (the same cut-first headline as the card: `~` on every estimate, "at least" for lower bounds, an unmeasured item is
320
- "not measured", never 0), per agent a table of what loads before hello, the Context Grade (provisional when something is unmeasured), "What to cut",
321
- a "Measured vs not measured" list, and a footer with the prehello version and "estimates". `--markdown-compact` is the short version for a PR comment
322
- (headline, one line per agent, the first things to cut; it implies `--markdown`). `--agent`, `--window`, `--card-headline` and `--max-tokens` (exit code 2)
323
- behave as everywhere else.
324
-
325
- **Privacy.** Same contract as the card: no file paths, no file contents, no findings or warnings text (those name files), no home directory. Plugin, MCP server and skill-folder
326
- *names* are shown (they make the report useful); `--card-anonymize` (alias `--anonymize`, implied by `--redact`) turns them into "plugin 1" / "MCP server 1".
327
- Every name is placed in an inline code span with control and bidi characters stripped, secrets scrubbed and pipes escaped, so a hostile name such as
328
- `](http://evil)`, `<img onerror=...>`, `@everyone` or a backtick run cannot become a link, HTML, a mention or a broken table. prehello's own text is plain ASCII, so it survives any
329
- console code page.
330
-
331
- Example (`--markdown-compact`, test fixture, not a real machine):
332
-
333
- ```md
334
- ## prehello report: what your coding agent loads before you say hello
335
-
336
- **Skills & plugins cost ~4.5k tokens before hello**
337
-
338
- Cursor: top 3 of 4 groups - cut them, save ~4.2k (estimate).
339
-
340
- - **Cursor**: ~5k tokens always on (2.5% of 200k), grade A
341
-
342
- Cut first (Cursor, estimates): `plugin analytics-kit` ~2.2k, `plugin design-kit` ~1.3k, `plugin cloud-kit` ~719
343
- ```
344
-
345
- </details>
346
-
347
- <details>
348
- <summary><b>SARIF (GitHub code scanning, IDEs)</b></summary>
349
-
350
- `--sarif` prints a [SARIF 2.1.0](https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html) log on stdout (it *replaces* the terminal report, like `--markdown`);
351
- `--sarif=report.sarif` (or `.sarif.json`) writes it to a file and the terminal report still prints. The same safe-write rules as the other outputs apply, and
352
- `--json`, `--fix` and `--markdown` cannot share stdout with it. `--max-tokens` keeps its exit code (2). The output is validated against the OASIS schema in the test suite.
353
-
354
- Rules (stable ids; every rule has help text; there are no documentation URLs, the text is in the SARIF itself):
355
-
356
- | Rule | Level | What it reports |
357
- | --- | --- | --- |
358
- | `PH001` | note, warning from 5% of the window | an always-loaded file of 2,000+ tokens (or 1%+ of the window): `CLAUDE.md`, `AGENTS.md`, a rule, `MEMORY.md` |
359
- | `PH002` | note, warning from 5% of the window | a plugin, skills folder or MCP server of 1,000+ tokens before the first message (the "what to cut" groups, up to 10 per agent) |
360
- | `PH003` | warning | always-on context above `--max-tokens` ("at least" when something is unmeasured); only exists with that flag |
361
- | `PH004` | note | always-loaded items that could not be measured: cost unknown, not zero, so totals are lower bounds |
362
- | `PH005` | warning | two context files that are 60%+ the same text |
363
- | `PH006` | note | a file longer than the agent's documented length guideline |
364
- | `PH007` | warning | content the agent silently cuts off (Codex 32 KiB, `MEMORY.md` caps, skill description cap) |
365
- | `PH008` | warning | a file the agent ignores (`AGENTS.md` next to a `CLAUDE.md` for Claude Code; `.md` in `.cursor/rules`) |
366
- | `PH009` | warning | a line that looks like a secret (line number only, **never the value**; a pattern match, so false positives happen) |
367
- | `PH010` | note | a skills listing above the agent's listing budget |
368
- | `PH011` | note | some sources were unreadable or skipped, or the scan hit its budget |
369
-
370
- Every number is labelled an estimate (`isEstimate: true`, message text says "estimate"); an unmeasured item never carries a number; `at least` marks a lower bound.
371
- The `properties` bags carry the estimate with its low/high band, the agent and the share of the window. Results for one file are merged across agents.
372
-
373
- **Locations and privacy.** A `physicalLocation` is written **only for files inside the scanned folder**, as a relative path against `%SRCROOT%` with `startLine` (the line of the
374
- first possible secret for `PH009`, else 1). So run it from the repository root. User-level items (`~/.claude`, `~/.cursor`, `~/.codex`, managed, plugin, built-in), files that are
375
- symlinks out of the project, odd or secret-shaped file names, and everything when you scan your home folder get a `logicalLocation` with a generic label ("User CLAUDE.md",
376
- "plugin 1") and **no path**. `--redact` drops every file location; `--card-anonymize` / `--anonymize` turns plugin and MCP server names into `plugin 1` / `MCP server 1`.
377
- No file contents, no finding or warning texts (they name user-level paths), no absolute paths and no home directory ever reach the file. GitHub code scanning shows only results that have a file
378
- location; results without one (user-level items, `PH003`, `PH004`, `PH011`) are kept for IDE viewers and other tools.
379
-
380
- GitHub Actions, as a non-blocking annotation (add `--max-tokens` if you also want a gate). The snippet uses `npx prehello`, which works once the package is on npm; until then build from source in the job:
381
-
382
- ```yaml
383
- name: prehello
384
- on: [pull_request, push]
385
- permissions:
386
- contents: read
387
- security-events: write # needed to upload SARIF
388
- jobs:
389
- context-budget:
390
- runs-on: ubuntu-latest
391
- steps:
392
- - uses: actions/checkout@v4
393
- - uses: actions/setup-node@v4
394
- with: { node-version: 20 }
395
- # a CI runner has no agent config in $HOME, so name the agents whose files in the repo you want scanned
396
- - run: npx prehello --agent claude-code,cursor,codex --sarif=prehello.sarif || test $? -eq 3
397
- - uses: github/codeql-action/upload-sarif@v4
398
- if: always()
399
- with:
400
- sarif_file: prehello.sarif
401
- category: prehello
402
- ```
403
-
404
- Notes: `|| test $? -eq 3` lets "partial results" through (exit 3) but still fails on a real error (1). Add `--max-tokens 16k` and drop the `|| ...` part if over-budget should fail the job (exit 2);
405
- the SARIF file is still written first. Uploading needs GitHub code scanning (public repos, or GitHub Advanced Security on private ones). This workflow has **not** been run against GitHub code scanning yet.
406
-
407
- </details>
408
-
409
- <details>
410
- <summary><b>CI: <code>--max-tokens</code></b></summary>
411
-
412
- ```sh
413
- prehello --max-tokens 16k --quiet || echo "always-on context is over budget"
414
- ```
415
-
416
- Exit code **2** if the always-on estimate of any agent in use is above the limit (a lower bound that already exceeds it counts; the central estimate is what is compared, not the high end of the band).
417
- The number goes to stderr, so `--json` on stdout stays valid. Exit code 2 wins over exit code 3 (partial results). Not a substitute for a lint: it gates size, not quality.
418
-
419
- </details>
420
-
421
- <details>
422
- <summary><b>Agents covered: what is scanned</b></summary>
423
-
424
- | Agent | What is scanned |
425
- | --- | --- |
426
- | Claude Code | `CLAUDE.md` chain (user → ancestors → project, `@imports`), `AGENTS.md` only when no `CLAUDE.md` is in the tree, `.claude/rules` (path-scoped → conditional), auto-memory `MEMORY.md` (200-line cap), skills (user, project, enabled plugins; listing up front, bodies deferred), plugin commands, subagent listings, MCP servers (`~/.claude.json`, `.mcp.json`, plugins) |
427
- | Cursor | `AGENTS.md`, `.cursor/rules/*.mdc` by mode (always / glob / agent-requested / manual; plain `.md` is flagged as ignored), nested rules and skills as conditional, skills in `.cursor/skills` and the compatible `.claude`/`.codex`/`.agents` skill folders, installed plugins' skills / rules / MCP, MCP servers, pasted User Rules |
428
- | Codex | `~/.codex/AGENTS.md` + `AGENTS.override.md` chain from the repo root to the working directory, 32 KiB cap, shadowed files reported, skills (`.agents/skills` up to the repo root, `~/.agents/skills`, `/etc/codex/skills`, `[[skills.config]]` disabling), MCP servers in `config.toml` |
429
-
430
- </details>
431
-
432
- <details>
433
- <summary><b>Honest caveats</b></summary>
434
-
435
- - **Token counts are estimates.** Counting uses the o200k BPE tokenizer (`gpt-tokenizer`) with a per-agent scaling prior.
436
- - Codex / OpenAI-family: ×1.0, ±3%.
437
- - Claude Code: ×1.5 (`--claude-profile legacy` uses ×1.2), ±20%. **The Claude factor and band are priors, not validated against Anthropic's tokenizer.**
438
- - Cursor: the model is not discoverable from disk, so the estimate is the midpoint between the GPT-like and Claude-like priors, with a wide band. Also **unvalidated**.
439
- - `--tokenizer heuristic` falls back to chars/3.5 (3.0 for JSON), ±35%.
440
- - **Never measured:** the agent's built-in system prompt and built-in tool definitions, server-side/org rules, Cursor User & Team Rules
441
- (unless you paste them), claude.ai connectors, hook output, anything injected dynamically (memory/RAG plugins).
442
- - **MCP servers.** Names and counts are always listed. Sizes come only from the bundled catalog (`spec/mcp-weights.json`, 7 servers) or your own `--mcp-catalog`.
443
- The bundled numbers were **actually measured** with `scripts/measure-mcp.cjs`: each package was installed from npm, started offline in a sandbox with a scrubbed
444
- environment, and asked for `tools/list`. They are raw o200k counts of the tool-list JSON for the stated version, **not** the exact text any agent injects,
445
- and tool lists change between versions. Every other server stays "unmeasured". The CLI itself never starts a server. `--no-bundled-catalog` turns the catalog off.
446
- - **Loading rules come from public docs and the agents' own announcements, not from their source code,** and were researched on the date in `spec/*.json`
447
- (`prehello --about-specs`). They were **not** re-verified against live installs. Where sources disagree the item is labelled `assumed` (see below).
448
- Treat `ignored`/`truncated` findings as strong hints, not proof.
449
- - **Confidence labels** on every item: `documented` (a public doc says so), `observed` (seen on a real machine), `assumed` (a best guess; stated as such in the notes).
450
- Examples of `assumed`: how Cursor and Codex format their skills listing and what it costs, Cursor's `~/.cursor/skills-cursor`, Cursor plugin install state,
451
- nested `.cursor/rules`, and whether Codex loads MCP schemas upfront.
452
- - **The Context Grade is a heuristic of this tool**, not a standard. `prehello explain grade` prints the exact rubric.
453
- - **Windows and macOS:** the full test suite runs in CI on Ubuntu, Windows and macOS with Node 18, 20 and 22, and was green on 2026-10-25 (GitHub-hosted runners only; not tried on a range
454
- of real Windows consoles, locales or corporate setups). Windows specifics (USERPROFILE home, drive letters, UNC, backslash globs, CRLF/BOM/UTF-16 files, reserved device names, case-insensitive file systems)
455
- are covered by tests, partly by simulation. Only the three listed agents plus plain `AGENTS.md` are covered.
456
-
457
- </details>
458
-
459
- <details>
460
- <summary><b>Privacy and safety</b></summary>
461
-
462
- - **Local only, read-only.** No network, no telemetry, no API key, no child processes. The scanner reads files; the only files it ever
463
- writes are those you explicitly request (`--json=<file>`, `--card=<file.svg|png>`, `--markdown=<file.md>`, `--sarif=<file.sarif>`), and it refuses to overwrite a file it scanned.
464
- - **Output files are written defensively.** prehello never writes *through a symlink* (not even with `--force`). It replaces an existing
465
- file only if that file is a previous prehello output (an SVG or PNG it generated, a Markdown file starting with its `<!-- generated by prehello` marker, JSON whose `tool.name` is `prehello`, or a SARIF file whose driver is `prehello`); anything else needs `--force`.
466
- Directories, other non-regular files and files with extra hard links are refused (hard links need `--force`). The file is opened with `O_NOFOLLOW` and
467
- checked again after opening, so a link swapped in at the last moment is not followed. A symlinked *parent directory* is not detected: point `--json=`/`--card=` at a path you mean to write.
468
- - It **never prints file contents** (that includes text passed with `--paste-user-rules`, which is counted and discarded).
469
- Output contains token counts, file *names/paths*, skill, plugin and MCP server *names*, and line-number locations for findings.
470
- A line that looks like a secret is reported by location only, never echoed. Terminal control characters in file names are neutralised.
471
- - Terminal and `--json` shorten paths (`~`, `./`) but keep names. **Use `--redact` before sharing a JSON file.** The SVG and PNG cards and the Markdown report contain no paths or file contents
472
- (no paths, no file contents, no home directory). They do show plugin and MCP server names as treemap tile labels; use `--card-anonymize` to hide those.
473
- - **Resource limits.**
474
- - A single file over **4 MiB** is skipped and shown as *unmeasured* (exit code 3). That matches Claude Code's documented behaviour of skipping a startup `CLAUDE.md` over 4 MiB entirely;
475
- for other agents it is a safety cap, not their rule. Binary files and symlinks that leave the project are skipped the same way.
476
- - **Scan budget:** at most **64 MiB** read in total (deterministic; `--scan-budget-mb`) and **20 s** wall clock (`--scan-budget-ms`, a safety net, the one limit that can vary on a slow disk).
477
- When a budget is hit the scan stops, prints one "results are PARTIAL" warning, every total becomes a lower bound, the grade is provisional, and `--json` has a non-null `partial`.
478
- - The directory walk stops at 5,000 entries (depth 8) and says so. Test-fixture folders are not walked by default (`--include-fixtures`), so they do not use up that budget.
479
- - These claims are tested, not just stated: a runtime guard blocks and records any filesystem write, network, DNS, `fetch` or child-process attempt
480
- while the CLI runs on fixtures; a source scan bans those modules from `src/` and allows write APIs in exactly one file (`src/safe-write.ts`); a network-namespace run is used when the OS allows it; and planted "canary" strings
481
- prove file contents never reach any output. See `test/safety.test.ts` and `test/sarif.test.ts`. (`scripts/measure-mcp.cjs` is a dev-only helper that is not part of the CLI and not in the package.)
482
-
483
- </details>
484
-
485
- <details>
486
- <summary><b>Platforms</b></summary>
487
-
488
- prehello runs on Linux, macOS and Windows (Node ≥ 18) and prints the same numbers on all three.
489
-
490
- - **Home folder.** macOS/Linux: `$HOME`. Windows: `%USERPROFILE%` (Claude Code, Cursor and Codex all take it from the OS; Git Bash's `HOME=/c/Users/me` is not used).
491
- `CLAUDE_CONFIG_DIR` is honoured everywhere.
492
- - **Machine-wide files.** macOS `/Library/Application Support/ClaudeCode`, Linux `/etc/claude-code`, Windows `%ProgramFiles%\ClaudeCode` (falls back to `C:\Program Files\ClaudeCode`).
493
- Cursor is detected by `~/.cursor`, `cursor` on `PATH`, `Cursor.app` (macOS) or `%LOCALAPPDATA%\Programs\cursor\Cursor.exe` (Windows).
494
- - **Paths in output** always use forward slashes (`./`, `~/`), on Windows too, so JSON and Markdown never contain backslashes or `C:\Users\...`.
495
- - **Files written by Windows tools** are read correctly: CRLF and a UTF-8 BOM are handled in context files, `--mcp-catalog` and `--paste-user-rules`. A UTF-16 file
496
- (Windows PowerShell 5's `>` redirection) is reported as "saved as UTF-16, re-save as UTF-8", not as binary.
497
- - **Redirecting output on Windows.** Windows PowerShell 5 re-encodes `prehello --json > out.json` as UTF-16. Use `--json=out.json` or `--markdown=report.md`; prehello writes UTF-8 itself.
498
- Output files named like a Windows device (`NUL`, `CON`, `COM1`, ...) or containing a `:` stream marker are refused.
499
- - **Console.** The legacy Windows console (cmd.exe, classic PowerShell window) and the Linux virtual console cannot draw box/block glyphs, so prehello switches to plain ASCII there
500
- automatically; `--ascii` (or `PREHELLO_ASCII=1`) forces it. `NO_COLOR`, `--no-color` and `TERM=dumb` turn colour off. The Markdown report is ASCII already.
501
- - **Install.** From source it is `node dist/cli.js` on every system. Once the package is on npm, `npm install -g prehello` creates a `prehello.cmd` shim on Windows and `npx prehello` works the same everywhere. File modes are not relied on.
502
-
503
- </details>
504
-
505
-
506
162
  ## Roadmap
507
163
 
508
- Not in 0.1: `--probe` (starting MCP servers to measure real schemas), `--save` / history / `diff` subcommands, `--apply` / `--patch`, Gemini and Windsurf adapters,
164
+ Not yet: `--probe` (starting MCP servers to measure real schemas), history beyond two snapshots, `--apply` / `--patch`, Windsurf and Cline adapters,
509
165
  Cursor Team Rules, a catalog beyond the 7 measured servers.
510
166
 
511
167
  ## Contributing, security, licence
@@ -28,6 +28,6 @@ TypeScript (Apache-2.0), vitest (MIT), ajv and ajv-formats (MIT), `@types/*` (MI
28
28
 
29
29
  ## Documentation
30
30
 
31
- The loading rules in `spec/*.json` are facts summarised from the public documentation of Claude Code, Cursor and Codex, each with the URL it came from. No documentation text is copied.
31
+ The loading rules in `spec/*.json` are facts summarised from the public documentation of Claude Code, Cursor, Codex, GitHub Copilot and Gemini CLI, each with the URL it came from. No documentation text is copied.
32
32
 
33
33
  The Code of Conduct is the [Contributor Covenant](https://www.contributor-covenant.org) 2.1 (CC BY 4.0).
@@ -40,8 +40,8 @@ function loadInstruction(ctx, filePath, o) {
40
40
  text = (0, comments_1.stripHtmlComments)(text);
41
41
  let detail;
42
42
  if (o.imports) {
43
- const roots = [(0, fs_safe_1.realpathOrSelf)(ctx.home), (0, fs_safe_1.realpathOrSelf)(ctx.gitRoot ?? ctx.cwd), (0, fs_safe_1.realpathOrSelf)(node_path_1.default.dirname(filePath))];
44
- const res = (0, imports_1.expandImports)(text, filePath, ctx.home, (real) => roots.some((root) => (0, fs_safe_1.isInside)(real, root)), { stripComments: o.stripComments, read: (t) => ctx.read(t, { quiet: true }) });
43
+ const roots = (o.importRoots ?? [ctx.home, ctx.gitRoot ?? ctx.cwd, node_path_1.default.dirname(filePath)]).map(fs_safe_1.realpathOrSelf);
44
+ const res = (0, imports_1.expandImports)(text, filePath, ctx.home, (real) => roots.some((root) => (0, fs_safe_1.isInside)(real, root)), { stripComments: o.stripComments, read: (t) => ctx.read(t, { quiet: true }), maxDepth: o.importMaxDepth, relativeOnly: o.importRelativeOnly });
45
45
  text = res.text;
46
46
  if (res.imported)
47
47
  detail = `(+${res.imported} @import${res.imported > 1 ? "s" : ""})`;
@@ -50,7 +50,7 @@ function loadInstruction(ctx, filePath, o) {
50
50
  }
51
51
  if (!text.trim())
52
52
  return null;
53
- const key = `${r.realPath}|${o.stripComments ? 1 : 0}${o.imports ? 1 : 0}|${o.transform ? text.length : ""}`;
53
+ const key = `${r.realPath}|${o.stripComments ? 1 : 0}${o.imports ? 1 : 0}|${o.importRoots ? o.importRoots.join(",") : ""}${o.importMaxDepth ?? ""}${o.importRelativeOnly ? "r" : ""}|${o.transform ? text.length : ""}`;
54
54
  const raw = ctx.count(key, text);
55
55
  if (!o.noAnalyze)
56
56
  ctx.analyzeDoc(o.agent, filePath, r.text, afterTransform, raw, o.guidelineLines);