A /issues pane listing the repo's open GitHub issues; click one to open it, or send it to the prompt.

Mods for Claude Code, installable on any machine (Windows, macOS, Linux) with no paths to configure.
command-deck is the main mod: one band above the prompt that shows your session at a glance and gives you buttons for the other mods. The other four are separate mods you add only if you want them. Each one adds its own slash command, and the deck shows a button for it only when it is installed.
| Mod | What it does | Command |
|---|---|---|
| command-deck | The band above the prompt. | /deck |
| github-issues | A pane listing the repo's open GitHub issues. | /issues |
| prompt-upgrade | Turns a rough prompt into a better one before it is sent. | /better |
| auto-model | Picks the right model for each prompt you type. | /automodel |
| dev-server | Starts, stops and restarts the project's dev server. | /dev |
In Claude Code, add the marketplace once:
/plugin marketplace add clafronteaccnts/commanddeck
Then install the deck:
/plugin install command-deck@commanddeck
Restart Claude Code. The deck works on its own, with its meters and the model and effort selectors.
Install any of these the same way, then restart Claude Code. Each one is optional.
/plugin install github-issues@commanddeck
/plugin install prompt-upgrade@commanddeck
/plugin install auto-model@commanddeck
/plugin install dev-server@commanddeck
One band above the prompt, with:
package.json version, the git branch, how many files changed, and commits ahead or behind.dev :9002 up or down, shown when the project's dev script names a port (for example next dev -p 9002).Run /deck to collapse the band to a single line, and again to expand it.
/issues opens a pane with the repo's open GitHub issues. Click one to open it in the browser, or press Ask to put "Work on issue #N" in the prompt. Needs the GitHub CLI (see Requirements).
/better <prompt> turns a rough prompt into a better one: it asks a few quick questions, rewrites the prompt and shows a side-by-side review before anything is sent.
/better on and /better off turn the automatic mode on and off./better history shows earlier upgrades.The deck's Prompt Upgrade button arms it for your next prompt.
/automodel on picks the right model for each prompt you type, quietly. /automodel off returns to the model you started on, and /automodel status shows the current state. The deck's Auto Model button toggles it, and the model selector gains an Auto choice.
/dev start, /dev stop, /dev restart and /dev status run the project's package.json dev script (npm run dev) and show its output in a pane. Plain /dev toggles it and opens the pane. Stopping also ends whatever is still listening on the dev port. It only stops a server it started itself; one started in a terminal has to be stopped there. The deck's Start dev and Stop dev button does the same.
/plugin marketplace update commanddeck
Restart Claude Code afterwards. Updates only arrive when a mod's version number changes.
/plugin uninstall command-deck@commanddeck
Use the same form for the other mods, for example github-issues@commanddeck.
git on your PATH for the git meter (it shows nothing in folders that aren't repos), and curl for the dev-server status (shown when the project's dev script names a port).gh), signed in with gh auth login.npm on your PATH, and a dev script in the project's package.json. To stop the server it uses netstat and taskkill on Windows, or lsof and kill on macOS and Linux.hooks/register.tsx 71 lines1import { atom, read, update } from 'claude-code'
2import type { Engine, Register } from 'claude-code'
3
4import type { Issue } from '../types'
5
6const PANE = 'github-issues'
7const issues = atom({ plugin: 'github-issues', key: 'issues' } as const, [])
8const status = atom({ plugin: 'github-issues', key: 'status' } as const, 'Not loaded yet.')
9
10async function load($: Engine): Promise<void> {
11 await update($, status, () => 'Loading...')
12 try {
13 const r = await $.process.run(
14 ['gh', 'issue', 'list', '--state', 'open', '--limit', '50', '--json', 'number,title,url,labels'],
15 { timeoutMs: 20000 },
16 )
17 if (r.exitCode !== 0) {
18 await update($, status, () => `gh failed: ${r.stderr.trim().slice(0, 200)}`)
19 return
20 }
21 const rows: Issue[] = JSON.parse(r.stdout).map((i: any) => ({
22 number: i.number,
23 title: i.title,
24 url: i.url,
25 labels: (i.labels ?? []).map((l: any) => l.name),
26 }))
27 await update($, issues, () => rows)
28 await update($, status, () => (rows.length === 0 ? 'No open issues.' : `${rows.length} open`))
29 } catch (err) {
30 await update($, status, () => `Could not load issues: ${String(err).slice(0, 200)}`)
31 }
32}
33
34export const register: Register = on => {
35 on('session.start', async ($, e, next) => {
36 await $.command.register({ name: 'issues', description: 'Show open GitHub issues in a pane' })
37 return next(e)
38 })
39
40 on('command.run', { command: 'issues' }, async $ => {
41 await $.ui.open({ id: PANE, title: 'GitHub issues' })
42 void load($)
43 return { text: 'Issues pane opened.' }
44 })
45
46 on('ui.render', { component: 'Pane', requestId: PANE }, async ($, e) => {
47 const { Box, Text, Button, Link } = $.ui.resolve(e)
48 const list = await read($, issues)
49 const note = await read($, status)
50
51 return (
52 <Box flexDirection="column">
53 <Box flexDirection="row">
54 <Button onPress={() => void load($)}>Refresh</Button>
55 <Text dimColor> {note}</Text>
56 </Box>
57 {list.map(i => (
58 <Box flexDirection="row" key={String(i.number)}>
59 <Button onPress={() => void $.prompt.fill({ text: `Work on issue #${i.number}: ${i.title}`, mode: 'replace' })}>
60 Ask
61 </Button>
62 <Text> </Text>
63 <Link href={i.url}>{`#${i.number} ${i.title}`}</Link>
64 {i.labels.length > 0 && <Text dimColor> [{i.labels.join(', ')}]</Text>}
65 </Box>
66 ))}
67 </Box>
68 )
69 })
70}
71types/index.d.ts 8 lines1export type Issue = { number: number; title: string; url: string; labels: string[] }
2
3declare module 'claude-code' {
4 interface PluginState {
5 'github-issues': { issues: Issue[]; status: string }
6 }
7}
8