Steer a live, interactive Claude Code session from your Elgato Stream Deck: switch the model, set reasoning effort, toggle fast mode, and fire off skills — without touching the keyboard.
Claude Code has no local socket/IPC to poke a running session, but /model,
/effort, /fast, and /skill-name are all slash commands that apply
immediately mid-session (Claude Code v2.1.205+). So the plugin injects the
slash command by typing it into the focused terminal via macOS System
Events (osascript):
Stream Deck key ─▶ plugin (Node) ─▶ osascript: keystroke "/effort high"
key code 36 (Return)
Run claude however you normally do — no wrapper, no tmux. The plugin types
into whichever terminal is frontmost (or force a specific app first, see
Activate app).
The plugin is the source of truth for the current selection (Claude Code doesn't report it back), so the model/effort keys light up to show what was last sent.
| Action | Sends | Notes |
|---|---|---|
| Set Model | /model opus|sonnet|haiku|fable |
Active model highlighted |
| Set Effort | /effort low|medium|high|xhigh|max|ultracode |
Active level highlighted |
| Fast Mode | /fast on|off |
2-state toggle |
| Run Skill | any /command (e.g. /prepare) |
one key per skill |
| Send Text / Key | literal text, or a key (Escape, C-c, Up) |
escape hatch |
| Voice | drives Claude Code's native /voice dictation |
push-to-talk, tap toggle, or enable |
- macOS
- Claude Code v2.1.205+
- Elgato Stream Deck app 7.1+
- Accessibility permission for the Stream Deck app (see below)
- Bun for the dev/build toolchain. The plugin itself runs on Stream Deck's own bundled Node.js (Elgato's runtime, set via the manifest); Bun is only used to install, bundle, and script.
System Events keystroke injection requires it. On first key press macOS may prompt; otherwise enable it manually:
System Settings → Privacy & Security → Accessibility → enable “Elgato Stream Deck”.
Without it, keys flash yellow ⚠ and nothing is typed.
Download the latest .streamDeckPlugin from the
latest release
and double-click it to install in the Stream Deck app. Then grant Accessibility
permission (above) and add the actions to your keys.
bun install
bun run build # bun build src -> com.linus.claude-code-control.sdPlugin/bin/plugin.js
bunx streamdeck link com.linus.claude-code-control.sdPlugin
bunx streamdeck restart com.linus.claude-code-control
# iterate with hot reload (rebuild + restart on change):
bun run watchA newly linked plugin only appears in the Stream Deck app's action list after the app rescans it — quit and reopen Stream Deck once. Afterwards,
bun run watchhot-reloads code changes without an app restart (manifest changes still need an app restart).
Then in the Stream Deck app, open the Keys tab, find the Claude Code Control category, and drag actions onto keys.
Package a distributable locally:
bun run validate
bun run package # -> com.linus.claude-code-control.streamDeckPluginEvery push/PR to main runs type-check, build, and plugin validation via
GitHub Actions (.github/workflows/ci.yml).
To cut a release, bump Version in manifest.json, then push a v* tag:
git tag v0.1.0
git push origin v0.1.0.github/workflows/release.yml builds, packages the .streamDeckPlugin, and
attaches it to an auto-generated GitHub Release. Double-click the downloaded
.streamDeckPlugin to install it in the Stream Deck app.
| Setting | Default | Purpose |
|---|---|---|
| Activate app | (blank) | Leave blank to type into whatever window is focused (no focus stealing). Set an app name (e.g. Zed, Ghostty) only if you want keys forced to that app. |
| Submit delay (ms) | 300 |
Wait between typing and Return (raise for long commands) |
| Clear line first | off | Send Escape to clear stray input before typing |
Per-key settings: Set Model → model; Set Effort → level; Run Skill →
the /command (+ optional label, and whether to press Enter); Send Text/Key
→ value + mode (text types it, key sends Escape/C-c/arrows/etc.).
The Voice action drives Claude Code's built-in /voice
dictation (streamed to Anthropic, coding-tuned, no token cost) — no third-party
speech-to-text needed. Pick a gesture in the key's Property Inspector:
- Push-to-talk — hold the key while you speak; release to send.
- Tap toggle — press to start, press again to send.
- Enable voice mode — sends
/voice tapto turn dictation on.
Setup (once per session): press an Enable voice mode key (or type
/voice tap), and grant your terminal microphone access on first use
(System Settings → Privacy & Security → Microphone). Voice needs a Claude.ai
login (not an API key).
Why tap mode under the hood: Claude's native hold mode detects a real key-hold via OS key-repeat, which a synthetic keypress can't produce — so both gestures use
/voice tap(a single injected Space tap to start and to stop). If you reboundvoice:pushToTalkoff Space, set the same key in the action's Voice key field.
- Row 1: Opus / Sonnet / Haiku (Set Model)
- Row 2: Low / High / Max (Set Effort) + Fast toggle
- A folder of Run Skill keys:
/prepare,/lintfix,/release, …
- Yellow ⚠ on a key —
osascriptfailed, almost always missing Accessibility permission for the Stream Deck app (see above). Check the plugin log incom.linus.claude-code-control.sdPlugin/logs/. - Typed into the wrong window — set Activate app to your terminal
(
Ghostty), or make sure the terminal is focused before pressing. - Command typed but not submitted — increase the submit delay.
MIT © Linus Gubenis.
Unofficial — not affiliated with or endorsed by Anthropic. "Claude" and "Claude Code" are trademarks of Anthropic.
