Drive Claude Code with a game controller โ and play retro games while the agent works.
vibesense wraps the claude CLI in a pty and passes its TUI through to your terminal untouched. A game controller (Xbox / DualSense / generic HID) drives everything:
- Agent waiting on you? D-pad navigates AskUserQuestion options, A/โ accepts, B/โ cancels, Y/โณ triggers Claude Code's native voice input, right stick scrolls.
- Agent executing? A retro alien-defenders game auto-starts in a browser tab โ left stick moves, RT/R2 fires. The moment Claude stops or asks a question, the game pauses and the controller flips back to driving the terminal.
- Want a break? Menu/Options pauses the game and hands the controller to the terminal; press it again to resume. This manual pause sticks โ the agent starting or stopping won't un-pause it.
- Games are plugins. Anyone can publish a game as an npm package (
vibesense-game-<id>); install withvibesense install <id>.
controller (node-hid) โ one host per machine
โ
input router โโ(agent waiting/idle)โโโถ keystrokes โโโถ node-pty โ claude
โ
โโโโโโโโโ(agent executing)โโโถ SSE โโโถ browser tab (game canvas)
Claude Code hooks (curl POST) โโโถ http://127.0.0.1:48753 โโโถ agent-state FSM
Agent state comes from Claude Code hooks (UserPromptSubmit, Stop, Notification, PermissionRequest, PreToolUse:AskUserQuestion) installed idempotently into ~/.claude/settings.json. Multiple Claude sessions share one host, one controller, and one game โ the game pauses whenever any session needs your attention.
Terminal buttons and game buttons are disjoint sets, with a 750 ms input guard on every mode flip โ mashing fire can never accidentally accept a question.
vibesense games # list installed games (* = active)
vibesense install <id> # install vibesense-game-<id> from npm (tarballs/paths work too)
vibesense use <id> # switch the active game
vibesense uninstall <id>A game is an npm package vibesense-game-<id> with a vibesense-game.json manifest โ either a web game (canvas page served to the game tab) or an external adapter (shell commands on state transitions, e.g. launching/pausing a Steam game). See docs/plugin-contract.md to build one. Paid games are a reserved manifest field (entitlement) with the activation gate already in place โ licensing bolts on later without changing the contract.
Trust model: installing a game is installing an npm package, and
externalgames run shell commands by design. Only install games from authors you trust โ same judgement as adding any dependency.
npm install -g vibesense # or: npx vibesenseRequires Node โฅ22, and is macOS-first. The native deps node-hid / node-pty compile on install, so you'll need build tools (Xcode Command Line Tools on macOS).
npm install
npm run dev # run from source (tsx)
npm run verify # typecheck + lint + format-check + tests