# Herdr Plugin Setup

[Herdr](https://herdr.dev) is a terminal workspace manager for coding agents. The Upstash Box plugin
runs your agent inside a box instead of on your machine: focus a pane in a Git worktree, start an
agent, and the plugin uploads that worktree to a new box and opens the agent in a new pane.

Your local files are never edited directly. Changes come back when you run **Apply changes** and
approve the patch.

---

## 1. Requirements

- Herdr 0.8.0 or newer
- Node.js 22 or newer
- Git and `tar`
- An [Upstash Box API key](/box/overall/quickstart#1-get-your-api-key)
- A provider credential for the default TUI mode: a Claude subscription token or an API key

---

## 2. Install the plugin

```bash
herdr plugin install upstash/herdr-upstash-box
```

---

## 3. Set up

```bash
herdr plugin action invoke setup --plugin upstash.box
```

A popup asks for your Upstash Box API key and checks it before going on, then asks which agent to
run, which mode, and which provider credential, and saves the answers for you. Keys are typed
without echo.

<Note>
  That is all the setup there is. The two sections below describe what setup wrote, for when you
  want to change it by hand.
</Note>

### Keys

Keys are read from the environment first, so if you start Herdr from a terminal, exporting them is
enough:

```bash
export UPSTASH_BOX_API_KEY=...
export CLAUDE_CODE_OAUTH_TOKEN=...
```

Herdr started from the Dock or Spotlight does not see your shell exports, which is why setup writes a
`secrets.json` instead, in the directory printed by `herdr plugin config-dir upstash.box`:

```json
{
  "UPSTASH_BOX_API_KEY": "...",
  "CLAUDE_CODE_OAUTH_TOKEN": "..."
}
```

The provider credential follows your model's prefix. For `anthropic/` models Claude Code takes
`CLAUDE_CODE_OAUTH_TOKEN` (a subscription token from `claude setup-token`) or `ANTHROPIC_API_KEY`;
`openrouter/` reads `OPENROUTER_API_KEY`, `openai/` reads `OPENAI_API_KEY`, and `opencode/` reads
`OPENCODE_API_KEY`.

---

## 4. Configure

`config.json`, next to `secrets.json`, is optional. Every key has a default, and setup writes the
ones it asked about:

```json
{
  "mode": "tui",
  "harness": "claude-code",
  "model": "anthropic/claude-sonnet-5",
  "providerApiKeyEnv": "CLAUDE_CODE_OAUTH_TOKEN"
}
```

`harness` is `claude-code`, `codex`, or `opencode`. `model` is a Box model id with its provider
prefix. Claude Code takes `anthropic/` and `openrouter/` models, Codex needs an `openai/` model, and
OpenCode takes any. `providerApiKeyEnv` names the one variable that carries the credential; leave it
out and the plugin picks the variable that fits the model.

`mode` decides what runs in your pane:

- `tui` runs the real agent terminal UI inside the box, using your provider credential.
- `native` runs the Upstash Box CLI, using the Box managed key. Required for the scheduled and typed
  runs in step 8.

Every setting is listed in the [plugin README](https://github.com/upstash/herdr-upstash-box#configure).

---

## 5. Start an agent

Focus a Herdr pane inside a Git worktree, then run:

```bash
herdr plugin action invoke start-agent --plugin upstash.box
```

The command only confirms in your terminal. The new pane opens in Herdr.

The plugin lists the files it will upload, creates the box, unpacks the worktree, and opens the
agent. Credentials and `.env` files are left out of the upload, and every excluded file is shown with
its reason first. Use `excludedPaths` to leave more out and `allowSensitivePaths` to keep something
the filter would drop.

Bind it to a key so this is one keystroke:

```toml
[[keys.command]]
key = "prefix+shift+u"
command = "herdr plugin action invoke start-agent --plugin upstash.box"
```

To start on a different agent for one launch without editing `config.json`, use `start-claude`,
`start-codex`, or `start-opencode` in place of `start-agent`.

---

## 6. Use the agent

```bash
herdr plugin action invoke reconnect --plugin upstash.box
herdr plugin action invoke apply-changes --plugin upstash.box
herdr plugin action invoke info --plugin upstash.box
herdr plugin action invoke stop --plugin upstash.box
```

You can close the agent pane at any time and the agent keeps working. **Reconnect** brings it back,
resuming the box first if it paused while you were away.

**Apply changes** exports what the agent changed as a Git patch, checks it against your worktree, and
applies it after you approve.

**Info** shows the box status and paths. **Stop** ends the session and keeps the box.

---

## 7. Manage boxes

```bash
herdr plugin action invoke pause --plugin upstash.box
herdr plugin action invoke resume --plugin upstash.box
herdr plugin action invoke snapshot --plugin upstash.box
herdr plugin action invoke previews --plugin upstash.box
herdr plugin action invoke delete-box --plugin upstash.box
herdr plugin action invoke dashboard --plugin upstash.box
```

Boxes pause on their own when idle. **Snapshot** saves the box state, and **Previews** exposes a
configured port with a [public URL](/box/overall/preview).

The **dashboard** lists every box with its worktree, agent, and live status, and runs any action on
the selected row:

```
[j/k] Select  [enter/r] Reconnect  [a] Apply  [i] Info  [s] Stop  [p] Pause  [u] Resume
[n] Snapshot  [f] Fork  [v] Previews  [t] Run task  [h] Results  [c] Schedules
[d] Delete  [R] Refresh  [q] Close
```

Delete boxes from here rather than from the Upstash console, so the plugin forgets them too.

---

## 8. Scheduled and typed runs

In native mode, a box can run the agent server-side with nothing attached:

```bash
herdr plugin action invoke run-task --plugin upstash.box
herdr plugin action invoke schedules --plugin upstash.box
herdr plugin action invoke run-results --plugin upstash.box
```

**Run task** takes a prompt and a JSON Schema and stores the typed result. **Schedules** manages
[cron schedules](/box/overall/schedules) with `c <cron> | <prompt>` to create, and `p`, `r`, `d` with
a schedule id to pause, resume, and delete. **Run results** shows recent runs.

A schedule wakes a paused box when it fires, so it can run up model and compute costs while Herdr is
closed.

---

## Troubleshooting

**The upload is too large.** Uploads are capped at 100 MiB in total and 10 MiB per file, and Box
rejects anything over 100 MB, so raising `maxUploadBytes` will not get you past it. The error names
the heaviest directories. Exclude them:

```json
{ "excludedPaths": ["img", "public/video"] }
```

**Claude Code answers `401 OAuth access token is invalid`.** The subscription token in
`secrets.json` is wrong, usually a paste that lost part of it or a token from an earlier
`claude setup-token` run. Run `claude setup-token` again, run setup, press `r` at the credential
prompt to replace the token, then run **stop** and **reconnect** so the agent restarts with the new
one.

**A second Start is refused.** One box per worktree is the default. Reconnect to the existing box, or
delete it from the dashboard, then start again.

**An action says another popup is already open.** Herdr shows one popup at a time. Close it and try
again.

**Native mode connects to the wrong API.** The `box` CLI reads a `.env` from your worktree. If it
sets `UPSTASH_BOX_BASE_URL`, unset it or set the same value where Herdr runs.

---

## Next steps

<CardGroup cols={2}>
  <Card title="Live Sessions" icon="terminal" href="/box/overall/live-sessions">
    How interactive sessions into a box work.
  </Card>
  <Card title="Snapshots" icon="camera" href="/box/overall/snapshots">
    Save and restore box state.
  </Card>
  <Card title="Schedules" icon="clock" href="/box/overall/schedules">
    Run agents on a cron server-side.
  </Card>
  <Card title="Plugin source" icon="github" href="https://github.com/upstash/herdr-upstash-box">
    The plugin repository and full configuration reference.
  </Card>
</CardGroup>
