chisle 2.0.0 → 3.1.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/.claude-plugin/plugin.json +1 -1
- package/.clinerules/chisle.md +1 -1
- package/.cursor/rules/chisle.mdc +1 -1
- package/.github/copilot-instructions.md +1 -1
- package/.kiro/steering/chisle.md +1 -1
- package/.windsurf/rules/chisle.md +1 -1
- package/AGENTS.md +2 -2
- package/README.md +180 -42
- package/bin/install.js +92 -40
- package/commands/chisle.toml +2 -3
- package/hooks/chisle-activate.js +57 -28
- package/hooks/chisle-compress-output.js +69 -25
- package/hooks/chisle-config.js +29 -4
- package/hooks/chisle-mode-tracker.js +8 -50
- package/hooks/chisle-mode.js +19 -0
- package/hooks/chisle-statusline.ps1 +4 -9
- package/hooks/chisle-statusline.sh +3 -8
- package/package.json +16 -7
- package/pi-extension/index.js +188 -0
- package/rules/chisle-activate.md +1 -1
- package/skills/chisle/SKILL.md +10 -18
- package/skills/chisle-help/SKILL.md +3 -12
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chisle",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "Maximum-efficiency dev mode. Zero-fluff prose combined with YAGNI/ladder-first code decisions. One persona: the senior dev who deletes code for fun and bills by the syllable.",
|
|
5
5
|
"hooks": {
|
|
6
6
|
"SessionStart": [
|
package/.clinerules/chisle.md
CHANGED
|
@@ -33,4 +33,4 @@ you're about to edit — diet trims transport, not understanding.
|
|
|
33
33
|
**Never minimal about:** input validation at trust boundaries, error handling
|
|
34
34
|
that prevents data loss, security, accessibility, anything explicitly requested.
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
Always on once installed. Deactivate: "stop chisle" / "normal mode".
|
package/.cursor/rules/chisle.mdc
CHANGED
|
@@ -38,4 +38,4 @@ you're about to edit — diet trims transport, not understanding.
|
|
|
38
38
|
**Never minimal about:** input validation at trust boundaries, error handling
|
|
39
39
|
that prevents data loss, security, accessibility, anything explicitly requested.
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
Always on once installed. Deactivate: "stop chisle" / "normal mode".
|
|
@@ -33,4 +33,4 @@ you're about to edit — diet trims transport, not understanding.
|
|
|
33
33
|
**Never minimal about:** input validation at trust boundaries, error handling
|
|
34
34
|
that prevents data loss, security, accessibility, anything explicitly requested.
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
Always on once installed. Deactivate: "stop chisle" / "normal mode".
|
package/.kiro/steering/chisle.md
CHANGED
|
@@ -37,4 +37,4 @@ you're about to edit — diet trims transport, not understanding.
|
|
|
37
37
|
**Never minimal about:** input validation at trust boundaries, error handling
|
|
38
38
|
that prevents data loss, security, accessibility, anything explicitly requested.
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
Always on once installed. Deactivate: "stop chisle" / "normal mode".
|
|
@@ -37,4 +37,4 @@ you're about to edit — diet trims transport, not understanding.
|
|
|
37
37
|
**Never minimal about:** input validation at trust boundaries, error handling
|
|
38
38
|
that prevents data loss, security, accessibility, anything explicitly requested.
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
Always on once installed. Deactivate: "stop chisle" / "normal mode".
|
package/AGENTS.md
CHANGED
|
@@ -41,6 +41,6 @@ edit — diet trims transport, not understanding.
|
|
|
41
41
|
Input validation at trust boundaries, error handling that prevents data loss,
|
|
42
42
|
security, accessibility, anything explicitly requested.
|
|
43
43
|
|
|
44
|
-
##
|
|
44
|
+
## Switching off
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
Always on once installed. Deactivate: "stop chisle" / "normal mode".
|
package/README.md
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="assets/logo.
|
|
2
|
+
<img src="assets/logo.png" width="120" alt="Chisle">
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
|
-
<h1 align="center"
|
|
5
|
+
<h1 align="center">Chisle</h1>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
8
|
<em>Your AI talks less, builds less, reads less — and says more. Like a senior dev who bills by the syllable.</em>
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
|
+
<p align="center">
|
|
12
|
+
<em>The only tool in this class that publishes the runs where it lost.</em>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
11
15
|
<p align="center">
|
|
12
16
|
<a href="https://www.npmjs.com/package/chisle"><img src="https://img.shields.io/npm/v/chisle?style=flat-square&color=d78a3c" alt="npm version"></a>
|
|
13
|
-
<img src="https://img.shields.io/badge/works%20with-
|
|
17
|
+
<img src="https://img.shields.io/badge/works%20with-9%20agents-d78a3c?style=flat-square" alt="Works with 9 agents">
|
|
14
18
|
<a href="https://github.com/JayPokale/Chisle/actions/workflows/test.yml"><img src="https://img.shields.io/github/actions/workflow/status/JayPokale/Chisle/test.yml?style=flat-square&label=CI" alt="CI"></a>
|
|
15
19
|
<img src="https://img.shields.io/badge/deps-0-2da44e?style=flat-square" alt="Zero deps">
|
|
16
20
|
<img src="https://img.shields.io/badge/license-MIT-d78a3c?style=flat-square" alt="MIT">
|
|
@@ -18,7 +22,7 @@
|
|
|
18
22
|
</p>
|
|
19
23
|
|
|
20
24
|
<p align="center">
|
|
21
|
-
<strong>
|
|
25
|
+
<strong>44% of a bare model on coding work · 41% on the long ones · one command</strong>
|
|
22
26
|
</p>
|
|
23
27
|
|
|
24
28
|
<p align="center">
|
|
@@ -75,7 +79,42 @@ Most efficiency tools compress one thing. Chisle compresses **three**:
|
|
|
75
79
|
|---|---|---|
|
|
76
80
|
| **Output: prose** | filler, hedging, manufactured structure | zero-fluff ruleset, injected per session |
|
|
77
81
|
| **Output: code** | speculative abstractions, unrequested boilerplate | YAGNI efficiency ladder |
|
|
78
|
-
| **Input: context** | oversized tool output flooding the window | `PostToolUse`
|
|
82
|
+
| **Input: context** | oversized tool output flooding the window | Claude `PostToolUse` / Pi `tool_result` — scrub, elide, dedup — plus prevention rules |
|
|
83
|
+
|
|
84
|
+
Where each one attaches to a session:
|
|
85
|
+
|
|
86
|
+
```mermaid
|
|
87
|
+
flowchart LR
|
|
88
|
+
subgraph S["Session start"]
|
|
89
|
+
H1["Ruleset injection<br/>once per active session"]
|
|
90
|
+
end
|
|
91
|
+
subgraph T["Every turn"]
|
|
92
|
+
H2["Mode tracking<br/>Claude + Pi"]
|
|
93
|
+
end
|
|
94
|
+
subgraph L["Every tool call"]
|
|
95
|
+
H3["PostToolUse / tool_result<br/>scrub → elide → dedup"]
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
H1 --> M(["Model"])
|
|
99
|
+
H2 --> M
|
|
100
|
+
M -->|writes| O["Output:<br/>terser prose,<br/>YAGNI-first code"]
|
|
101
|
+
M -->|calls a tool| TOOL[["Bash / grep / web / extension tools"]]
|
|
102
|
+
TOOL -->|raw output| H3
|
|
103
|
+
H3 -->|"compressed, rebuilt into<br/>the tool's own shape"| M
|
|
104
|
+
|
|
105
|
+
RE["Read / Edit / Write"] -.->|"never touched —<br/>exact bytes feed later edits"| M
|
|
106
|
+
|
|
107
|
+
style M fill:#1f2937,stroke:#d78a3c,color:#e6edf3
|
|
108
|
+
style O fill:#14532d,stroke:#2da44e,color:#e6edf3
|
|
109
|
+
style H3 fill:#1f2937,stroke:#2da44e,color:#e6edf3
|
|
110
|
+
style RE fill:#3f1d1d,stroke:#cf3b3b,color:#e6edf3
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The loop on the right is the input axis: tool output is billed again on *every* later request in the session, so shrinking it once pays repeatedly. `Read`, `Edit`, and `Write` are deliberately outside it.
|
|
114
|
+
|
|
115
|
+
<p align="center">
|
|
116
|
+
<img src="assets/thumbnail.png" width="820" alt="Chisle — less tokens, same results. Four parts: output compressor (compress noisy tool outputs), context diet (read only what's actually relevant), terse persona (short, focused, YAGNI-first), YAGNI ladder (do less, reuse more, build only when needed).">
|
|
117
|
+
</p>
|
|
79
118
|
|
|
80
119
|
Every "be concise" tool has a worst day — the day it makes the model write *more* than no tool at all. Across 20 measured tasks over two suites, the specialists had that day **6** and **8** times, blowing up to **424%** of the baseline. Chisle had it **once**, capped at 173% — and that one failure was root-caused, fixed in the ruleset, and re-validated live at 93%, with the whole investigation [committed to the repo](benchmarks/results/2026-07-07-verify-rerun.md). Think of it as downside insurance for your token bill: not always the single cheapest answer, always the smallest worst case — from the only tool in this class that publishes its own failures. [Why not caveman or ponytail? →](docs/comparison.md)
|
|
81
120
|
|
|
@@ -83,7 +122,7 @@ Every "be concise" tool has a worst day — the day it makes the model write *mo
|
|
|
83
122
|
|
|
84
123
|
## Install
|
|
85
124
|
|
|
86
|
-
One command. Auto-detects your agents (Claude Code, Cursor, Windsurf, Cline, Kiro, Codex, Gemini, Copilot) and wires each one. `--uninstall` puts everything back.
|
|
125
|
+
One command. Auto-detects your agents (Claude Code, Pi, Cursor, Windsurf, Cline, Kiro, Codex, Gemini, Copilot) and wires each one. `--uninstall` puts everything back.
|
|
87
126
|
|
|
88
127
|
```bash
|
|
89
128
|
npx chisle
|
|
@@ -99,9 +138,27 @@ curl -fsSL https://raw.githubusercontent.com/JayPokale/Chisle/main/install.sh |
|
|
|
99
138
|
irm https://raw.githubusercontent.com/JayPokale/Chisle/main/install.ps1 | iex
|
|
100
139
|
```
|
|
101
140
|
|
|
102
|
-
Preview first with `npx chisle --dry-run`, scope with `--only claude`, see everything with `npx chisle --help`. Remove with `npx chisle --uninstall`.
|
|
141
|
+
Preview first with `npx chisle --dry-run`, scope with `--only claude` or `--only pi`, see everything with `npx chisle --help`. Remove with `npx chisle --uninstall`.
|
|
142
|
+
|
|
143
|
+
**Requirements:** Node ≥18 (installer / `npx`) · Claude Code or Pi for `/chisle` toggling and input-side compression — the always-on ruleset still ships to every other agent.
|
|
144
|
+
|
|
145
|
+
### Upgrading
|
|
146
|
+
|
|
147
|
+
Same command as installing — it is idempotent and overwrites the previous copy:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
npx chisle # npm / standalone install
|
|
151
|
+
claude plugin update chisle@chisle # Claude Code plugin install
|
|
152
|
+
```
|
|
103
153
|
|
|
104
|
-
|
|
154
|
+
Chisle checks npm on session start and mentions it once when a **major** version
|
|
155
|
+
is out (cached 3 days, `CHISLE_UPDATE_CHECK=0` to silence). Minor and patch
|
|
156
|
+
releases stay quiet on purpose.
|
|
157
|
+
|
|
158
|
+
Upgrading to 3.0.0 from 2.x needs nothing: a `lite`/`full`/`ultra` value in
|
|
159
|
+
`CHISLE_DEFAULT_MODE` or `config.json` is no longer meaningful, falls through to
|
|
160
|
+
the default, and Chisle stays active. It says so once so the setting is not
|
|
161
|
+
ignored silently — replace it with `on`/`off` or delete it.
|
|
105
162
|
|
|
106
163
|
### Claude Code plugin (marketplace)
|
|
107
164
|
|
|
@@ -110,17 +167,26 @@ claude plugin marketplace add JayPokale/Chisle # register the marketplace
|
|
|
110
167
|
claude plugin install chisle@chisle # enable the plugin
|
|
111
168
|
```
|
|
112
169
|
|
|
170
|
+
### Pi package
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
pi install npm:chisle
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
The package loads the zero-dependency extension and `chisle` skill globally. Pi extensions run with your user permissions; review the source before installation. Project-local installs (`pi install -l npm:chisle`) load only after you trust that project.
|
|
177
|
+
|
|
113
178
|
### See what it would do, before it does it
|
|
114
179
|
|
|
115
180
|
```bash
|
|
116
181
|
npx chisle --dry-run # prints every file it would touch, changes nothing
|
|
117
182
|
```
|
|
118
183
|
|
|
119
|
-
Want the savings measured on your own work rather than ours? Clone the repo and replay the compressor over
|
|
184
|
+
Want the savings measured on your own work rather than ours? Clone the repo and replay the compressor over local transcripts — it reads them locally, writes nothing, and reports the input the hook would have stripped:
|
|
120
185
|
|
|
121
186
|
```bash
|
|
122
187
|
git clone https://github.com/JayPokale/Chisle && cd Chisle
|
|
123
|
-
node benchmarks/replay-compress.js
|
|
188
|
+
node benchmarks/replay-compress.js # Claude Code
|
|
189
|
+
node benchmarks/replay-compress.js pi # Pi; marginal over Pi's native truncation
|
|
124
190
|
```
|
|
125
191
|
|
|
126
192
|
---
|
|
@@ -147,7 +213,22 @@ Chisle wins all four columns: it cut the total 20-task bill **nearly in half** w
|
|
|
147
213
|
|
|
148
214
|
The bar is the whole 20-task bill; the badge is each tool's worst single day. caveman's worst day cost **4.2×** a bare model; ponytail's — a tool whose entire job is writing less — **2.3×**. Chisle's worst day was 1.7×, it happened once, and the fix is measured and merged.
|
|
149
215
|
|
|
150
|
-
|
|
216
|
+
In the July run all 24 answers, every arm, **graded correct**: nobody here buys token savings with wrong answers.
|
|
217
|
+
|
|
218
|
+
#### Code vs. explanation
|
|
219
|
+
|
|
220
|
+
Across all 20 cells, split by what the prompt actually asks for:
|
|
221
|
+
|
|
222
|
+
| | n | caveman | ponytail | **Chisle** |
|
|
223
|
+
|---|--:|--:|--:|--:|
|
|
224
|
+
| **coding** (wants working code) | 12 | 74% | 59% | **44%** |
|
|
225
|
+
| **non-coding** (wants an explanation) | 8 | 103% | 104% | **87%** |
|
|
226
|
+
|
|
227
|
+
Code is where the YAGNI ladder has something to bite on: an abstraction to skip, a stdlib call to reach for, a file not to create. Chisle bills **44%** of a bare model there — a third less than ponytail, which is the closest thing to a dedicated lazy-code tool.
|
|
228
|
+
|
|
229
|
+
On explanation-only prompts the picture is worse for everyone. Both specialists land **above 100%** — a tool whose job is writing less made the model write *more* than using nothing at all. Chisle is the only arm that stays under water (87%), which is a smaller win than the coding number and worth saying plainly.
|
|
230
|
+
|
|
231
|
+
This does revise a claim the earlier Sonnet writeup made. On that suite's three prose prompts caveman was leaner (44% vs 52%), and that still holds *for those cells*. Pooled across all eight non-coding cells it does not: caveman is at 103%. The prose win was suite-specific, not general.
|
|
151
232
|
|
|
152
233
|
#### Task by task
|
|
153
234
|
|
|
@@ -159,6 +240,47 @@ Averages hide the interesting part, so here is every cell of the June suite —
|
|
|
159
240
|
|
|
160
241
|
Chisle is leanest on **5 of 6**. caveman takes `cache` (8% vs our 12%) — it wins by answering in prose where we still emit working code, which is the trade you would want on a task that asked for code. Note the two prose rows where ponytail lands **above** 100%: a tool built to write less made the model write *more* than using no tool at all. That is the failure mode the worst-case column above is really about.
|
|
161
242
|
|
|
243
|
+
#### The headline average is hiding the good part
|
|
244
|
+
|
|
245
|
+
Split the same 20 cells at their median baseline — short answers below, long answers above — and the tools separate sharply:
|
|
246
|
+
|
|
247
|
+
<p align="center">
|
|
248
|
+
<img src="assets/by-size.svg" width="820" alt="Total billed output split by answer size. On short answers caveman and Chisle are level at about 84% of baseline and ponytail is above 100%. On long answers Chisle drops to about 45% while caveman is 79% and ponytail 59%.">
|
|
249
|
+
</p>
|
|
250
|
+
|
|
251
|
+
On **short** answers Chisle and caveman are level (84% each) — there is not much to cut in a three-line reply, and the ruleset overhead is proportionally at its worst. On **long** answers Chisle drops to **45%** while caveman only reaches 79%. The 52% headline is the blend of the two, so it understates the case where it matters and overstates the case where it doesn't.
|
|
252
|
+
|
|
253
|
+
The effect is not driven by one lucky cell. Dropping the `cache` outlier (the row where the baseline invented 150 lines against a codebase it never saw) *widens* the gap on long answers: caveman degrades to **116%** — worse than using no tool — while Chisle holds at **65%**.
|
|
254
|
+
|
|
255
|
+
Two honest limits. Per-task rank correlation between baseline size and leanness is weak (Spearman ρ = −0.15), so this is a difference between aggregate bills, not a tidy per-task law — with n=10 a side, treat it as a strong signal rather than a settled result. And much of the widening gap comes from the specialists getting *worse* on long answers, not only from Chisle getting better.
|
|
256
|
+
|
|
257
|
+
#### Size or kind? Both, and they're tangled
|
|
258
|
+
|
|
259
|
+
Coding prompts average ~1129 baseline tokens against ~393 for explanation prompts, so "long" and "code" largely describe the same cells. Crossing the two separates them as far as 20 tasks allow:
|
|
260
|
+
|
|
261
|
+
| | n | caveman | ponytail | **Chisle** |
|
|
262
|
+
|---|--:|--:|--:|--:|
|
|
263
|
+
| coding · short | 5 | **62%** | 116% | 70% |
|
|
264
|
+
| coding · long | 7 | 76% | 52% | **41%** |
|
|
265
|
+
| non-coding · short | 5 | 104% | 98% | **96%** |
|
|
266
|
+
| non-coding · long | 3 | 103% | 111% | **77%** |
|
|
267
|
+
|
|
268
|
+
<p align="center">
|
|
269
|
+
<img src="assets/by-kind.svg" width="820" alt="Billed output by task kind crossed with answer size. Code and short: caveman 62%, ponytail 116%, Chisle 70%. Code and long: caveman 76%, ponytail 52%, Chisle 41%. Explanation and short: caveman 104%, ponytail 98%, Chisle 96%. Explanation and long: caveman 103%, ponytail 111%, Chisle 77%.">
|
|
270
|
+
</p>
|
|
271
|
+
|
|
272
|
+
Size matters *within* each kind — coding goes 70% → 41%, non-coding 96% → 77% — so it isn't merely code in disguise. But the cells are thin, and the non-coding "long" bucket spans only 522–542 tokens, which is barely long at all.
|
|
273
|
+
|
|
274
|
+
The one row Chisle loses is **short coding**, where caveman takes it 62% to 70%. That is the honest shape of it: on a small code question there is little to skip, and the ruleset costs more than the ladder saves. The tool earns its keep on the long ones.
|
|
275
|
+
|
|
276
|
+
`SUITE=large` exists to fill the thin cells — see [below](#see-what-it-would-do-before-it-does-it).
|
|
277
|
+
|
|
278
|
+
These prompts were never designed to test this, which is the real caveat. To probe it directly:
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
SUITE=large bash benchmarks/run-live.sh <model> benchmarks/results/raw-large
|
|
282
|
+
```
|
|
283
|
+
|
|
162
284
|
#### Where each tool actually helps
|
|
163
285
|
|
|
164
286
|
| | prose | code judgment | input/context | worst-case guard | publishes failures |
|
|
@@ -170,7 +292,7 @@ Chisle is leanest on **5 of 6**. caveman takes `cache` (8% vs our 12%) — it wi
|
|
|
170
292
|
|
|
171
293
|
The row that matters is the last one. Every tool here looks good on its best day; the numbers above are the only ones in this class published alongside the run that went wrong. [Full comparison →](docs/comparison.md)
|
|
172
294
|
|
|
173
|
-
### Input axis — tool-output compression (Claude Code)
|
|
295
|
+
### Input axis — tool-output compression (Claude Code + Pi)
|
|
174
296
|
|
|
175
297
|
Measured over 171 real sessions ([receipts](benchmarks/results/2026-07-07-input-axis.md)): tool output is **67.5%** of context content, and every byte of it is re-billed on *every subsequent request* in the session (median: 171 requests). A `PostToolUse` hook shrinks it before the model reads it — deterministic, zero LLM, zero network:
|
|
176
298
|
|
|
@@ -180,13 +302,16 @@ Measured over 171 real sessions ([receipts](benchmarks/results/2026-07-07-input-
|
|
|
180
302
|
| **elide** | oversized output → head + tail, error-like lines salvaged from the cut | bounded, guarded |
|
|
181
303
|
| **dedup** | byte-identical repeat of a tool's previous output (same session) → one-line marker | none — the copy is already in context |
|
|
182
304
|
|
|
183
|
-
Replayed over the same 171 sessions: **~61k tokens**
|
|
305
|
+
Replayed over the same 171 Claude Code sessions: **~61k tokens** saved one-shot, ~46% off every eligible output — floor, not estimate, since each saved byte also stops being re-sent on every later request. Correctness rules: allowlist only (`Bash`, `Agent`, `WebFetch`, `WebSearch`, `Grep`, `Glob`, `mcp__*`) — never `Read`/`Edit`, whose exact bytes feed later edits. Honest ledger: dedup scored **0 hits** on this corpus (rtk-filtered at source); it's kept for the test-rerun case, kill-switchable, and labeled speculative until it earns a number.
|
|
306
|
+
|
|
307
|
+
Pi already truncates built-in output at 50KB/2,000 lines. Replay over 8,044 persisted Pi results measured the compressor's **marginal** saving after that truncation: **27.4% of tool-output chars** ([receipt + raw live Pi arm](benchmarks/results/2026-09-11-pi.md)). Pi compresses `bash`, `powershell`, `grep`, `find`, `ls`, MCP, and explicitly allowlisted extension-tool results; `read`/`edit`/`write` remain untouched. `CHISLE_COMPRESS_TOOLS` supplies the same explicit override for runtime and replay. Runtime dedup only compares earlier turns, so concurrently completed sibling calls cannot dedup one another.
|
|
184
308
|
|
|
185
309
|
```bash
|
|
186
|
-
node benchmarks/replay-compress.js
|
|
310
|
+
node benchmarks/replay-compress.js # Claude Code
|
|
311
|
+
node benchmarks/replay-compress.js pi # Pi
|
|
187
312
|
```
|
|
188
313
|
|
|
189
|
-
|
|
314
|
+
Outputs over 8k chars are elided. `stop chisle`, `CHISLE_COMPRESS=0`, `CHISLE_COMPRESS_SCRUB=0`, `CHISLE_COMPRESS_DEDUP=0` — every tier has an off switch.
|
|
190
315
|
|
|
191
316
|
### Prevention — the context diet
|
|
192
317
|
|
|
@@ -196,14 +321,11 @@ The biggest context whale (whole-file `Read`s — 5.6M chars in the measured cor
|
|
|
196
321
|
|
|
197
322
|
## What the output sounds like
|
|
198
323
|
|
|
199
|
-
**"Why React component re-render?"**
|
|
324
|
+
**"Why does this React component re-render?"**
|
|
200
325
|
> New object ref each render. Inline object prop = new ref = re-render. `useMemo`.
|
|
201
326
|
|
|
202
|
-
**"
|
|
203
|
-
>
|
|
204
|
-
|
|
205
|
-
**"Add a cache for API responses."** (ultra)
|
|
206
|
-
> No cache until profiler says so. When it does: `@lru_cache`. Hand-rolled TTL cache = bug farm with hit rate.
|
|
327
|
+
**"Add a cache for API responses."**
|
|
328
|
+
> `@lru_cache(maxsize=1000)` on the fetch fn. Skipped a custom cache class — add one when `lru_cache` measurably falls short.
|
|
207
329
|
|
|
208
330
|
---
|
|
209
331
|
|
|
@@ -211,15 +333,13 @@ The biggest context whale (whole-file `Read`s — 5.6M chars in the measured cor
|
|
|
211
333
|
|
|
212
334
|
| Command | Effect |
|
|
213
335
|
|---------|--------|
|
|
214
|
-
| *(nothing)* | On automatically
|
|
215
|
-
| `/chisle` | Re-activate
|
|
216
|
-
| `/chisle
|
|
217
|
-
| `/chisle full` | Full compression + YAGNI ladder enforced |
|
|
218
|
-
| `/chisle ultra` | Extremist — abbreviate prose, delete before add, challenge requirements |
|
|
336
|
+
| *(nothing)* | On automatically every session after install |
|
|
337
|
+
| `/chisle` | Re-activate if you'd stopped it |
|
|
338
|
+
| `/chisle off` | Deactivate |
|
|
219
339
|
| `stop chisle` | Deactivate (ruleset *and* input-side compression) |
|
|
220
340
|
| `normal mode` | Deactivate |
|
|
221
341
|
|
|
222
|
-
Natural language works too: "activate chisle", "chisle mode", "chislify this".
|
|
342
|
+
Natural language works too: "activate chisle", "chisle mode", "chislify this". Code symbols, function/API names, and error strings stay verbatim — only the noise around them compresses.
|
|
223
343
|
|
|
224
344
|
---
|
|
225
345
|
|
|
@@ -227,15 +347,31 @@ Natural language works too: "activate chisle", "chisle mode", "chislify this". A
|
|
|
227
347
|
|
|
228
348
|
Before writing code, the agent stops at the first rung that holds:
|
|
229
349
|
|
|
350
|
+
```mermaid
|
|
351
|
+
flowchart TD
|
|
352
|
+
A[Request for code] --> R[Read the problem fully]
|
|
353
|
+
R --> Q1{Does this need<br/>to exist at all?}
|
|
354
|
+
Q1 -->|no| S1[Skip it. Say so in one line]
|
|
355
|
+
Q1 -->|yes| Q2{Already in<br/>this codebase?}
|
|
356
|
+
Q2 -->|yes| S2[Reuse it. Don't rewrite]
|
|
357
|
+
Q2 -->|no| Q3{Stdlib<br/>does it?}
|
|
358
|
+
Q3 -->|yes| S3[Use the stdlib]
|
|
359
|
+
Q3 -->|no| Q4{Native platform<br/>feature covers it?}
|
|
360
|
+
Q4 -->|yes| S4["CSS over JS, DB constraint<br/>over app code"]
|
|
361
|
+
Q4 -->|no| Q5{Already-installed<br/>dependency?}
|
|
362
|
+
Q5 -->|yes| S5[Use it. Never add a new dep<br/>for what a few lines do]
|
|
363
|
+
Q5 -->|no| Q6{Can it be<br/>one line?}
|
|
364
|
+
Q6 -->|yes| S6[One line]
|
|
365
|
+
Q6 -->|no| S7[The minimum code that works]
|
|
366
|
+
|
|
367
|
+
S1 & S2 & S3 & S4 & S5 & S6 & S7 --> OUT[Ship it + note what was skipped<br/>and when to add it]
|
|
368
|
+
|
|
369
|
+
style Q1 fill:#1f2937,stroke:#d78a3c,color:#e6edf3
|
|
370
|
+
style OUT fill:#14532d,stroke:#2da44e,color:#e6edf3
|
|
371
|
+
style R fill:#1f2937,stroke:#8b949e,color:#e6edf3
|
|
230
372
|
```
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
3. Stdlib does it? → use it
|
|
234
|
-
4. Native platform feature? → use it
|
|
235
|
-
5. Installed dependency? → use it
|
|
236
|
-
6. One line? → one line
|
|
237
|
-
7. Only then: the minimum that works
|
|
238
|
-
```
|
|
373
|
+
|
|
374
|
+
The ladder runs **after** reading, never instead of it. Note the exit: every rung lands on the same obligation — say what you skipped, so "later" doesn't quietly become "never".
|
|
239
375
|
|
|
240
376
|
The ladder runs *after* reading the code — lazy about the solution, never about understanding. Lazy is not negligent: trust-boundary validation, data-loss handling, security, and accessibility are never on the chopping block.
|
|
241
377
|
|
|
@@ -250,17 +386,17 @@ Mark deliberate simplifications so "later" doesn't quietly become "never":
|
|
|
250
386
|
|
|
251
387
|
## Config
|
|
252
388
|
|
|
253
|
-
**On by default.** After install,
|
|
389
|
+
**On by default.** After install, Chisle activates automatically every session — no `/chisle` needed. Set `off` to stay dormant until you type `/chisle`:
|
|
254
390
|
|
|
255
391
|
```bash
|
|
256
392
|
# env var (highest priority)
|
|
257
|
-
export CHISLE_DEFAULT_MODE=
|
|
393
|
+
export CHISLE_DEFAULT_MODE=off
|
|
258
394
|
|
|
259
395
|
# config file (persists across shells)
|
|
260
|
-
~/.config/chisle/config.json → { "defaultMode": "
|
|
396
|
+
~/.config/chisle/config.json → { "defaultMode": "off" }
|
|
261
397
|
```
|
|
262
398
|
|
|
263
|
-
Resolution: env var → config file → `
|
|
399
|
+
Resolution: env var → config file → `on`. Valid: `off`, `on`.
|
|
264
400
|
|
|
265
401
|
---
|
|
266
402
|
|
|
@@ -280,12 +416,14 @@ Chisle borrows the best published token-saving techniques and implements the one
|
|
|
280
416
|
|
|
281
417
|
## Multi-agent
|
|
282
418
|
|
|
283
|
-
|
|
419
|
+
Ships to nine agents: Claude Code and Pi get both axes, live `/chisle` toggling, and a status badge; Cursor, Windsurf, Cline, Kiro, Codex, Gemini, and Copilot get the always-on ruleset. Per-agent static copies come from `scripts/build-rules.js`; Pi uses its package extension plus the Agent Skills standard. See [`docs/agent-portability.md`](./docs/agent-portability.md).
|
|
284
420
|
|
|
285
421
|
## FAQ
|
|
286
422
|
|
|
287
423
|
**Doesn't injecting a persona every turn cost tokens?**
|
|
288
|
-
|
|
424
|
+
Claude Code uses a ruleset at session start (~1.6k tokens) plus a ~50-token reminder per turn. Pi injects one persistent rules message only when project `AGENTS.md` does not already provide it; resume/reload does not duplicate it, and compaction restores it only if removed.
|
|
425
|
+
|
|
426
|
+
Worth reading the dissent before you take that on faith: [@enc0ded](https://github.com/enc0ded) measured 173 of their own sessions ([#2](https://github.com/JayPokale/Chisle/issues/2)) and found the injection overhead roughly cancelling the compressor's savings — because the ruleset was being re-sent on every resume and clear, not just at startup. That re-injection is fixed, which removes most of the overhead they measured, but their wider point stands: prose is only ~25% of what the model emits, so the ceiling on the output axis is lower than the headline suggests, and on a one-line throwaway prompt the overhead still exceeds the saving.
|
|
289
427
|
|
|
290
428
|
**Will it golf my code into clever one-liners?**
|
|
291
429
|
No. Boring over clever. Deletion beats addition; obfuscation isn't deletion.
|
|
@@ -310,7 +448,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md). Edit the skill (`skills/chisle/SKILL.md`
|
|
|
310
448
|
Built by [Jay Pokale](https://github.com/JayPokale) with [Claude](https://claude.com/claude-code), [Antigravity](https://antigravity.google), and [Codex](https://openai.com/blog/openai-codex/) as co-engineers — the input-compression hook, the benchmark verification, and several of the bug hunts documented in the changelog were pair-work.
|
|
311
449
|
|
|
312
450
|
```bash
|
|
313
|
-
npm test #
|
|
451
|
+
npm test # 67 tests: flag safety, tracker, settings merge, installer, compressor
|
|
314
452
|
```
|
|
315
453
|
|
|
316
454
|
## License
|
package/bin/install.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// Detects the AI coding agents on this machine and installs Chisle for each:
|
|
5
5
|
// - Claude Code → plugin (marketplace add + install), fallback to standalone
|
|
6
6
|
// hooks + settings.json merge + statusline badge
|
|
7
|
+
// - Pi → Pi package (extension + skill)
|
|
7
8
|
// - Gemini CLI → gemini extensions install
|
|
8
9
|
// - Codex → fenced ruleset appended to ~/.codex/AGENTS.md
|
|
9
10
|
// - Cursor/Windsurf/Cline/Kiro/Copilot → project rule file dropped into CWD
|
|
@@ -39,6 +40,7 @@ const REPO_ROOT = path.resolve(__dirname, '..');
|
|
|
39
40
|
// (that's how Cursor/Cline/Copilot rules actually work).
|
|
40
41
|
const PROVIDERS = [
|
|
41
42
|
{ id: 'claude', label: 'Claude Code', scope: 'global', detect: 'cmd:claude' },
|
|
43
|
+
{ id: 'pi', label: 'Pi', scope: 'global', detect: 'cmd:pi' },
|
|
42
44
|
{ id: 'gemini', label: 'Gemini CLI', scope: 'global', detect: 'cmd:gemini' },
|
|
43
45
|
{ id: 'codex', label: 'Codex CLI', scope: 'global', detect: 'cmd:codex||dir:~/.codex' },
|
|
44
46
|
{ id: 'cursor', label: 'Cursor', scope: 'project', detect: 'cmd:cursor||dir:~/.cursor',
|
|
@@ -196,6 +198,18 @@ function installClaude(ctx) {
|
|
|
196
198
|
else results.failed.push(['claude-hooks', r]);
|
|
197
199
|
} else {
|
|
198
200
|
note(' hooks: plugin manifest handles SessionStart + UserPromptSubmit + PostToolUse');
|
|
201
|
+
// Plugin path won — drop any standalone wiring left by an earlier run, or
|
|
202
|
+
// both copies of every hook run on each event and the PostToolUse pair
|
|
203
|
+
// dedups first-seen output against itself.
|
|
204
|
+
const settingsPath = path.join(claudeDir(opts), 'settings.json');
|
|
205
|
+
const settings = SETTINGS.readSettings(settingsPath);
|
|
206
|
+
if (settings && SETTINGS.removeHooks(settings, 'chisle-') > 0) {
|
|
207
|
+
if (!opts.dryRun) {
|
|
208
|
+
SETTINGS.validateHookFields(settings);
|
|
209
|
+
SETTINGS.writeSettings(settingsPath, settings);
|
|
210
|
+
}
|
|
211
|
+
note(' removed superseded standalone hook entries from settings.json');
|
|
212
|
+
}
|
|
199
213
|
}
|
|
200
214
|
process.stdout.write('\n');
|
|
201
215
|
}
|
|
@@ -209,7 +223,7 @@ function installClaudeHooks(ctx) {
|
|
|
209
223
|
const hooksDst = path.join(cfg, 'chisle-hooks');
|
|
210
224
|
const settingsPath = path.join(cfg, 'settings.json');
|
|
211
225
|
const HOOK_FILES = ['package.json', 'chisle-config.js', 'chisle-activate.js',
|
|
212
|
-
'chisle-mode-tracker.js', 'chisle-compress-output.js',
|
|
226
|
+
'chisle-mode.js', 'chisle-mode-tracker.js', 'chisle-compress-output.js',
|
|
213
227
|
'chisle-statusline.sh', 'chisle-statusline.ps1'];
|
|
214
228
|
|
|
215
229
|
if (opts.dryRun) {
|
|
@@ -263,6 +277,30 @@ function installClaudeHooks(ctx) {
|
|
|
263
277
|
return 'ok';
|
|
264
278
|
}
|
|
265
279
|
|
|
280
|
+
// ── Pi ──────────────────────────────────────────────────────────────────────
|
|
281
|
+
function piSources(output) {
|
|
282
|
+
return String(output || '').split('\n').map(line => line.trim())
|
|
283
|
+
.filter(line => /^npm:chisle(?:@|$)/i.test(line) || /^git:.*github\.com\/JayPokale\/Chisle(?:@|$)/i.test(line))
|
|
284
|
+
.map(source => source.replace(/@[^/@]+$/, ''));
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function installPi(ctx) {
|
|
288
|
+
const { say, note, opts, results } = ctx;
|
|
289
|
+
results.detected++;
|
|
290
|
+
say('→ Pi detected');
|
|
291
|
+
if (!opts.force) {
|
|
292
|
+
const installed = piSources(capture('pi', ['list']).stdout);
|
|
293
|
+
if (installed.length) {
|
|
294
|
+
note(' chisle package already installed (use --force)');
|
|
295
|
+
results.skipped.push(['pi', 'already installed']); process.stdout.write('\n'); return;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
const r = run('pi', ['install', 'npm:chisle'], opts.dryRun);
|
|
299
|
+
if ((r.status || 0) === 0) results.installed.push('pi');
|
|
300
|
+
else results.failed.push(['pi', 'pi package install failed']);
|
|
301
|
+
process.stdout.write('\n');
|
|
302
|
+
}
|
|
303
|
+
|
|
266
304
|
// ── Gemini ──────────────────────────────────────────────────────────────────
|
|
267
305
|
function installGemini(ctx) {
|
|
268
306
|
const { say, note, opts, results } = ctx;
|
|
@@ -347,53 +385,66 @@ function uninstall(ctx) {
|
|
|
347
385
|
say(c.orange('Chisle uninstall'));
|
|
348
386
|
let touched = 0;
|
|
349
387
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
388
|
+
const wants = id => !opts.only.length || opts.only.includes(id);
|
|
389
|
+
|
|
390
|
+
if (wants('claude')) {
|
|
391
|
+
// Claude plugin
|
|
392
|
+
if (hasCmd('claude') && !opts.dryRun) {
|
|
393
|
+
const r = capture('claude', ['plugin', 'list']);
|
|
394
|
+
if (r.status === 0 && /chisle/i.test(r.stdout || '')) {
|
|
395
|
+
run('claude', ['plugin', 'uninstall', 'chisle@chisle'], opts.dryRun); touched++;
|
|
396
|
+
}
|
|
355
397
|
}
|
|
356
|
-
}
|
|
357
398
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
399
|
+
// Claude standalone hooks + statusline
|
|
400
|
+
const cfg = claudeDir(opts);
|
|
401
|
+
const settingsPath = path.join(cfg, 'settings.json');
|
|
402
|
+
const settings = SETTINGS.readSettings(settingsPath);
|
|
403
|
+
if (settings) {
|
|
404
|
+
const removed = SETTINGS.removeHooks(settings, 'chisle-');
|
|
405
|
+
let slRemoved = false;
|
|
406
|
+
if (settings.statusLine && typeof settings.statusLine.command === 'string'
|
|
407
|
+
&& settings.statusLine.command.includes('chisle-statusline')) { delete settings.statusLine; slRemoved = true; }
|
|
408
|
+
if (removed > 0 || slRemoved) {
|
|
409
|
+
if (!opts.dryRun) { SETTINGS.validateHookFields(settings); SETTINGS.writeSettings(settingsPath, settings); }
|
|
410
|
+
note(` removed ${removed} hook entr${removed === 1 ? 'y' : 'ies'}${slRemoved ? ' + statusline' : ''} from settings.json`);
|
|
411
|
+
touched++;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
const hooksDst = path.join(cfg, 'chisle-hooks');
|
|
415
|
+
if (fs.existsSync(hooksDst)) { if (!opts.dryRun) fs.rmSync(hooksDst, { recursive: true, force: true }); note(` removed ${hooksDst}`); touched++; }
|
|
416
|
+
|
|
417
|
+
for (const f of ['.chisle-active', '.chisle-session-turns', '.chisle-statusline-suffix',
|
|
418
|
+
'.chisle-compress-stats.json', '.chisle-compress-last.json', '.chisle-update-check.json']) {
|
|
419
|
+
const p = path.join(cfg, f);
|
|
420
|
+
if (fs.existsSync(p)) { if (!opts.dryRun) { try { fs.unlinkSync(p); } catch (_) {} } note(` removed ${p}`); touched++; }
|
|
371
421
|
}
|
|
372
422
|
}
|
|
373
|
-
const hooksDst = path.join(cfg, 'chisle-hooks');
|
|
374
|
-
if (fs.existsSync(hooksDst)) { if (!opts.dryRun) fs.rmSync(hooksDst, { recursive: true, force: true }); note(` removed ${hooksDst}`); touched++; }
|
|
375
423
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
424
|
+
if (wants('pi') && hasCmd('pi')) {
|
|
425
|
+
const sources = piSources(capture('pi', ['list']).stdout);
|
|
426
|
+
for (const source of sources) {
|
|
427
|
+
if ((run('pi', ['remove', source], opts.dryRun).status || 0) === 0) touched++;
|
|
428
|
+
}
|
|
381
429
|
}
|
|
382
430
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
431
|
+
if (wants('codex')) {
|
|
432
|
+
const codexMd = path.join(os.homedir(), '.codex', 'AGENTS.md');
|
|
433
|
+
if (fs.existsSync(codexMd)) {
|
|
434
|
+
const txt = fs.readFileSync(codexMd, 'utf8');
|
|
435
|
+
if (txt.includes(FENCE_BEGIN)) {
|
|
436
|
+
const stripped = txt.replace(new RegExp(`\\n?${FENCE_BEGIN}[\\s\\S]*?${FENCE_END}\\n?`), '\n').replace(/\n{3,}/g, '\n\n');
|
|
437
|
+
if (!opts.dryRun) fs.writeFileSync(codexMd, stripped, { mode: 0o644 });
|
|
438
|
+
note(` removed chisle block from ${codexMd}`); touched++;
|
|
439
|
+
}
|
|
391
440
|
}
|
|
392
441
|
}
|
|
393
442
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
443
|
+
if (!opts.only.length || opts.only.some(id => PROVIDERS.find(p => p.id === id).scope === 'project')) {
|
|
444
|
+
note('');
|
|
445
|
+
note('Project-scoped rule files (.cursor/, .windsurf/, .clinerules/, .kiro/, .github/copilot-instructions.md)');
|
|
446
|
+
note('live in your project repos — remove them per-project with git if you added them there.');
|
|
447
|
+
}
|
|
397
448
|
say(touched ? c.green(`\nUninstalled. ${touched} item(s) cleaned.`) : c.yellow('\nNothing to uninstall.'));
|
|
398
449
|
}
|
|
399
450
|
|
|
@@ -406,7 +457,7 @@ Usage:
|
|
|
406
457
|
|
|
407
458
|
Flags:
|
|
408
459
|
--list Detect agents and print them; install nothing
|
|
409
|
-
--only <id>
|
|
460
|
+
--only <id> Limit install/uninstall to one agent (repeatable)
|
|
410
461
|
--dry-run Print actions, change nothing
|
|
411
462
|
--force Reinstall / overwrite even if already present
|
|
412
463
|
--uninstall, -u Remove what chisle installed
|
|
@@ -463,6 +514,7 @@ function main() {
|
|
|
463
514
|
|
|
464
515
|
for (const p of targets) {
|
|
465
516
|
if (p.id === 'claude') installClaude(ctx);
|
|
517
|
+
else if (p.id === 'pi') installPi(ctx);
|
|
466
518
|
else if (p.id === 'gemini') installGemini(ctx);
|
|
467
519
|
else if (p.id === 'codex') installCodex(ctx);
|
|
468
520
|
else installProjectRule(ctx, p);
|
|
@@ -476,7 +528,7 @@ function main() {
|
|
|
476
528
|
if (results.failed.length) say(c.red(` failed: ${results.failed.map(s => s[0] + ' (' + s[1] + ')').join(', ')}`));
|
|
477
529
|
say('');
|
|
478
530
|
if (!opts.dryRun && results.installed.length) {
|
|
479
|
-
say(c.orange('Done.') + ' Restart your agent. Type ' + c.orange('/chisle') + '
|
|
531
|
+
say(c.orange('Done.') + ' Restart your agent. Type ' + c.orange('/chisle') + ' in Claude Code or Pi, or just start coding.');
|
|
480
532
|
note('If Chisle earns its keep, a star helps others find it: https://github.com/JayPokale/Chisle');
|
|
481
533
|
}
|
|
482
534
|
process.exit(results.failed.length ? 1 : 0);
|