LLM context economics, in your terminal.
Session Watcher treats your prompt cache as inventory — it uses EOQ theory to tell you whether the current context is still worth carrying, and when to restart. Works with any session-based coding agent.
Install · Quick Start · How It Works · MCP Tools · Agents · Paper · Cite
Session Watcher monitors your agent's session transcript in real time and answers one question: should I restart this session?
- Real-time dashboard — Chart.js SPA with SSE streaming: token stock
L, exit lineL*, per-turn cost, bill progress, rate-lamp interrupt meter - Statusline widget — one-line shell command for your terminal status bar: lamp · progress bar · turn counter · cost rate ·
L/b· model - Zero context pollution — the MCP tools return only a URL. No metric number, no transcript content, no session state ever re-enters the model's context
- Fully local — all state lives in a sidecar JSON file; no cloud, no telemetry, no API calls
Your coding agent (Claude Code, OpenCode, OpenClaw, etc.)
│ writes session transcripts
▼
┌──────────────────────────────────────────┐
│ Session Watcher (local sidecar daemon) │
│ ─────────────────────────────────────── │
│ fold.js — tail JSONL, fold usage │
│ baseline.js — detect cold-start L_base │
│ metrics.js — compute L* (EOQ-optimal) │
│ rate-lamp.js — interrupt meter (burn) │
│ server.js — Express + SSE dashboard │
│ statusline.js — one-line shell client │
└──────────────────────────────────────────┘
│ dashboard :31393 · statusline · MCP
▼
Your browser / terminal status bar
Core model: L = cache_read_input_tokens (your context stock, rent-free while cached). When L crosses the EOQ-optimal restart line L*, the dashboard and statusline signal restart. See the paper for the full derivation — EOQ inventory theory mapped to LLM prompt caching.
# 1. Add the marketplace (one-time)
claude plugin marketplace add nomadop/session-watcher
# 2. Install the plugin
claude plugin install session-watcher@session-watcherOr from within a Claude Code session:
/plugin marketplace add nomadop/session-watcher
/plugin install session-watcher@session-watcher
/reload-plugins
This registers:
- MCP tools (
start_watcher,stop_watcher,watcher_status) — available in every session - SessionStart hook — auto-launches the dashboard server on each session
- Stop hook — evaluates the restart gate on each stop boundary
If you installed or updated in an already-running session, run /reload-plugins to activate.
{
"mcpServers": {
"session-watcher": { "command": "node", "args": ["/path/to/index.js"] }
}
}Add to your project's .mcp.json or ~/.claude/settings.json. Then call start_watcher — it launches the dashboard and returns its URL.
{
"hooks": { "SessionStart": [{ "command": "<path>/hooks/session-start.js" }] }
}Add to ~/.claude/settings.json. The watcher starts automatically, fire-and-forget.
The plugin system does not yet support declaring a statusline. Add to your ~/.claude/settings.json:
{
"statusLine": {
"type": "command",
"command": "<plugin-install-path>/dist/statusline.js"
}
}Find your plugin path with:
find ~/.claude/plugins/cache -path '*/session-watcher/*/dist/statusline.js' -printOr check via claude plugin details session-watcher@session-watcher.
Note: the plugin cache path changes on version update. After updating, re-run the command above and update your statusline path.
One compact line:
git clone https://github.com/nomadop/session-watcher.git
cd session-watcher
npm install
node server.js --project ~/.claude/projects/<project> --openAdditional flags: --ratio <N> (override C_RATIO), --port <N> (fixed port), --lbase <N> (override baseline — only when transcript has no cold start).
Then open http://localhost:31393 in your browser. The dashboard updates in real time as your agent runs.
| Tool | Description |
|---|---|
start_watcher |
Start (or reuse) the dashboard server; returns its URL |
stop_watcher |
Stop the managed server |
watcher_status |
Report whether the server is running and its URL |
All three are read-only — they never return metric values or session content into the model's context.
Session Watcher is agent-agnostic. The measurement pipeline (fold, baseline, L*, rate-lamp) only needs cache_read_input_tokens from each turn — it doesn't care which agent produced the transcript.
| Agent | Driver | Status |
|---|---|---|
| Claude Code | JSONL tail (native) | ✅ |
| OpenCode | adapter-ready | pending |
| OpenClaw | adapter-ready | pending |
| Hermes | adapter-ready | pending |
| Aider | adapter-ready | pending |
Adding a new agent requires implementing one interface: extract cache_read_input_tokens from the agent's session transcript. See lib/extract.js for the Claude Code reference driver. PRs welcome.
Context Is Inventory: A Rent-or-Buy Model for Prompt-Cached LLM Sessions Longju Cheng (2026) · DOI:
10.5281/zenodo.21236704
The paper derives the full theoretical specification: EOQ→LLM mapping, the 41.4% movable-cost bound, the ski-rental restart strategy, and measurements on 1,016 real session transcripts. See paper/paper.pdf.
The current release implements the full paper specification: the measurement pipeline (fold, baseline, L*, φ), the billing gauge (billProgress), the rate-lamp interrupt meter with wall-position scaling, model-tier-specific pricing ratios, deep-water latching, and the restart recommendation signal via dashboard and statusline.
claude plugin uninstall session-watcher@session-watcher
# Remove state directory (optional):
rm -rf ~/.session-watchernpm test # unit + integration (node:test)
npx playwright test # E2E (requires running server)@unpublished{cheng2026context,
author = {Longju Cheng},
title = {Context Is Inventory: A Rent-or-Buy Model for Prompt-Cached LLM Sessions},
year = 2026,
doi = {10.5281/zenodo.21236704},
url = {https://doi.org/10.5281/zenodo.21236704},
note = {Preprint}
}MIT
