Silently log notebook cell executions and restore your debugging thread after an interruption gap.
Project description
recontext
Silently log every notebook cell you run, and — when you come back after stepping away — get a "here's where you were" banner before your next cell runs. No more reconstructing the debugging thread by hand after a 10-minute interruption.
recontext is pure IPython kernel hooks: no IDE extension, no frontend. It
works identically in VSCode Jupyter, JupyterLab, and terminal
IPython. The only runtime dependency is ipython>=8; everything else is the
standard library. Zero network calls by default — all data stays on your
machine.
─ recontext ───────────────────────────────────────────────────────────────────────────────────────────────
⏸ away 14m (last activity 11:42:25)
GOAL: tracing weird nav_adj in pnl_attribution
AGO SNIPPET OUTPUT VARS TOOK
14m fig = px.line(mu_df, x='ts', y='mu') fig → Figure fig 210ms
15m mu_df, sig_df, _resid = fit_nb2(pnl, marks_df) mu_df, sig_df 6.2s
16m marks = mkt.get_marks(syms) ✗ KeyError: 'RELIANCE' marks 95ms
17m pnl[pnl.nav_adj.abs() > 1e6] pnl[…] → DataFrame (3, 12) 140ms
18m pnl = attr.load('2026-06-08') pnl 3.1s
(1 _var hidden · %recontext_config hide_underscore=off to show)
%wtf for more · %wtf --full for full sources
─────────────────────────────────────────────────────────────────────────────────────────────────────────
Each row is one executed cell — one activity line, most recent at the top,
since that's where your eye lands when you come back. Read it left to right:
how long ago, what you ran, what came out, what it bound, how long it took.
Errors are the red ✗ rows; OUTPUT names the displayed expression (pnl[…] → DataFrame (3, 12)), and DataFrames and plots collapse to one-line summaries
like DataFrame (84211, 12) / Figure. VARS shows every variable the
cell bound (wrapping onto extra lines when needed — nothing is summarized
away); throwaway _-prefixed names (_, _resid, …) are kept out by default
— when that happens the banner says so in a one-line note, and
%recontext_config hide_underscore=off brings them back. In a color terminal
each variable name gets its own stable color everywhere it appears, so you can
trace one variable across the trail at a glance — timings render dim so the
code stays the brightest thing on screen (NO_COLOR turns color off).
60-second quickstart
python -m build # -> dist/recontext-*.whl (needs: pip install build)
pip install dist/recontext-*.whl # install into the SAME env your kernel uses
Then, in any notebook or IPython session:
%load_ext recontext
which answers with the whole tutorial:
recontext: on — logging every cell you run, locally. Nothing leaves this machine.
Pulled away mid-trace? When you come back after 4m+, your next cell
opens with where you were — goal, recent cells, outputs, errors — so you
pick the trace back up instead of re-tracing it from the beginning.
%wtf where you were, on demand — live in Jupyter
%goal <what you're chasing> leave the breadcrumb — every banner leads with it
%recontext_config knobs (gap, banner, live, …)
That's it. From here recontext logs silently in the background: you won't see anything else until you step away longer than the gap threshold (default 4 min) and run your next cell — then the resume banner appears above that cell's output.
Drive it on demand
%wtf # banner with the last 8 events (alias: %recontext)
%wtf -n 20 # last 20 events
%wtf --full # untruncated sources + results
%wtf --last # the trail from your PREVIOUS session (after a kernel restart)
%wtf --stats # per-day usage counters, last 7 days
%wtf --ai # optional 2–3 sentence LLM summary (opt-in, see below)
%goal tracing weird nav_adj in pnl_attribution # leave yourself a breadcrumb
%goal # print the current goal
%goal --clear # clear it
%recontext_config # print the current config
%recontext_config gap_seconds=300 # widen the gap to 5 min (session-scoped)
%recontext_config banner=off # silence the auto-banner (magics still work)
%recontext_config hide_underscore=off # show _-prefixed names in VARS again
%recontext_config live=off # freeze %wtf into plain static prints
In Jupyter frontends the %wtf table is live: run it once and it keeps
itself current, repainting in place as each cell finishes and whenever the
goal changes (the newest %wtf is the one that stays live). In terminal
IPython — or with live=off — it's the same table as a static print.
The goal is shown at the top of every banner — so when you return you're reminded what you were chasing, not just what you ran.
Permanent autoload
To skip %load_ext in every session, add recontext to your IPython config.
Edit (or create) ~/.ipython/profile_default/ipython_config.py:
c.InteractiveShellApp.extensions = ["recontext"]
Startup-file alternative — drop ~/.ipython/profile_default/startup/00-recontext.py:
get_ipython().run_line_magic("load_ext", "recontext")
Reload after re-installing with %reload_ext recontext; remove cleanly with
%unload_ext recontext.
Configuration
Session config (set with %recontext_config k=v, reset on kernel restart):
| knob | default | what it does |
|---|---|---|
gap_seconds |
240 |
seconds away before the resume banner fires |
trail_len |
8 |
how many events %wtf shows by default |
banner |
on |
off silences the auto-banner (magics still work) |
hide_underscore |
on |
hide _-prefixed names from VARS (a note says when it did); off shows them |
live |
on |
%wtf repaints in place as you work (Jupyter frontends); off = static prints, and disarms the current live view |
Environment overrides, read at load time — precedence is env → %recontext_config → default:
| env var | overrides | example |
|---|---|---|
RECONTEXT_GAP_SECONDS |
gap_seconds |
export RECONTEXT_GAP_SECONDS=300 |
RECONTEXT_DIR |
data directory | export RECONTEXT_DIR=~/work/.recontext |
RECONTEXT_BANNER |
banner (0/off to silence) |
export RECONTEXT_BANNER=0 |
RECONTEXT_HIDE_UNDERSCORE |
hide_underscore (0/off to show _ names) |
export RECONTEXT_HIDE_UNDERSCORE=0 |
RECONTEXT_LIVE |
live (0/off for static prints) |
export RECONTEXT_LIVE=0 |
RECONTEXT_MODEL |
model used by %wtf --ai |
export RECONTEXT_MODEL=claude-sonnet-4-6 |
ANSI color is on by default (notebooks render it even though they aren't a TTY)
and is suppressed entirely when NO_COLOR is set.
All data stays on your machine
recontext makes zero network calls by default. Everything it writes lives
under ~/.recontext/ (override with RECONTEXT_DIR), and every file is created
at mode 0600 (owner read/write only):
| path | what |
|---|---|
sessions/YYYY-MM-DD_<id>.jsonl |
one file per kernel session — the event + goal trail, created lazily on your first cell |
stats.json |
local per-day usage counters (events, resumes_shown, wtf_calls, goals_set) |
errors.log |
the silent-failure sink: if a hook ever hits an internal error it logs here and stays quiet, never raising into your cell |
If a banner or magic "does nothing", read
~/.recontext/errors.logfirst.
There is no telemetry, no analytics, and no auto-update.
The one optional network feature: %wtf --ai
%wtf --ai is the only feature that touches the network, and only when you
explicitly invoke it and have ANTHROPIC_API_KEY set:
export ANTHROPIC_API_KEY=sk-ant-...
It POSTs your recent cell sources (truncated) to the Anthropic Messages API over
stdlib urllib with a 10 s timeout and prints a 2–3 sentence summary. The first
time you use it per session it warns you that cell sources leave your machine —
check your compliance policy. If the key is missing it just tells you how to set
it; any failure degrades to one line, never a traceback.
Develop
python -m pytest # full suite (test_core, test_render, test_store)
ruff check src/ tests/ # lint
ruff format src/ tests/ # format
mypy src/recontext # optional type-check, kept green
The per-cell overhead budget (< 5 ms mean over 1000 cells) is asserted
inside tests/test_core.py, so python -m pytest is all you run to check it.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file recontext-0.1.0.tar.gz.
File metadata
- Download URL: recontext-0.1.0.tar.gz
- Upload date:
- Size: 35.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1cc78ca181739bc9a19c79bd05d31ca96d77a94b3eb9dc3c8c008663b6042ebe
|
|
| MD5 |
063aab08d54f233882764ef125d64063
|
|
| BLAKE2b-256 |
718286d6dd058915ffe76e831b62f3429c8dbf485a96fcaad97ce4f21e4dedad
|
File details
Details for the file recontext-0.1.0-py3-none-any.whl.
File metadata
- Download URL: recontext-0.1.0-py3-none-any.whl
- Upload date:
- Size: 23.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1f3c09a4d7b1e2cfa21c4a70e7047f6f24c3bec15ed2b61b74036fcc3bb7753b
|
|
| MD5 |
63b29372e5999ffa13f2d49677d7a49b
|
|
| BLAKE2b-256 |
8e5b7d9de14d17aa1f1e996ac250a7ae56f663367663b6e7cb94bdfaa073b809
|