> ## 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.

# Folder structure

> How Buttons stores buttons, drawers, history, secrets, and runtime state.

Buttons stores data under `~/.buttons/` by default. In a project initialized with `buttons init`, the active data directory is the closest `.buttons/` folder in the current directory tree. `BUTTONS_HOME` overrides both.

Each button gets its own subdirectory with a spec file, optional code file, agent context, and run history. Drawers get the same pattern for workflow specs and workflow history.

## Directory layout

`buttons init` creates `buttons/` and `drawers/` (mode `0700`). `apps/`, `idempotency/`, and `queues/` are created lazily the first time they are needed.

```
~/.buttons/ or .buttons/
├── buttons.json               # registry dependency manifest; committed for projects
├── buttons-lock.json          # exact resolved versions/hashes; committed for projects
├── history.json              # local create/edit/install/update activity log; gitignored
├── .gitignore                # written by `buttons init`
├── buttons/
│   ├── deploy/
│   │   ├── button.json       # button spec
│   │   ├── main.sh           # script (code and file buttons)
│   │   ├── AGENTS.md         # agent instructions / prompt text
│   │   └── pressed/          # one JSON per run; capped at 100, oldest pruned; gitignored
│   │       ├── 2026-04-10T12-00-00Z.json
│   │       └── 2026-04-10T14-32-11Z.json
│   ├── get-user/
│   │   ├── button.json
│   │   ├── AGENTS.md
│   │   └── pressed/
│   └── summarize-pr/
│       ├── button.json
│       ├── AGENTS.md
│       └── pressed/
├── drawers/
│   └── release-flow/
│       ├── drawer.json
│       ├── AGENTS.md
│       └── pressed/
├── apps/                     # lazy; app-kind buttons from `buttons create --app`
│   └── site/
│       ├── button.json       # kind=app + serve block
│       ├── AGENTS.md
│       └── ...               # cloned/copied app source (no main.*)
├── batteries.json            # secret/env values; gitignored
├── agent.json                # device identity: Ed25519 seed + tunnel token; gitignored
├── webhook.json              # Cloudflare tunnel config; gitignored
├── idempotency/              # lazy; cached successful press results; gitignored
└── queues/                   # lazy; file-lock semaphore state; gitignored
```

## button.json

The spec file for a button. It describes the button type, arguments, runtime, and all other configuration. `schema_version` is the on-disk format counter — currently `1`, and distinct from the package `version` field.

```json theme={null}
{
  "schema_version": 1,
  "name": "deploy",
  "description": "Deploy a tagged release to an environment",
  "runtime": "shell",
  "args": [
    { "name": "env", "type": "string", "required": true },
    { "name": "version", "type": "string", "required": true }
  ],
  "created_at": "2026-04-10T11:00:00Z"
}
```

See [button.json](/concepts/button-json) for every field, including HTTP host locks, queues, output schemas, packaging metadata (`version`, `requires`, `requires_batteries`), and triggers.

## drawer.json

The reusable spec for a Drawer. Schema v2 discriminates pressable action
Drawers from proactive flow Drawers.

```json theme={null}
{
  "schema_version": 2,
  "name": "release-flow",
  "drawer_kind": "action",
  "steps": [
    { "id": "build", "kind": "button", "button": "build" },
    { "id": "publish", "kind": "button", "button": "publish" }
  ]
}
```

See [drawer.json](/concepts/drawer-json) for the full workflow schema.

## Installed buttons and pinning

Registry dependencies are tracked at the project root:

* `.buttons/buttons.json` is desired state: scoped package names mapped to `"latest"` or an exact version.
* `.buttons/buttons-lock.json` is resolved state: exact versions, content hashes, local installed names, and timestamps.
* `.buttons/buttons/<name>/button.json` is the installed button's runtime/package spec.
* `.buttons/drawers/<name>/drawer.json` is the installed drawer's workflow/package spec.

When you install with `buttons add @desk/name` or `buttons install`, button packages are written into `buttons/<name>/`, drawer packages are written into `drawers/<name>/`, and the dependency resolution is written to the lockfile. A drawer package also installs every button referenced by its steps. Dependencies declared in `button.json` `requires` are installed transitively and recorded in the lockfile too.

To share authored local buttons and drawers with a team, commit their folders under `buttons/` and `drawers/`. To share registry dependencies with a team, commit `buttons.json` and `buttons-lock.json` so teammates install the same resolved versions. To push a button or drawer to a registry, use `buttons publish @desk/<name>`; versions are simple numbers starting at `1`, and registry versions are immutable.

## history.json

`history.json` records local create, edit, install, update, delete, and rollback events. It is a per-machine audit log and is gitignored.

Commit the authored button and drawer folders — their `button.json` / `drawer.json` specs, code files, and `AGENTS.md`. Do **not** commit `history.json`, `batteries.json`, `webhook.json`, or the `pressed/` run traces; the `.gitignore` written by `buttons init` already excludes them.

## main.\*

The script file for [code buttons](/buttons/code). The extension matches the runtime: `main.sh` for shell or Bash, `main.py` for Python, `main.js` for Node. HTTP, prompt-only, and app buttons do not have a `main.*` file.

## AGENTS.md

Present on every button (and drawer). For [prompt buttons](/buttons/prompt), it contains the raw instruction text stored at create time via `--prompt`; when pressed, the contents are returned in the `prompt` field of the JSON output. For other button types, `AGENTS.md` holds notes and context an agent can read to understand when and how to press the button.

Units created before the rename may have a singular `AGENT.md`; it is still read as a legacy fallback, but every write uses `AGENTS.md`.

This per-unit file is distinct from two project-level files with the same name: the `.buttons/AGENTS.md` folder reference written by `buttons init`, and the **repo-root `AGENTS.md`**, where the CLI maintains a press-ranked list of the project's buttons between `<!-- BUTTONS:LIST -->` markers (refreshed on `create`/`delete`/`add`/`import`). See [Agent instructions](/ai/agent-instructions).

## pressed/

One JSON file per run, named by UTC timestamp. Each file records the input arguments, exit code, stdout, stderr (each truncated to 1 MB), duration, and status. The directory is capped at 100 runs — the oldest are pruned — and is gitignored because run traces may contain press-time argument values.

```json theme={null}
{
  "button": "deploy",
  "pressed_at": "2026-04-10T14:32:11Z",
  "args": { "env": "staging", "version": "v1.4.2" },
  "exit_code": 0,
  "stdout": "Deploying v1.4.2 to staging...\nDone.",
  "stderr": "",
  "duration_ms": 3241
}
```

## apps/

Lazily created the first time you run `buttons create --app <git-url|path>`. The app source is cloned (shallow, `.git` dropped) or copied here alongside a `button.json` with `kind: "app"` and a `serve` block. App buttons have no `main.*` file.

## batteries.json

Batteries are key/value pairs injected into button presses as `BUTTONS_BAT_<KEY>`. Keys must match `[A-Z][A-Z0-9_]*`.

Project-local batteries live at `.buttons/batteries.json`. Global batteries live at `~/.buttons/batteries.json`. Local values override global values on key collision.

## agent.json

Created by `buttons agent setup`. Holds the workspace's Ed25519 device seed (the private key, base64), the registered slug, and the backing tunnel id and run-token, written `0600`. Because it contains the private seed, it is machine-local and **must never be committed** — `buttons init` gitignores it. See [Agent identity](/concepts/agent-identity).

## webhook.json

Named webhook setup stores Cloudflare tunnel configuration in `webhook.json`. It is machine-specific and should not be committed.

## idempotency/

Successful presses with `--idempotency-key` are cached here until their TTL expires. Created lazily.

## queues/

Buttons with a `queue` declaration use file locks here to enforce concurrency limits. Created lazily.

## Overriding the home directory

Set `BUTTONS_HOME` to use a different base directory:

```bash theme={null}
BUTTONS_HOME=/tmp/test-buttons buttons create test-btn --code 'echo ok' --runtime shell
```

This is useful in CI, tests, or container environments where you want an isolated state directory.

<Note>
  The `~/.buttons/` directory and the files inside it are created with restrictive permissions (`0700` for directories, `0600` for secret files). Other users on the same system cannot read button specs or run history.
</Note>

## Related

* [button.json](/concepts/button-json) — button spec fields
* [drawer.json](/concepts/drawer-json) — workflow spec fields
* [History](/concepts/history) — local audit history
* [JSON output](/concepts/json-output) — the shape of history records
* [Code buttons](/buttons/code) — how `main.*` is populated from scaffolded or imported scripts


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.