Buttons is a VS Code and VSCodium extension that scans your project for scripts - package.json scripts, Rust Cargo.toml, Go go.mod, Makefile targets, PHP composer.json scripts, justfile recipes, shell .sh files, and Python entry files - and turns them into a clickable command launcher. You choose the directories to scan (the project root is always included); virtual environments get activate / deactivate / install-requirements buttons.
Run any command in the current or a new integrated terminal, copy it to the clipboard, add your own custom commands, and manage everything from a single panel - no more digging through package.json or remembering the exact flags.
- VS Code: Install from the Marketplace
- VSCodium: Install from Open VSX
- Source / issues: github.com/CurbSoftware/vscode-buttons
Monorepos are my bittersweet ally. Every package brings its own scripts, and I never could keep them straight. I kept retyping the same commands, wasting time.
Buttons is my marriage counsellor. It scans the scripts, turns them into buttons, and remembers what I don't want to. That's what makes my monorepos tolerable.
Detailed guides live in the docs/ directory:
- Getting started
- Using the panel
- Configuration & settings
.buttons.jsonfile format- Script scanning
- Command reference
- FAQ
- Troubleshooting
- Activity Bar - click the Buttons icon in the left Activity Bar for a compact sidebar.
- Editor panel - click the Buttons icon in the editor title bar (top-right, near "split editor") for a full-width editor tab. Both stay in sync and can be used at the same time.
- Buttons (default) - your project buttons and global buttons.
- Project scripts - the scanner, where you pick which discovered scripts become buttons.
Opening a project never writes a file. Click Generate to create .buttons.json with the root-level discovered scripts. Click it again later to add any missing root-level scripts; custom commands and your edits stay (see Generate vs Rescan).
The project root is always scanned at its top level. Add more directories in the Project scripts tab - each with its own recursive toggle - via the Scan directories card and your OS folder picker. The list lives in the buttons.scanDirectories workspace setting, so it is shared with the project (see Script file types and docs/scanning.md).
- Scans
package.json,Cargo.toml,go.mod,Makefile,composer.json, andjustfile, plus standalone.shfiles and common Python entry files (app.py,main.py,manage.py,run.py,server.py) - see Script file types. - Offers venv buttons -
Activate venv,Deactivate, andInstall requirements- when avenv/or.venv/directory is detected. - Supports monorepos - add
packages/(orapps/, …) as a recursive scan directory and nested manifests are found and scoped to their own directory. - Skips installed packages, VCS, and build output (
node_modules,dist,build,coverage,.git,vendor, and more).
Scripts render with the right runner automatically, detected from your lockfiles:
| Lockfile | Rendered command |
|---|---|
pnpm-lock.yaml |
pnpm dev |
yarn.lock |
yarn test |
bun.lockb |
bun dev |
package-lock.json (default) |
npm run dev |
In the Project scripts tab, check or uncheck scripts to include or remove them as buttons. Changes are saved immediately once the file exists.
Add any command that isn't in a script file - docker ps, git pull, curl … - with + Add command, and attach an optional note.
Every button gives you:
- Run - run in the current integrated terminal (reusing it, or a dedicated
Buttonsterminal). - New Terminal - run in a fresh terminal named
Buttons: <label>. - System - open the configured OS terminal at the project root with the command on the prompt. Press Enter there to run.
- + - add the command to the current terminal line with a space (
pnpmthendev→pnpm dev). Does not run. - ↵ - add the command on a new line. Does not run. Press Enter in the terminal when the line is ready.
- Copy - copy the exact command to the clipboard.
- Duplicate - clone the button, including its variants.
- Note / Edit - inline-edit the note (for script buttons) or the command/args and note (for custom commands and variants).
- ✕ - first click shows Confirm; click again to remove.
Parents expand to parameter options (extra args, or nested commands/scripts). Variants can nest further with their own chevron and + Add variant. The chevron badge shows the variant count, or direct:deeper when those variants have children of their own, and stays visible while the group is open. Open groups tint with a depth color from the current theme. Drag the gripper to reorder.
- Sidebar renders each button as a compact card (command/note on one row, actions on the next). Use the window icon in the sidebar header to open the full editor panel.
- Editor panel renders the full table (Command | Note | Actions). Drag the column header edges to resize. The editor tab shows the Buttons logo.
- AI skill - the markdown icon in either header copies the Buttons skill or writes
BUTTONS-SKILL.mdat the project root so coding agents can create.buttons.jsonfiles.
Set the UI text size to VS Code default, +2px, or +4px via buttons.textSize. Optional buttons.colors.* hex values tint action buttons, command text, and command-row backgrounds; leave them empty to inherit the active VS Code theme. The gear icon in the panel header jumps to settings (see Settings).
A ~/.buttons.json file holds commands that apply to every project, so your go-to commands follow you across workspaces.
A Rescan button plus automatic file watchers keep commands current when package.json, Cargo.toml, go.mod, Makefile, composer.json, justfile, .sh or Python entry files, requirements.txt, or your buttons files change.
- Install from the Marketplace or Open VSX.
- Open a folder/project in VS Code.
- Click the Buttons icon in the Activity Bar (or the editor title-bar icon).
- Click Generate to scan the project and create
.buttons.jsonwith the root-level discovered scripts. - Fine-tune in the Project scripts tab, then use Run, New Terminal, System, or Copy on any row - or + Add command for a custom command.
The default tab shows two sections:
- Project buttons - commands from the current workspace's
<workspace root>/.buttons.json. - Global buttons - commands from your personal
~/.buttons.json, shown in every project.
Each row (or card, in the sidebar) shows the command, an optional note, a file badge for script buttons, and the action buttons described above.
A Scan directories card (the always-on project root plus the directories you've added, each with a recursive toggle), and a list of every discovered script grouped by file. Checking a box adds it as a project button; unchecking removes it. Before you Generate a file, the boxes are disabled (there's nothing to edit yet) and a Generate buttons file call-to-action is shown.
- Click + Add command in the Project or Global section.
- Type the command (e.g.
docker ps) and an optional note. - Click Save.
Custom commands are stored verbatim and are never rewritten by scanning.
Buttons distinguishes two scan actions so you never lose work:
- Generate - first time, creates the project's
.buttons.jsonwith every root-level discovered script. If the file already exists, it adds any missing root-level scripts and leaves custom commands, notes, variants, and extra opted-in scripts in place. - Rescan - re-runs the scanner against the existing file. It keeps your included scripts and notes, recomputes their commands, marks scripts that no longer exist as "not found", and leaves newly-discovered scripts unchecked for you to opt in.
In other words: Generate fills in root-level scripts; Rescan updates commands in place without changing what you have selected.
The Buttons: Script Files setting controls which file types are scanned. package.json, shell, python, Cargo.toml, and go.mod are included by default; the others are opt-in checkboxes:
| Type | Ecosystem | Run as |
|---|---|---|
package.json |
Node.js / TypeScript | pnpm dev, npm run dev, yarn test, bun dev |
Cargo.toml |
Rust | cargo build, cargo test, cargo run |
go.mod |
Go | go build, go test, go run . |
Makefile |
C/C++, generic | make build |
composer.json |
PHP | composer test |
justfile |
Universal task runner | just build |
shell |
.sh files |
bash deploy.sh |
python |
app.py, main.py, manage.py, run.py, server.py + venv buttons |
python app.py, source venv/bin/activate |
Commands run with the terminal's working directory set to the script file's directory, and their paths are relative to that directory - scripts/migrate.sh becomes bash migrate.sh inside scripts/.
Only these formats are discovered. Other ecosystems (Python pyproject.toml, .NET, and so on) aren't auto-detected - add their commands with + Add command instead.
Disabling a file type stops offering its scripts in the Project scripts tab, but never removes buttons already in your .buttons.json - Rescan preserves your custom commands and scripts.
Buttons contributes these settings, configurable at User and Workspace scope:
| Setting | Type | Default | Description |
|---|---|---|---|
buttons.textSize |
string (default / plus2 / plus4) |
default |
Text size in the Buttons UI, relative to VS Code's font size. |
buttons.scriptFiles |
string[] (checkbox list) |
["package.json", "shell", "python", "Cargo.toml", "go.mod"] |
Which script file types to scan for commands. |
buttons.scanDirectories |
{ path, recursive }[] |
[] |
Extra directories to scan; the project root is always scanned at its top level. |
buttons.colors.runBackground / runForeground |
color string | "" |
Run button. Same pair exists for newTerminal, append, newline, copy, duplicate, edit, and remove. Empty falls back to actionBackground / actionForeground. |
buttons.colors.actionBackground / actionForeground |
color string | "" |
Fallback for action buttons, and fill for header actions. Empty inherits the VS Code theme. |
buttons.colors.commandForeground / commandBackground |
color string | "" |
Command text and its background. |
buttons.colors.variantCommandForeground / variantCommandBackground |
color string | "" |
Same pair for variant commands. Empty falls back to the command colors. |
buttons.colors.rowOddBackground / rowEvenBackground |
color string | "" |
Alternating command rows. Empty falls back to rowBackground. |
buttons.colors.variantRowOddBackground / variantRowEvenBackground |
color string | "" |
Alternating variant rows. Empty falls back to variantRowBackground, then rowBackground. |
buttons.colors.hoverBackground |
color string | "" |
Action-button hover background. Empty inherits the VS Code theme. |
You can open the settings page from the gear icon in the panel header, or via Command Palette → Preferences: Open Settings and searching "Buttons".
Buttons stores its configuration as JSON:
- Project -
<workspace root>/.buttons.json - Global -
~/.buttons.json
The file has a flat buttons array. Each entry is either a script reference (a live link to a scanned script) or a custom command:
{
"version": 1,
"buttons": [
{ "type": "script", "file": "package.json", "script": "dev", "packageDir": "", "packageManager": "pnpm", "note": "Vite dev server" },
{ "type": "script", "file": "packages/api/package.json", "script": "start", "packageDir": "packages/api", "packageManager": "pnpm" },
{ "type": "script", "file": "Cargo.toml", "script": "build", "packageDir": "", "packageManager": "cargo" },
{ "type": "script", "file": "go.mod", "script": "test", "packageDir": "", "packageManager": "go" },
{ "type": "script", "file": "deploy.sh", "script": "deploy.sh", "packageDir": "", "packageManager": "shell" },
{ "type": "script", "file": "app.py", "script": "app.py", "packageDir": "", "packageManager": "python" },
{ "type": "script", "file": "venv", "script": "Activate venv", "packageDir": "", "packageManager": "python" },
{ "type": "command", "command": "docker ps", "note": "List running containers" }
]
}| Field | Meaning |
|---|---|
type |
Always "script". |
file |
The script file, relative to the workspace root (e.g. package.json, packages/api/package.json). |
script |
The script/target name (e.g. dev, build). For standalone .sh and Python entry files this is the file's relative path. |
packageDir |
The directory of the script file relative to the workspace root (empty string = root). This is where the terminal's working directory is set when you run it. |
packageManager |
One of npm, pnpm, yarn, bun, make, composer, just, shell, python, cargo, go. |
note |
Optional human-readable note. |
| Field | Meaning |
|---|---|
type |
Always "command". |
command |
The literal command to run. |
note |
Optional human-readable note. |
Because a script entry is a reference, its command is recomputed on every scan - so if you switch from pnpm to bun, the button updates to bun dev automatically. Custom command entries are stored verbatim.
These commands are available in the Command Palette (Ctrl/Cmd+Shift+P):
| Command | Purpose |
|---|---|
Buttons: Open Panel |
Focus the Buttons sidebar. |
Buttons: Open in Editor |
Open the full-width Buttons editor panel. |
Buttons: Rescan Scripts |
Re-scan and reconcile the project scripts. |
Buttons: Open Project Buttons File |
Open (and create if needed) <workspace root>/.buttons.json. |
Buttons: Open Global Buttons File |
Open (and create if needed) ~/.buttons.json. |
Buttons scans the project root (top level) plus the directories you add in the Scan directories card. For a monorepo, add the package roots as recursive scan directories - e.g. apps and packages:
project/
├── package.json <- always found (root)
├── apps/ <- add as recursive scan directory
│ └── web/package.json
├── packages/ <- add as recursive scan directory
│ └── api/package.json
└── plugin/composer.json <- found when "plugin" is a scan directory
Each script's terminal is opened with its working directory set to the script's packageDir, so pnpm dev in apps/web runs in the right place.
Inside recursive scan directories, these directories are never entered: node_modules, .git, .hg, .svn, .next, .nuxt, .output, .cache, .turbo, .yarn, .pnpm-store, dist, build, out, coverage, vendor, .venv, venv, __pycache__, .vscode, .idea, target, .svelte-kit, .parcel-cache, and any hidden (dot-prefixed) directory.
Buttons runs the commands exactly as they are written. Review a shared project's .buttons.json before running its commands - treat it like a Makefile or a package.json script. Your ~/.buttons.json is personal and is never shared with a project.
Build and install the extension from source:
# Install dependencies and compile
npm install && npm run compile
# Package as a .vsix
npm run package
# Install the .vsix into VS Code
code --install-extension buttons-vscode-*.vsixReload VS Code (Ctrl+Shift+P → Developer: Reload Window) to pick up the new version. To test without packaging, press F5 in this project to launch the Extension Development Host with the latest code.
npm install # install dependencies
npm run compile # clean + compile TypeScript to dist/
npm run watch # continuous compilation
npm run lint # type-check only (tsc --noEmit)
npm test # compile + run the test suite
npm run package # package as release/<name>-<version>.vsixSee CHANGELOG.md for version history.
- Node.js
>= 24 - VS Code
^1.97.0
MIT. See LICENSE.
