Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.buttons.sh/llms.txt

Use this file to discover all available pages before exploring further.

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:
buttons create greet --arg name:string:required
# Created button: greet
#   Edit:  /Users/you/.buttons/buttons/greet/main.sh
#   Press: buttons press greet
Open the scaffolded main.sh — it has a shebang, a TODO comment, and a hint about where args arrive:
#!/bin/sh
set -eu

# TODO: add your command here
# Args arrive as $BUTTONS_ARG_<NAME>
Edit it to whatever you want:
#!/bin/sh
echo "Hello, $BUTTONS_ARG_NAME"
Press:
buttons press greet --arg name=Ada
# → Hello, Ada
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 Python or Node

Pass --runtime to scaffold with the right shebang and extension:
buttons create parse-json --runtime python --arg input:string:required
# → scaffolds main.py with:
#     #!/usr/bin/env python3
#     # TODO: add your code here
#     # Args arrive as os.environ["BUTTONS_ARG_<NAME>"]
buttons create transform --runtime node --arg payload:string:required
# → scaffolds main.js
Flag valueInterpreter usedFile written
shell (default)/bin/shmain.sh
pythonpython3main.py
nodenodemain.js

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:
buttons create hostname --code 'hostname -f'
buttons create ls-home --code 'ls -la ~' --runtime shell
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:
buttons create deploy \
  --file ./scripts/deploy.sh \
  --arg env:string:required \
  --arg version:string:required \
  -d "Deploy a tagged release"
If the script has a shebang, the OS uses that interpreter directly — no need to pass --runtime. Without a shebang and without --runtime, 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):
# Declared:  --arg bucket:string:required
# Available:
echo "$BUTTONS_ARG_BUCKET"           # shell
os.environ["BUTTONS_ARG_BUCKET"]     # python
process.env.BUTTONS_ARG_BUCKET       # node
This prevents shell injection regardless of what the caller passes at press time.

Where the code lives

After buttons create, the button folder contains:
~/.buttons/buttons/<name>/
  button.json     # spec: args, runtime, timeout
  main.sh         # your code (or main.py / main.js)
  AGENT.md        # notes for agents pressing this button
  pressed/        # run history, one JSON file per press
Edit main.sh any time. Changes take effect on the next press — no recreate needed.

Example: wrap a deploy script

# scripts/deploy.sh
#!/bin/bash
set -euo pipefail

ENV=$BUTTONS_ARG_ENV
VERSION=$BUTTONS_ARG_VERSION

echo "Deploying $VERSION to $ENV..."
kubectl set image deployment/app app=registry.example.com/app:$VERSION -n $ENV
kubectl rollout status deployment/app -n $ENV
Import it:
buttons create k8s-deploy \
  --file ./scripts/deploy.sh \
  --arg env:string:required \
  --arg version:string:required \
  -d "Roll out a new image version to a Kubernetes namespace"