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 - by typing or pasting a path into the Scan directories card's Add field. 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
>= 22 - VS Code
^1.110.0
MIT. See LICENSE.
