Metadata-Version: 2.4
Name: recontext
Version: 0.1.0
Summary: Silently log notebook cell executions and restore your debugging thread after an interruption gap.
Author: Sean Gong
License-Expression: MIT
Project-URL: Homepage, https://github.com/PlathsOven/human-context-window
Project-URL: Repository, https://github.com/PlathsOven/human-context-window
Project-URL: Issues, https://github.com/PlathsOven/human-context-window/issues
Keywords: ipython,jupyter,notebook,debugging,trader
Classifier: Framework :: IPython
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Debuggers
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: ipython>=8
Provides-Extra: dev
Requires-Dist: ruff; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: pytest; extra == "dev"
Requires-Dist: mypy; extra == "dev"
Dynamic: license-file

# 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

```bash
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:

```python
%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

```python
%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`:

```python
c.InteractiveShellApp.extensions = ["recontext"]
```

**Startup-file alternative** — drop `~/.ipython/profile_default/startup/00-recontext.py`:

```python
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.log` first.

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:

```bash
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

```bash
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.
