jupyagent is an agent-first CLI for inspecting and editing Jupyter notebooks without working directly with raw .ipynb JSON.
This MVP focuses on notebook file management and stateless full-notebook execution:
- list cells
- read cell source
- read saved outputs
- insert, replace, delete, and move cells
- patch one or more cell sources with unified diffs
- execute a notebook from top to bottom
It does not provide interactive or persistent kernel management.
Notebook JSON is noisy for both humans and coding agents. jupyagent exposes common notebook operations as small CLI commands with readable Markdown output and safe in-place mutations.
Clone this repository, activate your virtual environment, and install this project directly.
pip install -e .
This workspace is configured with uv.
uv sync --devRun the CLI with:
source .venv/bin/activate
jupyagent --helpUse jupyagent when you need to inspect or modify notebook structure without editing .ipynb JSON directly.
Good uses:
- inspect notebook structure before making changes
- read one or more cells as Markdown or fenced code
- read saved outputs, including extracted images
- insert or replace cells from stdin or a file
- reorder cells safely
Recommended workflow for agents:
- Start with
jupyagent cell list <notebook>. - Read specific cells with
jupyagent cell read <notebook> <selector>. - Read saved outputs with
jupyagent output read <notebook> <selector>when needed. - Apply structural edits with
cell insert,cell replace,cell delete, orcell move. - Use
cell pathandcell patchfor source-level edits across multiple cells. - Run
jupyagent exec <notebook>when you need fresh outputs. - Re-run
cell list,cell read, oroutput readto verify the result.
Notes:
- Read-only commands do not rewrite notebooks.
- Mutating commands repair missing or duplicate cell IDs before writing.
output readmay create files under.jupyagent/assets/for extracted images.- Replacing or patching a code cell clears saved outputs and execution count.
jupyagent cell list <notebook>
jupyagent cell read <notebook> <selector> [--output]
jupyagent cell path <notebook> <selector>
jupyagent cell insert <notebook> <position> --type code|markdown|raw [--file <path>]
jupyagent cell replace <notebook> <selector> --type code|markdown|raw [--file <path>] [--keep-outputs]
jupyagent cell delete <notebook> <selector>
jupyagent cell move <notebook> <selector> <position>
jupyagent cell patch <notebook> [--file <path>]
jupyagent output read <notebook> <selector>
jupyagent exec <notebook> [--timeout <seconds>] [--output <path>]Supported selector forms:
<cell-id> Cell ID, such as abc123
<index> One-based cell index, such as 4
<start>:<end> Inclusive one-based cell index range, such as 2:6
all All cells
Resolution rules:
- If a selector matches an existing cell ID, it is treated as a cell ID.
- Numeric selectors are treated as one-based indexes.
- Range selectors are inclusive.
- Some commands require the selector to resolve to exactly one cell.
Examples:
jupyagent cell read analysis.ipynb abc123
jupyagent cell read analysis.ipynb 4
jupyagent cell read analysis.ipynb 2:6
jupyagent cell read analysis.ipynb 2 --output
jupyagent output read analysis.ipynb allSupported position forms:
start
end
before:<selector>
after:<selector>
Examples:
jupyagent cell insert analysis.ipynb start --type markdown
jupyagent cell insert analysis.ipynb after:abc123 --type code < transform.py
jupyagent cell move analysis.ipynb 3:5 endcell patch targets canonical virtual cell source paths.
Always get these paths from jupyagent cell path <notebook> <selector> instead of constructing them by hand.
Format:
<notebook-name>.ipynb/cells/<index-padded>__<cell-id>.source.<ext>
Examples:
analysis.ipynb/cells/0001__intro.source.md
analysis.ipynb/cells/0002__prep.source.code
analysis.ipynb/cells/0003__notes.source.raw
Rules:
- Paths are canonical.
cell patchmatches these exact paths. - Paths are generated after in-memory cell ID repair, so duplicate or missing notebook IDs may appear with repaired IDs.
cell pathdoes not rewrite the notebook file.cell patchonly edits cell source content. It does not create, delete, move, or patch outputs or metadata.- Extensions map to cell types:
code -> .code,markdown -> .md,raw -> .raw.
List cells:
jupyagent cell list analysis.ipynbRead a code cell:
jupyagent cell read analysis.ipynb 2Show canonical virtual paths:
jupyagent cell path analysis.ipynb 2:3Read a code cell with saved outputs:
jupyagent cell read analysis.ipynb 2 --outputInsert a markdown cell from a file:
jupyagent cell insert analysis.ipynb end --type markdown --file notes.mdInsert a code cell from stdin:
jupyagent cell insert analysis.ipynb after:prep --type code < transform.pyInsert a code cell from a multiline heredoc:
cat <<'EOF' | jupyagent cell insert analysis.ipynb end --type code
import pandas as pd
df = pd.read_csv("data.csv")
df.head()
EOFReplace a cell and clear old outputs:
jupyagent cell replace analysis.ipynb 2 --type code < transform.pyReplace a cell from a multiline heredoc:
cat <<'EOF' | jupyagent cell replace analysis.ipynb 2 --type markdown
## Summary
- Loaded the latest dataset
- Recomputed the aggregate metrics
EOFReplace a code cell but keep saved outputs:
jupyagent cell replace analysis.ipynb abc123 --type code --keep-outputs < transform.pyDelete a range of cells:
jupyagent cell delete analysis.ipynb 3:5Move cells to the end:
jupyagent cell move analysis.ipynb 3:5 endPatch two cells at once:
--- analysis.ipynb/cells/0002__prep.source.code
+++ analysis.ipynb/cells/0002__prep.source.code
@@ -1 +1 @@
-print("old")
+print("new")
--- analysis.ipynb/cells/0004__summary.source.md
+++ analysis.ipynb/cells/0004__summary.source.md
@@ -1 +1 @@
-Old summary
+New summaryjupyagent cell patch analysis.ipynb < changes.diffRead saved outputs:
jupyagent output read analysis.ipynb 2Execute a notebook in place:
jupyagent exec analysis.ipynbExecute a notebook and write the result elsewhere:
jupyagent exec analysis.ipynb --output analysis.executed.ipynbexec performs a stateless batch execution of the full notebook using the notebook's configured kernel.
- execution always starts from the first cell
- outputs are saved back into the notebook file by default
--outputwrites the executed notebook to a new path instead of modifying the source file- failures return a non-zero exit code and report the failing cell
- partial outputs up to the failing cell are preserved in the written notebook
- this is intended for exploratory and batch workflows, not long-running interactive sessions
output read renders saved outputs as Markdown where possible.
Current MVP support:
text/markdowntext/plain- simple
text/htmltables converted to Markdown tables - complex
text/htmltables normalized into row-oriented fencedtableblocks - other
text/htmloutput converted to readable text image/pngimage/jpeg
Image outputs are extracted automatically to:
.jupyagent/assets/<notebook-stem>/<cell-id>/
The emitted Markdown uses relative asset paths.
Mutating commands:
- read the existing notebook
- apply the requested operation
- repair missing or duplicate cell IDs
- preserve notebook metadata where possible
- write to a temporary file in the same directory
- atomically replace the original notebook
Commands return non-zero exit codes on failure.
Example:
error: selector 'abc123' did not match any cell in analysis.ipynb
This is an MVP implementation.
Implemented now:
cell listcell readcell insertcell replacecell deletecell movecell pathcell patchoutput readexec
Not yet implemented:
- kernel management