Skip to main content
A code button is a script the runtime executes every time you press it. The script lives as a file inside the button folder, so you can edit it the same way you edit any other file.

The default flow: scaffold, edit, press

The simplest way to create a button is to let Buttons scaffold a placeholder script you can fill in. Declare the args you’ll need up front — they’re part of the button spec and can’t be added later without recreating the button:
Open the scaffolded main.sh — it has a shebang, a TODO comment, and a hint about where args arrive:
Edit it to whatever you want:
Press:
Args are declared at create time and stored in button.json. If you need to change them, delete and recreate the button — your main.sh is at the same path each time, so you can copy your edits over.

Scaffold in Bash, Python, or Node

Pass --runtime to scaffold with the right shebang and extension:
The bash runtime requires Bash to be installed. If it is unavailable, buttons press returns RUNTIME_MISSING; Buttons does not install it automatically.

Shortcuts for when you already know the code

Three shortcuts let you skip the edit step when the script is trivial or already on disk.

--code 'one-liner'

Pass a one-line script inline. Useful when the body is a single command and quoting isn’t painful:
Inline code is capped at 64 KB. Beyond that, write it to a file and use --file.

--file ./path/to/script.sh

Copy an existing script into the button folder. The file is copied (not symlinked) so the button is self-contained:
When importing code, Buttons infers the runtime from the file extension or shebang. Without a recognized extension or shebang, Buttons defaults to /bin/sh.

Argument injection

Arguments are never interpolated into the script body. They arrive as environment variables named BUTTONS_ARG_<NAME> (uppercased):
This prevents shell injection regardless of what the caller passes at press time.

Reporting progress

Long-running buttons can stream progress while they run. Before executing your script, the engine sets $BUTTONS_PROGRESS_PATH to a per-press file. Append one JSON object per line (JSONL) to it, and buttons tail -f follows those events live in another terminal.
Follow it while it runs:
Progress events are advisory and separate from the result — the final structured output still goes to stdout when the press finishes. A script that never writes to $BUTTONS_PROGRESS_PATH simply produces no progress to follow. See the tail CLI reference.

Where the code lives

After buttons create, the button folder contains:
Edit main.sh any time. Changes take effect on the next press — no recreate needed.

Example: wrap a deploy script

Import it: