.buttons.json
Buttons stores its configuration as JSON in two places:
| Scope | Path | Applies to |
|---|---|---|
| Project | <workspace root>/.buttons.json |
The current workspace. |
| Global | ~/.buttons.json |
Every project you open. |
Both files use the same format: a version field and a buttons array. Each entry is either a script reference (a live link to a scanned script) or a custom command. Command, script, and args entries can nest children at any depth. Args-only objects are still invalid as top-level buttons.
Example
Section titled “Example”{ "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": "Makefile", "script": "build", "packageDir": "", "packageManager": "make" }, { "type": "script", "file": "composer.json", "script": "test", "packageDir": "", "packageManager": "composer" }, { "type": "script", "file": "justfile", "script": "deploy", "packageDir": "", "packageManager": "just" }, { "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": "scripts/migrate.sh", "script": "scripts/migrate.sh", "packageDir": "scripts", "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" }, { "type": "script", "file": "package.json", "script": "dev", "packageDir": "", "packageManager": "pnpm", "note": "dev server", "children": [ { "args": "--include app1 app2", "note": "app1 + app2" }, { "type": "command", "command": "pnpm dev --filter web", "note": "web only" }, { "type": "script", "file": "apps/web/package.json", "script": "dev", "packageDir": "apps/web", "packageManager": "pnpm" } ] } ]}Script entries (type: "script")
Section titled “Script entries (type: "script")”A live reference to a script the scanner found. The command is recomputed on every scan, so it updates automatically when you switch package managers.
| Field | Required | Meaning |
|---|---|---|
type |
yes | Always "script". |
file |
yes | The script file, relative to the workspace root (e.g. package.json, packages/api/package.json, scripts/deploy.sh); for venv buttons, the venv directory (e.g. venv). |
script |
yes | The script/target name (e.g. dev, build). For standalone .sh and Python entry files this is the file’s workspace-relative path. The run command uses just the file name, relative to packageDir. |
packageDir |
no | The script file’s directory relative to the workspace root ("" = root). This is the terminal working directory when the script runs. |
packageManager |
no | One of npm, pnpm, yarn, bun, make, composer, just, shell, python, cargo, go. Invalid values are normalized to npm. |
note |
no | An optional note shown next to the button. |
id |
no | Stable identity. Assigned when you add or duplicate a button in the UI. |
args |
no | Extra flags appended to the recomputed script command. |
children |
no | Nested variants. See Children. |
Command entries (type: "command")
Section titled “Command entries (type: "command")”A literal custom command, not tied to any file. Stored verbatim and never rewritten.
| Field | Required | Meaning |
|---|---|---|
type |
yes | Always "command". |
command |
yes | The literal command to run. Must be a non-empty string. |
note |
no | An optional note shown next to the button. |
id |
no | Stable identity. Assigned when you add or duplicate a button in the UI. |
args |
no | Extra flags appended to the stored command. |
children |
no | Nested variants. See Children. |
Because a script entry is a reference, its command is recomputed on every scan. Switch from pnpm to bun and the button updates to bun dev automatically. Custom command entries are stored verbatim.
Children
Section titled “Children”A script, command, or args variant can list children, including when it is itself a child. The panel shows them as an expandable set of parameter options.
| Child shape | Meaning |
|---|---|
{ "args": "--include app1 app2", "note": "..." } |
Appends args to the parent’s live command. Nested args append to that variant’s resolved command (pnpm dev --include app1 plus --verbose becomes pnpm dev --include app1 --verbose). If the parent is a script, this stays in sync when the package manager changes. |
{ "type": "command", "command": "..." } |
A literal command, independent of the parent. |
{ "type": "script", "file": "...", "script": "..." } |
Another script reference, resolved on its own. |
Args-only objects are only valid as children, not as top-level buttons. Empty args is rejected.
Use + Add variant on any row to create an args child of that row. Full command or script children can also be added by editing the JSON.
Buttons 2.0.1 and earlier drop children, args, and id if they write the file. Upgrade before editing a file that uses variants.
Validation
Section titled “Validation”When a buttons file is read, it is parsed and validated. If it fails, Buttons shows an error message and treats the file as empty until it is fixed.
| Condition | Message |
|---|---|
| Malformed JSON | Invalid JSON. |
| Top-level value isn’t an object | Top-level value must be an object. |
Unsupported version |
Unsupported version: <v>. Only version 1 is supported. |
buttons isn’t an array |
"buttons" must be an array. |
A buttons[i] element isn’t an object |
buttons[i] must be an object. |
Script entry missing string file/script |
buttons[i] script entry requires string "file" and "script". |
Command entry with empty/non-string command |
buttons[i] command entry requires a non-empty "command". |
Args child with empty/non-string args |
buttons[i].children[j] args entry requires a non-empty "args". |
Unknown entry type |
buttons[i] has unknown type: <v>. Expected "script" or "command". |
The version field is optional when absent (it defaults to 1). note, id, args, and children are only kept when they are valid.
Editing by hand
Section titled “Editing by hand”You can edit these files directly with Buttons: Open Project Buttons File / Buttons: Open Global Buttons File, or in any editor. Buttons watches the files and picks up changes automatically.