{"id":"b16889ab-33e0-4009-a4a1-720bcff7a813","slug":"session-watcher","kind":"mcp","name":"session-watcher","summary":"Context is inventory. Know when to restock.","owner":"nomadop","repoUrl":"https://github.com/nomadop/session-watcher","license":"MIT","licenseTier":"permissive","trust":"community","stars":5,"match":null,"fewStars":false,"format":"mcp","createdAt":"2026-07-06T10:55:08.000Z","addedAt":"2026-10-21T04:46:53.476Z","logoUrl":"https://avatars.githubusercontent.com/u/4026632?u=68347dbcaa253a656037d8fa34cf484dc31708bd&v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["memory-knowledge","cloud-infra","developer-tools"],"tags":["coding-agents","cost-optimization","dashboard","developer-tools","eoq","nodejs","session-monitoring","statusline"],"runtime":"node","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-25T21:35:09.804Z","sample":false,"url":"https://conduits.dev/tools/session-watcher","language":"JavaScript","transports":["stdio"],"install":{"npm":"@nomadop/session-watcher"},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"<div align=\"center\">\n\n# Session Watcher\n\n**LLM context economics, in your terminal.**\n\nSession Watcher treats your prompt cache as *inventory* — it uses EOQ theory to measure whether the current context is still *worth carrying*, tracking restart pressure so you can decide when to hand off.\n\n<img src=\"assets/dashboard.gif\" alt=\"Session Watcher dashboard\" width=\"820\">\n\n</div>\n\n<p align=\"center\">\n  <a href=\"https://doi.org/10.5281/zenodo.21236704\"><img src=\"https://zenodo.org/badge/DOI/10.5281/zenodo.21236704.svg\" alt=\"DOI\"></a>\n  <a href=\"LICENSE\"><img src=\"https://img.shields.io/badge/License-MIT-yellow.svg\" alt=\"License: MIT\"></a>\n  <a href=\"#install\"><img src=\"https://img.shields.io/badge/platform-node.js%20%E2%89%A522.16-green.svg\" alt=\"Platform: Node.js ≥22.16\"></a>\n</p>\n\n<p align=\"center\">\n  <a href=\"https://nomadop.github.io/session-watcher/docs/\"><strong>Documentation</strong></a> ·\n  <a href=\"https://www.npmjs.com/package/@nomadop/session-watcher\">npm</a> ·\n  <a href=\"https://doi.org/10.5281/zenodo.21236704\">Paper</a> ·\n  <a href=\"llms.txt\">llms.txt</a>\n</p>\n\n<p align=\"center\">\n  <a href=\"#quick-start\">Quick Start</a> ·\n  <a href=\"#install\">Install</a> ·\n  <a href=\"#dsh-plugin\">DSH</a> ·\n  <a href=\"#how-it-works\">How It Works</a> ·\n  <a href=\"#context-buckets\">Context Buckets</a> ·\n  <a href=\"#handoff\">Handoff</a> ·\n  <a href=\"#mcp-tools\">MCP Tools</a> ·\n  <a href=\"#agent-support\">Agents</a> ·\n  <a href=\"#citation\">Cite</a>\n</p>\n\n---\n\n## What it does\n\nSession Watcher reads your Claude Code transcript in real time and answers one question: **is this session still worth carrying?**\n\nMost context tools optimize *how* you consume tokens — Headroom compresses, `/compact` shrinks, RTK filters. Session Watcher tracks *when* the cost curve is drifting, giving you the data to decide. They compose: run any pruning strategy you like, SW measures the cost curve so you can decide when to hand off.\n\nSW reads from the transcript, never writes to it. The dashboard and statusline are pure observers; MCP tools return data for you to act on.\n\n## How it works\n\n```\nYour coding agent (Claude Code)\n        │  writes session transcript\n        ▼\n┌───────────────────────────────────────────────────────┐\n│  Session Watcher (in-process MCP server)              │\n│  ───────────────────────────────────────────────────  │\n│  harness/claude-code  — read rows, emit observations  │\n│  measurement/engine   — B (context belief), epochs    │\n│  session-watcher      — apply frames, run operations  │\n│  rate-lamp            — rent ledger + wallet clock    │\n│  server.js            — Express + SSE dashboard       │\n│  statusline           — one-line shell client         │\n└───────────────────────────────────────────────────────┘\n        │  dashboard  ·  statusline  ·  MCP\n        ▼\n   Your browser / terminal status bar\n```\n\nThe harness layer is the only part that knows Claude Code: it reads transcript rows, decides the active branch, and emits normalized observations. Everything below it — measurement, dialogue history, handoff — consumes those observations and carries no transcript format, no row shape, and no tool name of any particular agent.\n\n**Core model:** `L = cache_read_input_tokens` — the context stock you are renting. `B` is the rebuild baseline: the session's overhead floor plus the tokens of every file, skill and tool it has pulled in, which is what a restart would have to re-read. `g` is the growth no path accounts for, a smoothed `ΔtotalStock − ΔB`. `x = L / B` is the raw position ratio; the authoritative position is `u`, which every call advances by its own fraction of the restart interval that held while it ran, so the position records the path travelled rather than a ratio of today's numbers, and each landmark on the x axis is read off the reference skeleton fitted across that path. `br = mf × pp` is the bill premium — how much you are overpaying relative to ideal restart timing. The restart reminder is separate: it reads the rent the ledger has accumulated, so no revision of the position can withdraw one.\n\nLamp thresholds are the named constants `BR_AMBER` and `BR_RED` in `lib/bill-regret.js`: below the amber one the lamp is green, between them amber, at or above the red one red. See the [paper](#paper) for the full derivation — EOQ inventory theory mapped to LLM prompt caching.\n\n## Quick Start\n\nRequires Node.js ≥ 22.16.\n\n```bash\n# Try without installing — self-contained demo\nnpx -y @nomadop/session-watcher demo\n\n# Replay your own transcript\nnpx -y @nomadop/session-watcher replay ~/.claude/projects/<project>/<session>.jsonl\n```\n\nOpens a browser dashboard. The demo uses a pre-built anonymized session; replay uses your real transcript. Both are read-only — nothing is modified or uploaded.\n\n## Install\n\n### Plugin (recommended)\n\n```bash\n# 1. Add the marketplace (one-time)\nclaude plugin marketplace add nomadop/session-watcher\n\n# 2. Install the plugin\nclaude plugin install session-watcher@session-watcher\n```\n\nOr from within a Claude Code session:\n```\n/plugin marketplace add nomadop/session-watcher\n/plugin install session-watcher@session-watcher\n/reload-plugins\n```\n\nThis registers:\n- **MCP tools** — available in every session\n- **SessionStart hook** — points the running watcher at a new session and announces pending handoffs\n\nIf you installed or updated in an already-running session, run `/reload-plugins` to activate.\n\n## DSH plugin\n\n`@nomadop/session-watcher-dsh` runs Session Watcher inside DeepSeek Harness (DSH). It watches every running session of the host it loads into and shares `~/.session-watcher` with the Claude Code plugin.\n\n```bash\ndsh plugin --profile <name> add @nomadop/session-watcher-dsh\n```\n\n- **The Session Watcher tab** — a view in the conversation view strip that mounts the dashboard's elements for that session.\n- **The composer dock** — a pill below the composer showing the lamp, the bill premium and the alert clock, with the position and the context stock in its popover.\n- **Tools** — the [MCP tools](#mcp-tools), each answering for the calling agent's own session, except that `watcher_status` can name another.\n- **Skills** — `sw-handoff`, `sw-load` and `sw-explain`, registered with the host.\n- **Handoff across sessions** — an agent that starts or resumes gets a message listing the pending handoffs other sessions prepared for its project.\n- **Replay** — `npx -y @nomadop/session-watcher replay <path>` plays a DSH session log back on the dashboard.\n\nSee the [DSH plugin docs](https://nomadop.github.io/session-watcher/docs/dsh/) for the profile to add it to, what the tab and the dock show, the surface they are supported on, and handoffs that cross between the two hosts.\n\n## Statusline\n\nThe plugin system does not yet support declaring a statusline. Add to your `~/.claude/settings.json`:\n\n```json\n{\n  \"statusLine\": {\n    \"type\": \"command\",\n    \"command\": \"<plugin-install-path>/dist/statusline.js\"\n  }\n}\n```\n\nFind your plugin path with:\n```bash\nfind ~/.claude/plugins/cache -path '*/session-watcher/*/dist/statusline.js' -print\n```\n\nOr check via `claude plugin details session-watcher@session-watcher`.\n\n**Note:** the plugin cache path changes on version update. After updating, re-run the command above and update your statusline path.\n\nOne compact line:\n\n<img src=\"assets/statusline.png\" alt=\"Statusline example\" width=\"820\">\n\n## Context Buckets\n\nThe bucket panel shows exactly which files, skills, and tools are consuming your context budget. Each path carries a token count — check or uncheck to preview how the restart cost changes. The U-curve ghost line updates in real time as you toggle.\n\n<img src=\"assets/preview_u.gif\" alt=\"Context bucket selection preview\" width=\"820\">\n\n## Handoff\n\nWhen it's time to restart, handoff preserves the state you want to keep. Run `/sw-handoff` to prepare a package — selected paths, working summary, next task. Then `/clear`, and in the fresh session run `/sw-load` to restore. Only what you chose is rebuilt — less ramp-up, less waste.\n\n<img src=\"assets/handoff.gif\" alt=\"Handoff workflow\" width=\"820\">\n\n## MCP Tools\n\nBoth plugins register the same tools, except for `rotate_session`, which only Claude Code registers. The [Guarantees page](https://nomadop.github.io/session-watcher/docs/guarantees/#mcp-tools) tables them once, with where the two hosts differ.\n\n## Agent support\n\nSession Watcher is agent-agnostic. Everything below the harness layer consumes normalized observations, so it never learns which agent produced the session.\n\n| Agent | Driver | Status |\n|-------|--------|--------|\n| Claude Code | JSONL tail (native) | ✅ |\n| DSH (DeepSeek Harness) | session event log (native) | harness ✅ · plugin ✅ |\n| OpenCode | adapter-ready | pending |\n| OpenClaw | adapter-ready | pending |\n| Hermes | adapter-ready | pending |\n| Aider | adapter-ready | pending |\n\nAdding a new agent means writing a harness for it under `lib/harness/<agent>/`: a source driver that turns that agent's own session evidence into normalized observations, a thin measurement projection adapter over the shared [`lib/measurement-projection.js`](lib/measurement-projection.js), a tool-evidence profile that names the agent's residual calls, its handoff-loading tool and any resource that is not a file (the interpreter that matches tool output against the files on disk is shared), the dialogue source and history turn rules that read its conversation, and the recovery sentences that tell a reader how to open a turn it cites. The engine, dialogue history, handoff, and every product surface are shared and need no change. See [`lib/harness/claude-code/`](lib/harness/claude-code/) for the reference harness and [`lib/harness/dsh/`](lib/harness/dsh/) for a second one. PRs welcome.\n\n## Paper\n\n> **Context Is Inventory: A Rent-or-Buy Model for Prompt-Cached LLM Sessions**\n> Longju Cheng (2026) · DOI: [`10.5281/zenodo.21236704`](https://doi.org/10.5281/zenodo.21236704)\n\nThe 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. Read it at the [DOI](https://doi.org/10.5281/zenodo.21236704) above.\n\n## Uninstall\n\n```bash\nclaude plugin uninstall session-watcher@session-watcher\n# Remove state directory (optional):\nrm -rf ~/.session-watcher\n```\n\n## Test\n\n```bash\nnpm test              # unit + integration (node:test)\nnpx playwright test   # E2E (requires running server)\n```\n\n## Citation\n\n```bibtex\n@unpublished{cheng2026context,\n  author = {Longju Cheng},\n  title  = {Context Is Inventory: A Rent-or-Buy Model for Prompt-Cached LLM Sessions},\n  year   = 2026,\n  doi    = {10.5281/zenodo.21236704},\n  url    = {https://doi.org/10.5281/zenodo.21236704},\n  note   = {Preprint}\n}\n```\n\n## Privacy\n\n- No remote telemetry.\n- Transcripts are read locally and never uploaded.\n- Files a transcript names are read locally to attribute tool output to their lines; their content stays in memory and is never uploaded.\n- Local aggregate usage and handoff records are stored under `~/.session-watcher`.\n- No transcript prose or file contents are stored in telemetry.\n- Each tool call's file attribution is stored with its session as paths, line numbers, character counts and a hash of each line, plus the name of the tool or command that made the call (for a shell command, also its main argument) — no file contents.\n- Removing `~/.session-watcher` deletes all local state, except the Turn Notes a DSH session prepared and has not yet submitted successfully, which sit under the system temp directory.\n\n## License\n\nMIT\n"}