Skip to content

Latest commit

Β 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Vibe Hero 🎸

Approve your coding agent's actions with a Guitar Hero controller.

Code like a guitar GOD. 🀘

CI License: MIT Python 3.9+

A Guitar Hero controller being used to approve a coding agent's actions

Vibe coding is fast but hands-off; reviewing every step is safe but slow. Vibe Hero is the middle ground: Claude Code proposes each command or edit, and you approve or reject it with a guitar gesture β€” keeping a human glance in the loop at rhythm-game speed.

        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   1. wants to run a tool
        β”‚ Claude Code  │──────────────┐
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜              β–Ό
               β–²              PermissionRequest hook
               β”‚                      β”‚
               β”‚                      β”‚ 2. POST /decision  (blocks)
   4. {"behavior":"allow"}            β–Ό
               β”‚              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
               └──────────────│  bridge :8787     β”‚
                              β”‚  vibe_hero.server β”‚
                              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                      β–²
                                      β”‚ 3. you strum
                              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                              β”‚  guitar (USB HID) β”‚
                              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  1. Claude Code fires its PermissionRequest hook whenever it wants to run a tool.
  2. The hook POSTs the pending request to the local bridge, which prints what is being approved and blocks until you play something.
  3. Green fret + strum = allow. Red fret + strum = deny.
  4. The decision goes back to Claude Code as JSON on the hook's stdout.

Fail-safe: if the bridge isn't running, the hook exits silently with no output, and Claude Code falls back to its normal keyboard prompt. An unplugged guitar never blocks your session.

Requirements

  • Python 3.9+
  • A Guitar Hero / Rock Band-style controller that enumerates as a gamepad (see Known controllers)
  • Claude Code
  • macOS: your terminal needs Input Monitoring and Accessibility permission (System Settings β†’ Privacy & Security) to read the controller

Setup

git clone https://github.com/ProjectX-collab/Vibe-Hero.git
cd Vibe-Hero
python -m pip install -e .

1. Find your controller's mapping

Clone controllers (DOYO, NBCP, …) use inconsistent button indices, so this step is not optional β€” the shipped defaults are wrong on most units.

python -m vibe_hero.diagnose

Press each fret one at a time, then strum, then whammy, and note the indices it prints. Then create your mapping and edit it to match:

python -m vibe_hero.diagnose --template

That copies mappings.example.json to mappings.json β€” gitignored, since it's specific to your hardware. If your unit is already in KNOWN_CONTROLLERS.md, copy that block instead and skip the discovery.

Check your work before wiring anything up:

python -m vibe_hero.play --verify

It names each fret in turn and tells you whether it arrived. If every fret and both strum directions check out, your mapping is right.

For raw event output instead, python -m vibe_hero.guitar prints one line per strum. Holding frets alone prints nothing β€” by design, not a fault.

2. Start the bridge

python -m vibe_hero.server

Leave it running in its own terminal. This is where you'll see what Claude Code is asking for.

Only one process can hold the controller. Quit vibe_hero.guitar before starting vibe_hero.server.

3. Shred

Working inside this repo, the hook is already registered by the checked-in .claude/settings.json β€” nothing to configure. Start Claude Code and ask it to do something. When it wants to run a command, the bridge terminal shows:

⏳ APPROVAL WANTED β€” Bash: git status
   green + strum = allow | red + strum = deny

Glance at it, then play your answer.

Use it in your other projects

Merge the hooks key from hooks/settings.example.json into your ~/.claude/settings.json and replace the placeholder with the absolute path to your checkout. Restart Claude Code to load it.

The hook itself is pure standard library, so plain python3 runs it β€” it does not need the environment where pygame is installed. That one is only for the bridge.

Gestures

Gesture Decision
🟒 Green + strum Allow
πŸ”΄ Red + strum Deny
Anything else Ignored β€” the request stays pending

Three rules hold the design together:

  • Only a strum decides. Frets change what a strum means; they never answer on their own, so resting your hand on the neck is safe.
  • A bare strum means nothing. Strumming with no fret held is the easiest thing to do by accident, so it must not be what approves a command. Approving costs a deliberate press.
  • Deny wins ties. Any chord containing red denies, even with green also held, so a fumbled fret can't turn a reject into an approve.

Everything else is deliberately unmapped. The gesture vocabulary is the fun part and it's being designed in the open β€” bring opinions.

Play it

There's a tiny Guitar Hero in the box:

python -m vibe_hero.play
  β™ͺ VIBE HERO   score 1240   streak Γ—2 (11)   47.3s

     β”‚      β”‚      β”‚      β”‚      β”‚
     β”‚      β”‚     ●●●     β”‚      β”‚
     β”‚      β”‚      β”‚      β”‚      β”‚
    ●●●     β”‚      β”‚      β”‚      β”‚
  ───────────────────────────────────
   ( ● )  ( ● )  [●●●]  ( ● )  ( ● )

        PERFECT +200

Notes fall down five lanes; hold the matching fret and strum as one crosses the line. Same rule as the bridge β€” only a strum commits.

Jam while you wait

The controller can only be held by one process, so you can't run the game next to a running bridge. Run it inside the bridge instead:

python -m vibe_hero.server --jam

The game plays while nothing is pending. The moment Claude Code asks for something, the neck clears and the approval prompt takes over β€” approvals always win, and a strum is never counted as both a note and an answer.

Troubleshooting

My guitar isn't detected. If diagnose reports Joysticks found: 0, check the dongle and pairing first. Some clones enumerate as a keyboard rather than a gamepad; python -m vibe_hero.diagnose --keyboard (needs pip install -e ".[keyboard]") will show you which keystrokes the frets emit. There's no keyboard input layer yet β€” it's on the roadmap, and a report of your unit helps.

Nothing happens when I strum. Confirm the layers in order: python -m vibe_hero.guitar prints events β†’ curl http://127.0.0.1:8787/health returns vibe hero ok β†’ the bridge prints ⏳ APPROVAL WANTED when Claude Code asks. Whichever step is silent is the broken one.

The bridge never prints anything. PermissionRequest hooks only fire when Claude Code actually asks for permission. In a session whose permission mode auto-approves, the hook never runs and the bridge stays quiet. That's expected.

The strum registers but Claude Code ignores it. Deny and ask rules in your Claude Code settings are evaluated independently of hooks, so an allow can't override a matching deny rule. Check your permission settings.

Port 8787 is taken. Set VIBE_HERO_PORT for the bridge and a matching VIBE_HERO_URL for the hook.

Security model

Vibe Hero never widens what the agent can do. It only replaces how you answer permission prompts you'd otherwise answer by keyboard β€” deny and ask rules in your Claude Code settings still apply and are evaluated independently.

The bridge binds to 127.0.0.1 and has no authentication, which is appropriate for a local dev tool but worth understanding: any process running as you on the same machine can POST to it and consume a pending approval slot. It can't approve anything on its own β€” only your strum produces a decision, and the decision goes to the hook that asked β€” but a hostile local process could make your strum answer its request instead of Claude Code's. Don't expose port 8787 beyond loopback.

Because the bridge prints the tool and its arguments before blocking, you always see what you're approving. A strum should never be blind.

Roadmap

  • Keyboard-mode input layer for clones that enumerate as keyboards
  • Whammy bar to scroll pending diffs
  • Chords for batch approvals
  • Sound feedback
  • Configurable gesture β†’ decision mapping in mappings.json
  • Star power = enter plan mode?

Reporting a security issue

Please use private vulnerability reporting rather than a public issue. SECURITY.md also explains which parts of the codebase are security-relevant and why.

Contributing

Mappings for untested controllers are the most valuable contribution β€” see CONTRIBUTING.md. Reports of guitars that didn't work are welcome too.

python -m pip install -e ".[dev]"
python -m pytest

License

MIT

About

Vibe Hero is a simple bridge to connect a Guitar Hero/Clone Hero guitar to the coding agent (initially tested with Claude Code).

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages