nblean 0.1.0__tar.gz

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.
nblean-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Recep Kaan Karaman
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
nblean-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,283 @@
1
+ Metadata-Version: 2.4
2
+ Name: nblean
3
+ Version: 0.1.0
4
+ Summary: Token-lean Jupyter notebook access for coding agents: outlines, clipped outputs, lazy images, a persistent kernel.
5
+ Keywords: jupyter,notebook,ipynb,llm,coding-agent,claude-code,tokens,cli
6
+ Author: Recep Kaan Karaman
7
+ Author-email: Recep Kaan Karaman <kaanrkaraman@gmail.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Framework :: Jupyter
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Topic :: Scientific/Engineering
21
+ Classifier: Topic :: Software Development
22
+ Classifier: Typing :: Typed
23
+ Requires-Dist: jupyter-client>=8.10.0
24
+ Requires-Python: >=3.13
25
+ Project-URL: Homepage, https://github.com/kaanrkaraman/nblean
26
+ Project-URL: Repository, https://github.com/kaanrkaraman/nblean
27
+ Project-URL: Issues, https://github.com/kaanrkaraman/nblean/issues
28
+ Description-Content-Type: text/markdown
29
+
30
+ <p align="center">
31
+ <strong>nblean</strong><br>
32
+ <strong>Lets coding agents work with Jupyter notebooks without reading every output</strong>
33
+ </p>
34
+
35
+ <p align="center">
36
+ <a href="https://github.com/kaanrkaraman/nblean/actions/workflows/ci.yml"><img src="https://github.com/kaanrkaraman/nblean/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
37
+ <a href="https://pypi.org/project/nblean/"><img src="https://img.shields.io/pypi/v/nblean" alt="PyPI"></a>
38
+ <a href="https://pypi.org/project/nblean/"><img src="https://img.shields.io/pypi/pyversions/nblean" alt="Python"></a>
39
+ <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT"></a>
40
+ </p>
41
+
42
+ <p align="center">
43
+ <a href="#installation">Install</a> &bull;
44
+ <a href="#quick-start">Quick Start</a> &bull;
45
+ <a href="#commands">Commands</a> &bull;
46
+ <a href="#how-savings-work">Benchmarks</a> &bull;
47
+ <a href="#supported-agents">Agents</a>
48
+ </p>
49
+
50
+ ---
51
+
52
+ An `.ipynb` file holds code plus everything the code printed: DataFrame dumps,
53
+ progress bars, tracebacks, and plots stored as base64 images. An agent that opens one
54
+ reads all of it. To fix one cell, it then runs the whole notebook again and reads the
55
+ result again.
56
+
57
+ nblean is a small CLI and agent skill that lets the agent work one cell at a time. It
58
+ lists the notebook as an outline, opens only the cells asked for, clips their outputs,
59
+ and runs cells in a background kernel that stays alive between commands.
60
+
61
+ ## What nblean Does
62
+
63
+ | Agent needs to | Without nblean | With nblean |
64
+ |---|---|---|
65
+ | See what a notebook contains | Reads the whole JSON, outputs included | `outline`: one line per cell, with an output summary like `→ 14L img ERR KeyError` |
66
+ | Look at a few cells | Writes a one-off `json`/`jq` script | `show 12 15-18`: source, plus outputs clipped to the first and last lines |
67
+ | Find code | Greps JSON-escaped strings | `grep`: matches by cell and line number |
68
+ | Debug | Scrolls through ANSI-colored tracebacks full of library frames | `errors`: only the failing cells, showing your frame and the exception |
69
+ | Edit a cell | Rewrites the JSON, or reads the notebook first | `set` / `add` / `rm`, with the new source passed on stdin |
70
+ | Re-run after a fix | Runs the whole notebook again and reads all the output | `run 12`: runs that cell in a kernel that is still alive, prints only its output, and saves it into the notebook |
71
+ | Check a value | Adds a throwaway `print` cell | `eval 'df.dtypes'`: runs the code in the kernel without changing the notebook |
72
+ | Look at plots | Every plot costs image tokens | Plots are saved as files and only their paths are printed; the agent opens one when it needs to |
73
+
74
+ ## How Savings Work
75
+
76
+ nblean cuts **notebook tokens**, which are only part of an agent's bill. Every session
77
+ also pays for the system prompt, tool definitions, and conversation history. These
78
+ fixed costs come to about 28k tokens per session on Claude Code. Savings grow with the
79
+ size of the notebook and the volume of its outputs.
80
+
81
+ ### A/B test in Claude Code
82
+
83
+ Claude Sonnet ran headless (`claude -p`), two times with the nblean skill and two
84
+ times without it. Token counts
85
+ come from the `usage` that Claude Code reports; costs are what the same usage would
86
+ cost at API prices.
87
+
88
+ | Task | Without nblean | With nblean | Change |
89
+ |---|---:|---:|---:|
90
+ | Answer two questions from the saved outputs of a 7 MB EDA notebook (97 cells, 31 plots) | 236k tokens · $0.207 | 172k tokens · $0.160 | **-27% tokens, -23% cost** |
91
+ | Find and fix a bug in a 124 KB notebook, then re-run it until clean | 183k tokens · $0.153 | 183k tokens · $0.150 | no measurable change |
92
+
93
+ The first version of nblean showed execution counts in the outline, and one run
94
+ reported them as cell indices. The numbers above come from runs after that fix, and
95
+ all of them answered correctly. Every fix run ended with a clean notebook. On the
96
+ small notebook the baseline agent already worked efficiently: it ran `nbconvert` and
97
+ grepped for errors, so nblean had little to remove.
98
+
99
+ ### First look
100
+
101
+ This compares the `outline` output with reading the whole notebook,
102
+ counting text as bytes/4 and images by pixel area. It is an upper bound on what the
103
+ first step saves.
104
+
105
+ | Notebook | Whole notebook | `nblean outline` |
106
+ |---|---:|---:|
107
+ | Flight-data EDA, 97 cells, 31 plots | ~81k | ~1.5k |
108
+ | Data preprocessing | ~58k | ~260 |
109
+ | Kaggle training run | ~29k | ~90 |
110
+
111
+ ## Installation
112
+
113
+ ```bash
114
+ uv tool install nblean # or: pipx install nblean
115
+ nblean --help
116
+ ```
117
+
118
+ You can also run it without installing: `uvx nblean outline nb.ipynb`.
119
+
120
+ The kernel runs in the notebook's own environment, not in nblean's. nblean picks the
121
+ nearest `.venv` above the notebook, which needs `ipykernel` installed
122
+ (`uv add --dev ipykernel`). Use `--python PATH` to pick a different interpreter.
123
+
124
+ ## Quick Start
125
+
126
+ ```bash
127
+ # 1. Install the skill for your agent
128
+ nblean init # Claude Code (default)
129
+ nblean init --agent codex # Codex
130
+ nblean init --agent opencode # OpenCode
131
+ nblean init --agent gemini # Gemini CLI
132
+ nblean init --agent all # all of the above
133
+ nblean init --project # into ./ instead of ~/
134
+
135
+ # 2. Ask your agent anything about a notebook
136
+ ```
137
+
138
+ The skill tells the agent to start with `outline` and never to read the `.ipynb`
139
+ directly.
140
+
141
+ ## How It Works
142
+
143
+ ```
144
+ Without nblean: With nblean:
145
+
146
+ agent --read--> nb.ipynb agent --outline/show--> nblean --> nb.ipynb
147
+ ^ | ^ | clip, summarize,
148
+ | every source, | | only requested | images to files
149
+ | output, image | | cells, clipped |
150
+ +-----------------+ +-----------------------+
151
+ agent --run 12--> nblean --> live kernel
152
+ | only this cell's output,
153
+ | saved back into nb.ipynb
154
+ ```
155
+
156
+ The kernel is a detached `ipykernel` process. Each notebook gets its own kernel, and
157
+ each nblean call connects to it, runs code, and disconnects. Variables stay in memory
158
+ between calls until `kernel stop` or `kernel restart`.
159
+
160
+ ## Commands
161
+
162
+ CELL is an index (`12`), a range (`3-7`, `5-`), `all`, or the start of a cell id.
163
+
164
+ ### Read
165
+
166
+ ```bash
167
+ nblean outline nb.ipynb # one line per cell
168
+ nblean show nb.ipynb 12 15-18 # source + clipped outputs
169
+ nblean show nb.ipynb 12 --no-output # source only
170
+ nblean show nb.ipynb 12 --lines 60 # bigger clip; --full disables it
171
+ nblean grep nb.ipynb 'read_csv' # search sources; -o includes outputs
172
+ nblean errors nb.ipynb # failing cells only
173
+ ```
174
+
175
+ ### Edit
176
+
177
+ ```bash
178
+ nblean set nb.ipynb 12 <<'PY' # replace source, clears stale outputs
179
+ df = pd.read_parquet(path)
180
+ PY
181
+ nblean add nb.ipynb --at 13 <<'PY' # insert; --md for markdown
182
+ df.describe()
183
+ PY
184
+ nblean rm nb.ipynb 14 20-22
185
+ ```
186
+
187
+ ### Execute
188
+
189
+ ```bash
190
+ nblean run nb.ipynb 0-12 # run cells, save outputs, stop at first error
191
+ nblean eval nb.ipynb 'df.shape' # scratch code, nothing saved
192
+ nblean kernel nb.ipynb status|stop|restart
193
+ ```
194
+
195
+ ## Examples
196
+
197
+ ```
198
+ $ nblean outline eda.ipynb
199
+ eda.ipynb: 97 cells (36 markdown, 61 code), kernel off
200
+ 0 md 1. Files and Schema +14L
201
+ 1 code import itertools +27L
202
+ 3 code files = pl.DataFrame( +5L → 13L
203
+ 13 code p0 = pl.read_parquet(PARQ / "part.0.parquet") +7L → 1L img
204
+ 15 code fl_min = feat["flight_length"].to_numpy() / 60 +19L → img
205
+ ```
206
+
207
+ A 40-line pandas traceback, cut down to the line that failed:
208
+
209
+ ```
210
+ $ nblean errors buggy.ipynb
211
+ ── 8 code id=cell08 exec=3 ──
212
+ KeyError Traceback (most recent call last)
213
+ Cell In[3], line 1
214
+ ----> 1 df["pressure_kpa"] = df["presure"] * 6.89476
215
+ 2 df.head()
216
+
217
+ … 11 library or chained frames omitted …
218
+ KeyError: 'presure'
219
+ ```
220
+
221
+ A 300-line training log, with a plot that is saved to a file instead of loaded:
222
+
223
+ ```
224
+ $ nblean run buggy.ipynb 3 4 --lines 6
225
+ ── 3 code id=cell03 exec=4 ──
226
+ epoch 000 smoothing pass loss=1.000000 temp_mean=141.845
227
+ epoch 001 smoothing pass loss=0.500000 temp_mean=141.724
228
+ epoch 002 smoothing pass loss=0.333333 temp_mean=141.651
229
+ … 294 lines omitted …
230
+ epoch 297 smoothing pass loss=0.003356 temp_mean=139.027
231
+ epoch 298 smoothing pass loss=0.003344 temp_mean=139.038
232
+ epoch 299 smoothing pass loss=0.003333 temp_mean=139.048
233
+ ── 4 code id=cell04 exec=5 ──
234
+ [image/png → /tmp/nblean/buggy-ec4a859a6390/img/4_0.png]
235
+ ```
236
+
237
+ ## Supported Agents
238
+
239
+ The skill uses the [Agent Skills](https://agentskills.io) `SKILL.md` format, so the
240
+ same file works in every agent below. The CLI works with any agent that can run shell
241
+ commands.
242
+
243
+ | Agent | `nblean init` | Skill location |
244
+ |---|---|---|
245
+ | Claude Code | `--agent claude`, or the plugin below | `~/.claude/skills/nblean` |
246
+ | Codex | `--agent codex` | `~/.agents/skills/nblean` |
247
+ | OpenCode | `--agent opencode` | `~/.agents/skills/nblean` |
248
+ | Gemini CLI | `--agent gemini` | `~/.gemini/skills/nblean` |
249
+ | Others | `npx skills add kaanrkaraman/nblean` | per agent |
250
+
251
+ In Claude Code the skill is also available as a plugin:
252
+
253
+ ```
254
+ /plugin marketplace add kaanrkaraman/nblean
255
+ /plugin install nblean@nblean
256
+ ```
257
+
258
+ nblean ships as a CLI and a skill instead of an MCP server. An MCP server's tool
259
+ definitions are loaded into every session. A skill is loaded only when a notebook
260
+ comes up.
261
+
262
+ ## Platform Support
263
+
264
+ macOS, Linux, and Windows, on Python 3.13+. The kernel's Python can be any version
265
+ that `ipykernel` supports.
266
+
267
+ ## Limitations
268
+
269
+ - A cell's outputs are written when the cell finishes. If a long cell is killed, its output is lost.
270
+ - Writes are atomic but not merged. If the notebook is open in Jupyter or VS Code, reload it there after nblean writes.
271
+ - Widgets, `update_display_data`, and `input()` are not supported.
272
+
273
+ ## Contributing
274
+
275
+ ```bash
276
+ uv sync
277
+ uv run pytest
278
+ uv run ruff check . && uv run mypy
279
+ ```
280
+
281
+ ## License
282
+
283
+ [MIT](LICENSE)
nblean-0.1.0/README.md ADDED
@@ -0,0 +1,254 @@
1
+ <p align="center">
2
+ <strong>nblean</strong><br>
3
+ <strong>Lets coding agents work with Jupyter notebooks without reading every output</strong>
4
+ </p>
5
+
6
+ <p align="center">
7
+ <a href="https://github.com/kaanrkaraman/nblean/actions/workflows/ci.yml"><img src="https://github.com/kaanrkaraman/nblean/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
8
+ <a href="https://pypi.org/project/nblean/"><img src="https://img.shields.io/pypi/v/nblean" alt="PyPI"></a>
9
+ <a href="https://pypi.org/project/nblean/"><img src="https://img.shields.io/pypi/pyversions/nblean" alt="Python"></a>
10
+ <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT"></a>
11
+ </p>
12
+
13
+ <p align="center">
14
+ <a href="#installation">Install</a> &bull;
15
+ <a href="#quick-start">Quick Start</a> &bull;
16
+ <a href="#commands">Commands</a> &bull;
17
+ <a href="#how-savings-work">Benchmarks</a> &bull;
18
+ <a href="#supported-agents">Agents</a>
19
+ </p>
20
+
21
+ ---
22
+
23
+ An `.ipynb` file holds code plus everything the code printed: DataFrame dumps,
24
+ progress bars, tracebacks, and plots stored as base64 images. An agent that opens one
25
+ reads all of it. To fix one cell, it then runs the whole notebook again and reads the
26
+ result again.
27
+
28
+ nblean is a small CLI and agent skill that lets the agent work one cell at a time. It
29
+ lists the notebook as an outline, opens only the cells asked for, clips their outputs,
30
+ and runs cells in a background kernel that stays alive between commands.
31
+
32
+ ## What nblean Does
33
+
34
+ | Agent needs to | Without nblean | With nblean |
35
+ |---|---|---|
36
+ | See what a notebook contains | Reads the whole JSON, outputs included | `outline`: one line per cell, with an output summary like `→ 14L img ERR KeyError` |
37
+ | Look at a few cells | Writes a one-off `json`/`jq` script | `show 12 15-18`: source, plus outputs clipped to the first and last lines |
38
+ | Find code | Greps JSON-escaped strings | `grep`: matches by cell and line number |
39
+ | Debug | Scrolls through ANSI-colored tracebacks full of library frames | `errors`: only the failing cells, showing your frame and the exception |
40
+ | Edit a cell | Rewrites the JSON, or reads the notebook first | `set` / `add` / `rm`, with the new source passed on stdin |
41
+ | Re-run after a fix | Runs the whole notebook again and reads all the output | `run 12`: runs that cell in a kernel that is still alive, prints only its output, and saves it into the notebook |
42
+ | Check a value | Adds a throwaway `print` cell | `eval 'df.dtypes'`: runs the code in the kernel without changing the notebook |
43
+ | Look at plots | Every plot costs image tokens | Plots are saved as files and only their paths are printed; the agent opens one when it needs to |
44
+
45
+ ## How Savings Work
46
+
47
+ nblean cuts **notebook tokens**, which are only part of an agent's bill. Every session
48
+ also pays for the system prompt, tool definitions, and conversation history. These
49
+ fixed costs come to about 28k tokens per session on Claude Code. Savings grow with the
50
+ size of the notebook and the volume of its outputs.
51
+
52
+ ### A/B test in Claude Code
53
+
54
+ Claude Sonnet ran headless (`claude -p`), two times with the nblean skill and two
55
+ times without it. Token counts
56
+ come from the `usage` that Claude Code reports; costs are what the same usage would
57
+ cost at API prices.
58
+
59
+ | Task | Without nblean | With nblean | Change |
60
+ |---|---:|---:|---:|
61
+ | Answer two questions from the saved outputs of a 7 MB EDA notebook (97 cells, 31 plots) | 236k tokens · $0.207 | 172k tokens · $0.160 | **-27% tokens, -23% cost** |
62
+ | Find and fix a bug in a 124 KB notebook, then re-run it until clean | 183k tokens · $0.153 | 183k tokens · $0.150 | no measurable change |
63
+
64
+ The first version of nblean showed execution counts in the outline, and one run
65
+ reported them as cell indices. The numbers above come from runs after that fix, and
66
+ all of them answered correctly. Every fix run ended with a clean notebook. On the
67
+ small notebook the baseline agent already worked efficiently: it ran `nbconvert` and
68
+ grepped for errors, so nblean had little to remove.
69
+
70
+ ### First look
71
+
72
+ This compares the `outline` output with reading the whole notebook,
73
+ counting text as bytes/4 and images by pixel area. It is an upper bound on what the
74
+ first step saves.
75
+
76
+ | Notebook | Whole notebook | `nblean outline` |
77
+ |---|---:|---:|
78
+ | Flight-data EDA, 97 cells, 31 plots | ~81k | ~1.5k |
79
+ | Data preprocessing | ~58k | ~260 |
80
+ | Kaggle training run | ~29k | ~90 |
81
+
82
+ ## Installation
83
+
84
+ ```bash
85
+ uv tool install nblean # or: pipx install nblean
86
+ nblean --help
87
+ ```
88
+
89
+ You can also run it without installing: `uvx nblean outline nb.ipynb`.
90
+
91
+ The kernel runs in the notebook's own environment, not in nblean's. nblean picks the
92
+ nearest `.venv` above the notebook, which needs `ipykernel` installed
93
+ (`uv add --dev ipykernel`). Use `--python PATH` to pick a different interpreter.
94
+
95
+ ## Quick Start
96
+
97
+ ```bash
98
+ # 1. Install the skill for your agent
99
+ nblean init # Claude Code (default)
100
+ nblean init --agent codex # Codex
101
+ nblean init --agent opencode # OpenCode
102
+ nblean init --agent gemini # Gemini CLI
103
+ nblean init --agent all # all of the above
104
+ nblean init --project # into ./ instead of ~/
105
+
106
+ # 2. Ask your agent anything about a notebook
107
+ ```
108
+
109
+ The skill tells the agent to start with `outline` and never to read the `.ipynb`
110
+ directly.
111
+
112
+ ## How It Works
113
+
114
+ ```
115
+ Without nblean: With nblean:
116
+
117
+ agent --read--> nb.ipynb agent --outline/show--> nblean --> nb.ipynb
118
+ ^ | ^ | clip, summarize,
119
+ | every source, | | only requested | images to files
120
+ | output, image | | cells, clipped |
121
+ +-----------------+ +-----------------------+
122
+ agent --run 12--> nblean --> live kernel
123
+ | only this cell's output,
124
+ | saved back into nb.ipynb
125
+ ```
126
+
127
+ The kernel is a detached `ipykernel` process. Each notebook gets its own kernel, and
128
+ each nblean call connects to it, runs code, and disconnects. Variables stay in memory
129
+ between calls until `kernel stop` or `kernel restart`.
130
+
131
+ ## Commands
132
+
133
+ CELL is an index (`12`), a range (`3-7`, `5-`), `all`, or the start of a cell id.
134
+
135
+ ### Read
136
+
137
+ ```bash
138
+ nblean outline nb.ipynb # one line per cell
139
+ nblean show nb.ipynb 12 15-18 # source + clipped outputs
140
+ nblean show nb.ipynb 12 --no-output # source only
141
+ nblean show nb.ipynb 12 --lines 60 # bigger clip; --full disables it
142
+ nblean grep nb.ipynb 'read_csv' # search sources; -o includes outputs
143
+ nblean errors nb.ipynb # failing cells only
144
+ ```
145
+
146
+ ### Edit
147
+
148
+ ```bash
149
+ nblean set nb.ipynb 12 <<'PY' # replace source, clears stale outputs
150
+ df = pd.read_parquet(path)
151
+ PY
152
+ nblean add nb.ipynb --at 13 <<'PY' # insert; --md for markdown
153
+ df.describe()
154
+ PY
155
+ nblean rm nb.ipynb 14 20-22
156
+ ```
157
+
158
+ ### Execute
159
+
160
+ ```bash
161
+ nblean run nb.ipynb 0-12 # run cells, save outputs, stop at first error
162
+ nblean eval nb.ipynb 'df.shape' # scratch code, nothing saved
163
+ nblean kernel nb.ipynb status|stop|restart
164
+ ```
165
+
166
+ ## Examples
167
+
168
+ ```
169
+ $ nblean outline eda.ipynb
170
+ eda.ipynb: 97 cells (36 markdown, 61 code), kernel off
171
+ 0 md 1. Files and Schema +14L
172
+ 1 code import itertools +27L
173
+ 3 code files = pl.DataFrame( +5L → 13L
174
+ 13 code p0 = pl.read_parquet(PARQ / "part.0.parquet") +7L → 1L img
175
+ 15 code fl_min = feat["flight_length"].to_numpy() / 60 +19L → img
176
+ ```
177
+
178
+ A 40-line pandas traceback, cut down to the line that failed:
179
+
180
+ ```
181
+ $ nblean errors buggy.ipynb
182
+ ── 8 code id=cell08 exec=3 ──
183
+ KeyError Traceback (most recent call last)
184
+ Cell In[3], line 1
185
+ ----> 1 df["pressure_kpa"] = df["presure"] * 6.89476
186
+ 2 df.head()
187
+
188
+ … 11 library or chained frames omitted …
189
+ KeyError: 'presure'
190
+ ```
191
+
192
+ A 300-line training log, with a plot that is saved to a file instead of loaded:
193
+
194
+ ```
195
+ $ nblean run buggy.ipynb 3 4 --lines 6
196
+ ── 3 code id=cell03 exec=4 ──
197
+ epoch 000 smoothing pass loss=1.000000 temp_mean=141.845
198
+ epoch 001 smoothing pass loss=0.500000 temp_mean=141.724
199
+ epoch 002 smoothing pass loss=0.333333 temp_mean=141.651
200
+ … 294 lines omitted …
201
+ epoch 297 smoothing pass loss=0.003356 temp_mean=139.027
202
+ epoch 298 smoothing pass loss=0.003344 temp_mean=139.038
203
+ epoch 299 smoothing pass loss=0.003333 temp_mean=139.048
204
+ ── 4 code id=cell04 exec=5 ──
205
+ [image/png → /tmp/nblean/buggy-ec4a859a6390/img/4_0.png]
206
+ ```
207
+
208
+ ## Supported Agents
209
+
210
+ The skill uses the [Agent Skills](https://agentskills.io) `SKILL.md` format, so the
211
+ same file works in every agent below. The CLI works with any agent that can run shell
212
+ commands.
213
+
214
+ | Agent | `nblean init` | Skill location |
215
+ |---|---|---|
216
+ | Claude Code | `--agent claude`, or the plugin below | `~/.claude/skills/nblean` |
217
+ | Codex | `--agent codex` | `~/.agents/skills/nblean` |
218
+ | OpenCode | `--agent opencode` | `~/.agents/skills/nblean` |
219
+ | Gemini CLI | `--agent gemini` | `~/.gemini/skills/nblean` |
220
+ | Others | `npx skills add kaanrkaraman/nblean` | per agent |
221
+
222
+ In Claude Code the skill is also available as a plugin:
223
+
224
+ ```
225
+ /plugin marketplace add kaanrkaraman/nblean
226
+ /plugin install nblean@nblean
227
+ ```
228
+
229
+ nblean ships as a CLI and a skill instead of an MCP server. An MCP server's tool
230
+ definitions are loaded into every session. A skill is loaded only when a notebook
231
+ comes up.
232
+
233
+ ## Platform Support
234
+
235
+ macOS, Linux, and Windows, on Python 3.13+. The kernel's Python can be any version
236
+ that `ipykernel` supports.
237
+
238
+ ## Limitations
239
+
240
+ - A cell's outputs are written when the cell finishes. If a long cell is killed, its output is lost.
241
+ - Writes are atomic but not merged. If the notebook is open in Jupyter or VS Code, reload it there after nblean writes.
242
+ - Widgets, `update_display_data`, and `input()` are not supported.
243
+
244
+ ## Contributing
245
+
246
+ ```bash
247
+ uv sync
248
+ uv run pytest
249
+ uv run ruff check . && uv run mypy
250
+ ```
251
+
252
+ ## License
253
+
254
+ [MIT](LICENSE)
@@ -0,0 +1,114 @@
1
+ [project]
2
+ name = "nblean"
3
+ version = "0.1.0"
4
+ description = "Token-lean Jupyter notebook access for coding agents: outlines, clipped outputs, lazy images, a persistent kernel."
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ requires-python = ">=3.13"
9
+ keywords = [
10
+ "jupyter",
11
+ "notebook",
12
+ "ipynb",
13
+ "llm",
14
+ "coding-agent",
15
+ "claude-code",
16
+ "tokens",
17
+ "cli",
18
+ ]
19
+ classifiers = [
20
+ "Development Status :: 4 - Beta",
21
+ "Environment :: Console",
22
+ "Framework :: Jupyter",
23
+ "Intended Audience :: Developers",
24
+ "Intended Audience :: Science/Research",
25
+ "Operating System :: MacOS",
26
+ "Operating System :: POSIX :: Linux",
27
+ "Programming Language :: Python :: 3 :: Only",
28
+ "Programming Language :: Python :: 3.13",
29
+ "Programming Language :: Python :: 3.14",
30
+ "Topic :: Scientific/Engineering",
31
+ "Topic :: Software Development",
32
+ "Typing :: Typed",
33
+ ]
34
+ dependencies = ["jupyter-client>=8.10.0"]
35
+
36
+ [[project.authors]]
37
+ name = "Recep Kaan Karaman"
38
+ email = "kaanrkaraman@gmail.com"
39
+
40
+ [project.urls]
41
+ Homepage = "https://github.com/kaanrkaraman/nblean"
42
+ Repository = "https://github.com/kaanrkaraman/nblean"
43
+ Issues = "https://github.com/kaanrkaraman/nblean/issues"
44
+
45
+ [project.scripts]
46
+ nblean = "nblean:main"
47
+
48
+ [build-system]
49
+ requires = ["uv_build>=0.12.19,<0.13.0"]
50
+ build-backend = "uv_build"
51
+
52
+ [dependency-groups]
53
+ dev = [
54
+ "ipykernel>=7.4.0",
55
+ "mypy>=2.4.0",
56
+ "pytest>=9.1.1",
57
+ "ruff>=0.16.10",
58
+ ]
59
+
60
+ [tool.ruff]
61
+ line-length = 100
62
+ target-version = "py313"
63
+ src = [
64
+ "src",
65
+ "tests",
66
+ ]
67
+
68
+ [tool.ruff.lint]
69
+ select = ["ALL"]
70
+ ignore = [
71
+ "D",
72
+ "CPY",
73
+ "FIX",
74
+ "TD",
75
+ "COM812",
76
+ ]
77
+
78
+ [tool.ruff.lint.per-file-ignores]
79
+ "src/nblean/cli.py" = ["T201"]
80
+ "src/nblean/kernel.py" = ["S603"]
81
+ "src/nblean/process.py" = [
82
+ "S603",
83
+ "S607",
84
+ "FBT003",
85
+ ]
86
+ "src/nblean/render.py" = ["RUF001"]
87
+ "tests/**" = [
88
+ "S101",
89
+ "PLR2004",
90
+ "INP001",
91
+ ]
92
+
93
+ [tool.mypy]
94
+ python_version = "3.13"
95
+ files = [
96
+ "src",
97
+ "tests",
98
+ ]
99
+ strict = true
100
+ warn_unreachable = true
101
+ enable_error_code = [
102
+ "redundant-expr",
103
+ "possibly-undefined",
104
+ "ignore-without-code",
105
+ ]
106
+
107
+ [[tool.mypy.overrides]]
108
+ module = ["jupyter_client.*"]
109
+ ignore_missing_imports = true
110
+
111
+ [tool.pytest.ini_options]
112
+ testpaths = ["tests"]
113
+ addopts = "-q --strict-markers --strict-config"
114
+ xfail_strict = true