session-watch
A Claude Code Mod that shows this session's state in the sidebar: context fill, token totals, cost, model and thinking level, the Claude Code version, and the git branch and status.
What it shows
A section at the top of the sidebar (order: 5), measured on Claude Code 2.1.282:
session-watch: session
context 8% · 81k / 1.0M
tokens T 81k · I 2 · O 8 · CR 74k · CW 7k
cost $0.07
model opus-5-5[1m] · thinking medium
Claude Code 2.1.282
main · 1 untracked · no upstream
context: the input tokens of the last reply over the model's context window, and their share. Green under 50%, yellow from 50% to 80%, red above 80%. The engine reports all three ($.session.usage().context); the mod computes none of them. Before the first reply the line readscontext: no reply yet.tokens: the session's totals:Tall,Iinput,Ooutput,CRcache reads,CWcache writes. A session with no totals kept reads them once from its transcripts (the main loop's and each subagent's), counting each model response once, and every turn after that adds its own, a subagent's too. A request no transcript records counts as it returns: a plugin's own model call ($.model.fork,$.model.complete, such as the fork memory-save runs at each turn's end) and a compaction's summary. Measured on 2.1.282: a fork of 16 input tokens and a completion of 14 raisedIfrom 2 to 32, and a fork fires noturn.complete, so it counts once. The totals are kept in$.storeper session, so a reloaded module goes on from them. While the transcripts are read the line readstokens: reading the transcripts. Measured on 2.1.282 in a resumed session: the totals equalled the/costrow of the session's model,6 input, 19 output, 222.3k cache read, 21.5k cache write.cost: the session's cost in US dollars, as/costtotals it.model: the main loop's model, and the thinking setting (effort) of the main loop's last model request:lowtomax, a budget,no thinking settingfor a model without one, orthinking: not read yetbefore the first request. The model's name is coloured by family, the dearest the warmest: opus red, fable yellow, sonnet green, haiku faint. The thinking level is coloured by how hard it asks:lowfaint,mediumgreen,highyellow,xhighandmaxred. Colouring one word needs sidebar 0.11.0 or later; an older sidebar draws the line in one colour.Claude Code: the engine's version.- The git line: the branch (or
detached at <sha>), the staged, modified, untracked and conflicted files, and the commits ahead of and behind the upstream (↑1 ↓0, orno upstream). Yellow while the tree has changes, green when it is clean. Outside a repository it readsgit: not a repository.
A status line in place of the section while the sidebar is closed or not installed:
session-watch: ctx 8% · $0.07 · main*
A * after the branch marks a tree with changes. The status line is cleared while the sidebar holds the section.
When it reads
- At session start.
- At the end of each main-loop turn.
- After each Bash command that names
git, so a commit, checkout or pull shows at once. - Every 10 seconds in an interactive session, so a change made outside the session (a checkout in another terminal) shows too. Measured with the earlier 30-second timer: a file staged from outside turned
1 untrackedinto1 stagedwithin one tick. - After a plugin's own model call (
$.model.fork,$.model.complete) or a compaction, so memory-save's fork at a turn's end shows at once. The redraw runs from a timer, so the call's caller does not wait for its git run. - At
/session-watch, which also prints the section's lines.
Each reading runs git status --porcelain=v2 --branch once in the directory the session started in. A reading that fails is logged once as cannot read the session: <error>.
Command
/session-watch the section's lines, read now
Install
claude plugin marketplace add KilimcininKorOglu/claude-code-mods
claude plugin install session-watch@kilimcininkoroglu-mods
Function hooks are early access. Nothing loads without the flag. To keep it on, add this to ~/.claude/settings.json:
{ "env": { "CLAUDE_CODE_ENABLE_FUNCTION_HOOKS": "1" } }
After installing
- Restart Claude Code.
- Install the sidebar mod and open it with
/sidebar. Without it the mod writes the short status line. - Install
git. Without it the git line reads the error.
What it can reach
Validated with claude plugin validate on Claude Code 2.1.282:
❯ ./register.ts hooks: session.start, turn.step, turn.complete, model.fork, model.complete, session.compact, tool.call{tool=Bash}, command.run{command=session-watch}
❯ ./register.ts calls: $.clock.after (via countCall, startTotals), $.clock.every, $.command.register, $.env.get (via configDirOf), $.fs.exists (via transcriptsOf), $.fs.list (via transcriptsOf), $.fs.stat (via transcriptsOf), $.process.run (via readGit), $.process.spawn (via readTotals), $.session.id, $.session.model (via readNow), $.session.root, $.session.usage (via readNow), $.session.version, $.sidebar.set (via show), $.store.delete (via startTotals), $.store.get (via keepTotals, startTotals), $.store.set (via keepTotals), $.ui.log (via refresh, seedTotals, startTotals), $.ui.status (via show)
Reach L2, it runs git and head.
1. Reads: the session's usage figures (context, cost), model, id, start directory and engine version; each turn's token counts, the usage of each plugin model call and compaction, and each request's thinking setting; the text of each Bash command, to see whether it names git; once per session with no totals kept, the session's transcripts under <config dir>/projects/, only their model responses' usage
2. Runs: git status --porcelain=v2 --branch in the session's start directory, at each reading; head -c <size> on each transcript, once; one 10 second timer in an interactive session
3. Sends: nothing leaves the machine
4. Persists: the token totals of the last 20 sessions in $.store
5. Hostile input: git's output is parsed by line shape and only counted; a transcript row is parsed as JSON and only its four token counts are added, a count of another type adding nothing; a stored value of another shape reads as none
Limits
- The engine's own side calls (part of the
haikurow in/cost) reach no hook and are not counted; measured on 2.1.282, 888 of 902 haiku input tokens in a probe session.$.model.classifyreports no usage and is not counted either.costcounts every request. - A plugin's model call or a compaction made before the module loaded left no record, so a session open before the install misses them for good.
- A turn that ran across the moment the transcripts' sizes were read can be counted twice: its responses written before that moment are read from the transcript, and its
turn.completeadds the whole turn. - The thinking setting is the main loop's last request; a subagent's own setting is not shown.
git statusreads the directory the session started in; a Bashcdinto another repository does not move it.- A Bash command that runs git through a script without naming
gitrefreshes the git line only at the turn's end or the timer.
Development
make install # eslint, typescript-eslint, typescript
make lint # complexity limit 10, fails the build above it
make typecheck # needs .claude/types/ from /plugin-types
make validate
make test # claude plugin test