Skip to content

Repository files navigation

Session Sitter

Agent governance for the terminal.
Permission rules that never match git add && git commit. An "always allow" that saves the whole command line and so never matches again. Unattended runs that stall, or are denied with nothing said. Session Sitter answers each prompt from your team's written practices instead — rules that hold across a whole command, approvals that generalise, and a record of every decision, each one citing the clause it applied.

Silence is never approval.

CI Latest release MIT

What changes · Install · Supervision · vs. first-party · Docs

Session Sitter supervising live agent sessions: a worklist across four agents above the supervision activity feed, showing one auto-approved, one auto-corrected and one escalated decision
The panel — every live session, and what the supervisor decided. More shots.


What one decision looks like

The agent asked to force-push. It was not blocked — it was corrected, and told why:

{"tool":"Bash","inputSummary":"git push --force origin main",
 "light":"yellow","decision":"allow","clause":"practices §force-push","actor":"policy",
 "latencyMs":4,"rewritten":true,
 "note":"corrected — practices §force-push: --force replaced with --force-with-lease so the
 push refuses rather than overwriting commits pushed by someone else"}

That is a real record, from a real session — not an illustration. The push it corrected was not a no-op either: another clone had already pushed a commit our repo had never fetched, so the original --force would have destroyed it. The lease refused instead — ! [rejected] main -> main (stale info) — and the other commit is still on the remote. The agent worked out what had happened on its own: "(stale info) is not an error plain git push --force produces… something between me and git converted the force push into a lease-checked one."

4 ms in the hook, no model call. The full transcripts, the verbatim hook input and output, and the other thirteen decisions ship as docs/EVIDENCE.md alongside the plugin itself.

Every decision names the practice it applied. That is the whole difference between a governance layer and a classifier: Blocked by classifier is not something you can hand to your security lead, and it is not something an agent can act on.


Install

# Grab the .vsix from the latest release, then:
code --install-extension session-sitter-*.vsix

Latest release ↓ · or in the IDE: Extensions panel → ···Install from VSIX… · reload the window and you are done.

Note

Not on the VS Code Marketplace yet, so the extension installs by VSIX. The extension is not the only way in, and for a terminal it is not the recommended one — the Claude Code plugin and the session-sitter command have both landed:

/plugin marketplace add eranra/session-sitter    # governance in the terminal
/plugin install session-sitter@session-sitter
npx github:eranra/session-sitter status          # the command, on its own

The plugin · the command · the design.

Every pull request also attaches a build, under the CI run's Artifacts — handy for trying a change before it lands.

Or from source:

git clone https://github.com/eranra/session-sitter.git
cd session-sitter
make install

That builds the extension and installs it. Then reload the window — Ctrl+Shift+PDeveloper: Reload Window. Done.

Installing into IBM Bob IDE, Cursor, or another VS Code build

make install shells out to code. Point it at any other CLI:

make install CODE=bobide     # IBM Bob IDE
make install CODE=cursor     # Cursor
make install CODE=code-insiders
Hacking on it
npm ci        # once
make check    # type-check + lint + the test suite

Then press F5 for an Extension Development Host with live reloading — no packaging step. make on its own lists every target.


What changes

A coding agent that pauses for approval and gets no answer is not safe — it is stopped, or it is waved through. Session Sitter is the layer that answers, in writing, and keeps the receipt.

Without it With it
An overnight run stalls at the first prompt — or, in a session that cannot prompt, is silently denied — unless you run under --dangerously-skip-permissions and hope keeps going on the actions your rules already allow, and a denial says which clause denied it
A safe, boring prompt you approve read_file for the ninetieth time resolved by rule, before any model call
A compound command Bash(git:*) never matches git add x && git commit -m y — and a deny rule you wrote is walked past the same way every part of the line is judged, and the most restrictive verdict wins
"Always allow", clicked the literal command line is saved, so the next near-identical one asks again the approval is generalised from the practice that justified it
An unsafe action approved, or blocked with nothing to act on blocked, and the agent is handed the safe alternatives instead
A judgment call it waits until you look a decision card on your phone with a countdown — and on timeout it is denied, never approved
"What did it actually do?" scroll four transcripts one durable JSON record per decision, plus the activity feed
An agent stuck in another window you find out when you get there it is in this window's worklist, marked as waiting on you
A session on another machine you go and look for it it is in the same list, one click to focus the window that owns it

† These two are in the open pull requests behind the Claude Code plugin, not in the released extension — same status as the plugin itself.


Supervision

Coding agents do not stop when you close the laptop. Supervision is for the moments you are not there: it classifies each action an agent pauses on, against your own written practices, and acts.

The four supervision lights. Green: the action is fine — approve the prompt, record it, no human contact. Yellow: a safe correction — inject labeled guidance, the agent self-corrects, no human contact. Orange: your call — block it, decision card with a countdown, on timeout deny and hand over safe alternatives. Red: policy, not judgment — block outright, send an alert, on timeout the block stands. Silence is never approval: an unanswered card denies the action and never writes an approval.

The deterministic tier is what keeps a governance layer off the critical path of every read, and the two timeout edges are the whole principle: an unanswered card is a denial.

Every one of those decisions lands in the activity feed, saying which light it was, who decided — 🧠 AI or ⚙ rule — and what the agent was actually asked to do:

The supervision activity feed showing one decision of each light: green auto-approved, yellow auto-corrected, orange awaiting a human, red blocked
One card per decision. An orange card names its options and its countdown; a red one says why it stands.

Everything is a setting — no environment variables to maintain, no .env. Open ☰ → All settings… in the panel, or search sessionSitter in the Settings UI. There is nothing to run: the supervisor lives inside the extension, with no daemon and no interpreter.

docs/SUPERVISION.md — turning it on, the lifecycle, the CLI, troubleshooting. → docs/CONFIGURATION.md — every setting, flag and command. → docs/KNOWLEDGE.md — the practices files the classifier reads.


Telegram remote control (optional)

Your active sessions as topics in a Telegram forum group. The thread you type in is the session you are talking to, so there is no mode to get wrong.

GROUP "Session Sitter"  (Topics enabled)

  # General                            ← the active list, /sessions /history /new /who /help
  # 🟠 sitter / sort order · claude              2
  # 🔄 payments / refund flow · bob
  # ⚪ scratch / spike · codex@laptop2

The group holds the same sessions the Sessions panel does — one shared rule, so the two cannot disagree — and every name reads status, workspace, title, then the agent and the machine. A session that leaves the active list has its topic closed, keeping its scrollback. /history reaches the rest: tap a row to open its topic and bring the session back.

Open a topic and you get that session's turns as they happen, its supervision cards, a Full transcript upload, Focus in IDE, and a text box that sends straight into the agent.

Reading works for all four agents. Writing works for Bob — any task, live or historical — and for Claude sessions open in their own window. Codex and VS Code Chat expose no message API, so their topics say they are read-only rather than dropping what you type.

Turning it on, once per machine:

{
  "sessionSitter.telegram.remoteControl": true,
  "sessionSitter.telegram.allowedUserIds": ["123456789"]
}

plus a group with Topics enabled, a bot with privacy mode disabled (otherwise it cannot see what you type in a topic), and TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID in your environment or .env.

Two things to know before you start:

  • allowedUserIds is empty by default, and empty authorises nobody. A group is not a private chat, and acting on a message means typing into a live coding agent.
  • Use one bot per machine. A bot token has a single message stream and reading it is destructive, so two machines sharing one steal each other's messages. Add each machine's bot to the same group; the fleet view is the union.

Full walk-through, including the failure table: → docs/TELEGRAM.md


How this relates to Claude Code's own features

Leave Auto mode on. It is a better default than approving by reflex. What it does not do is the part that has to be yours, because the policy is yours:

Claude Code, first-party Session Sitter
Who decides Auto mode, with Anthropic's judgment your team's written practices
What you are told Blocked by classifier the clause it applied — denied — practices §4: never force-push to a shared branch
An unsafe call blocked rewritten into the safe one — git push --force--force-with-lease — so the run continues
Afterwards nothing to hand anyone one durable JSONL record per decision, queryable
Unattended a session that cannot prompt denies silently a standing policy decides, and deny-on-timeout is explicit
Scope Claude Code, one machine (Agent view is local by design) Claude Code, IBM Bob, Codex, VS Code Chat — unioned across windows and peer machines

Both layers run at once, and the supervision half of this extension is off until you turn it on.


Features

  • Practices as policy, with the clause cited — every decision names the rule it applied, not a fixed string.
  • Deny on timeout, always — an escalated decision with no answer is denied, and the denial says which clause denied it. Silence never writes an approval, and never stalls a run without a reason.
  • A durable record per decision — which light, who decided (🧠 AI or ⚙ rule), what was asked, what happened. JSON on disk, plus an activity feed that expands failures to their recorded error.
  • A deterministic tier in front of the classifier — read-only actions never cost a model call, so governance stays off the critical path.
  • The correction lane — an unsafe call is rewritten into the safe one and re-checked against your deny rules, so a blocked agent gets a way forward instead of a wall.
  • Four agents, one policy — Claude Code, IBM Bob IDE, Codex CLI, VS Code Chat, by reading only what they already write to disk. → how
  • Across windows and across machines — peers are discovered from the remote windows your IDE already opened and probed over SSH, with nothing to install on the far side. One click focuses the window that owns a session, even on another box.
  • Six live states, not three — working, waiting for your approval, waiting for your answer, finished-unread, finished-read, dormant. An agent that is stuck is not an agent that is busy.
  • Copy transcript as handoff-clean markdown — prose only, tool calls stripped, all four sources.
  • Telegram remote control (off by default) — every session becomes a topic in a Telegram forum group; read it, and type into it, from your phone. → above

Let an agent configure it

You already have a coding agent. It can do the setup, and it can tell you why a setting is not taking effect — docs/onboarding/ is an Agent Skill for exactly that.

Read docs/onboarding/SKILL.md and set up Session Sitter for me.

It walks the configuration in six layers, from the session panel (which needs nothing) up to the fast classifier, asks about each, and validates what it wrote — because VS Code ignores an unrecognised setting key silently, so an invented id gives you a configuration that looks complete and does nothing. The same skill reconfigures an existing install and reviews one:

Turn on Telegram decision cards.
Why isn't my auto-approve rule firing?
Review my Session Sitter configuration.

To have it in every Claude Code session, copy it into your skills directory:

mkdir -p ~/.claude/skills/configuring-session-sitter
cp -r docs/onboarding/* ~/.claude/skills/configuring-session-sitter/

The validator runs on its own too — no dependencies, no network, and it writes nothing:

node docs/onboarding/scripts/ss-config.mjs where   # which settings.json is the live one
node docs/onboarding/scripts/ss-config.mjs check   # what is configured, and what is broken

where matters more than it sounds: on WSL and on a remote IDE several settings.json files exist and only one is read, which is the commonest reason a change appears to do nothing.

Not using an agent? docs/onboarding/SKILL.md reads as a getting-started guide, and docs/CONFIGURATION.md is the full reference.


First run

Open the Secondary SidebarCtrl+Alt+B, or View → Secondary Side Bar. The Session Sitter panel is there. Open a Claude or Bob session and it shows up within seconds.

I want to… Do this
Switch to a session Click the row
Close its tab Click × on the row
Start a new session Click + (Claude) or +B (Bob)
Peek at the conversation Hover a row
Reorder the list Click — recency, machine, workspace, agent, title, or needs-you-first
Colour a project ☰ → Settings — one colour per workspace, or auto for all of them
See older sessions Click History ▶
Copy a transcript Right-click → Copy transcript → editor / clipboard / file
Open About or Settings Click

The main list is a live worklist — only sessions you can act on right now. Claude and Bob are judged by what their extension hosts report as open, unioned across every window, so a session open in another window still appears here. Codex and Chat expose no such signal, so they count as active while recently updated. Everything else moves to History.

Each row carries a status marker — six states, distinguished by shape as well as colour, so they survive a screenshot and a colour-blind reader: working · waiting for your approval · waiting for your answer · finished-unread · finished-read · dormant. Titles come from each agent's own naming — Claude's generated title, Bob's task title, Codex's thread name, Chat's first request — and the non-recency sort orders hold rows still while sessions update, so you do not lose your place.

The worklist sorted needs-you-first, with one session waiting on a human decision Hovering a row shows a preview of the last few messages in that session
Needs-you-first ordering · hovering a row previews the conversation

What you need

VS Code or IBM Bob IDE 1.65 or later
Linux, WSL or macOS for Claude liveness detection — /proc/<pid>/stat on Linux, ps elsewhere
python3 to read IBM Bob's SQLite store. Only needed for Bob sessions.
Node 20+ only to build from source

Documentation

Every document is indexed in docs/README.md. The short version:

Document What it covers
docs/onboarding/ the Agent Skill that configures all of it: the interview, seven worked configurations, and the validator
docs/ARCHITECTURE.md components, session detection, cross-machine, the supervision layer, the agent bridges
docs/STATUS-INDICATORS.md the six row markers, and the rules that pick one — per agent
docs/CLI.md the session-sitter terminal command: status, log, digest, policy check
docs/SUPERVISION.md the traffic lights, the lifecycle, the CLI, troubleshooting
docs/TELEGRAM.md the remote interface: setup, ownership, write limits, troubleshooting
docs/KNOWLEDGE.md the BDI schema, the three tiers, routing
docs/CORPUS.md collecting sessions, bulk import, secret masking
docs/CONFIGURATION.md every setting, environment variable, flag and command
docs/PLUGIN.md the Claude Code plugin: install, the hooks, the practices format, the audit trail

Known limitations

  • On Windows, Claude liveness loses its recycled-PID guard — Linux and WSL cross-check the PID against /proc/<pid>/stat, macOS against ps -o lstart=. With neither available the kill(pid, 0) signal alone decides, so sessions still list but a recycled PID could in principle look live.
  • python3 is required for Bob sessions — a VS Code extension has no SQLite driver, and a native module would break VSIX portability. Confined to one file, read-only. → why
  • Claude message injection cannot always pick a session — the sessionId↔channel link is searched for at send time and is not exposed by every Claude build. When a window has several Claude sessions open and none matches, nothing is sent and you are told: delivering a prompt to the wrong agent is worse than not delivering it.
  • Supervision needs a classifier CLIbob or claude on your PATH.
  • Telegram remote control needs a bot per machine — a bot token has one destructive message stream, so machines cannot share one. → docs/TELEGRAM.md
  • Telegram cannot write to Codex or VS Code Chat sessions — neither exposes a message API. Their topics are read-only and say so.
  • Peer visibility is one-way — a machine behind NAT with no reachable sshd can see its peers and will not be seen by them. Unreachable peers are named as unreachable rather than shown empty.
  • No motion demo yet — the screenshots are real; the 20-second GIF of a correction being made needs a machine with a screen. Shot list: docs/screenshots/README.md.

The per-agent liveness caveats behind these — when a new Claude session first appears, what Bob can and cannot report about its sidebar, and why Codex and Chat fall back to recency — are in docs/ARCHITECTURE.md.


Contributing

make check — type-check, lint and tests, the same gate CI applies. Then make on its own lists every target. Issues and pull requests welcome; the guards, the TypeScript-only rule and the release process are in CONTRIBUTING.md. For a vulnerability please use the private path in SECURITY.md rather than an issue.

License

MIT

About

Session Sitter — see every coding-agent session, switch in one click, and supervise what they pause on. VS Code extension for Claude Code, IBM Bob, Codex and VS Code Chat.

Topics

Resources

Contributing

Security policy

Stars

7 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages