berthdocs

Reference

Config reference

Every field of .berth/config.json, kit.json, and the box's own config files.

.berth/config.json

A repository's config, committed at .berth/config.json. The same shape is a kit's config and a box's own config for a location. A missing file means no config; a file that doesn't parse is an error the app and CLI show. A guide is in project config.

FieldTypeMeaning
setupstringRun in a new worktree, through a login shell, after it is created. Up to 30 minutes, logged on the box.
archivestringRun before a worktree is removed, after its services stop. If it fails, the worktree stays.
portsnumberHow many ports each worktree gets, 0 to 10. Every worktree gets at least one.
envobjectVariables for everything run in a worktree. Keys are [A-Za-z_][A-Za-z0-9_]*. Values can use $NAME for BERTH_* variables and berthd's environment, or be a secret reference.
servicesarrayServices run in every worktree.
agentsarrayAgent presets to add, or to replace built-ins by id.
hooksarrayHooks for this repository's events only, run in the worktree.
flowsarrayFlows for this repository's worktrees.

services

FieldTypeMeaning
namestringRequired. [a-z0-9][a-z0-9-]*, at most 32 characters, unique.
runstringRequired. Run in the worktree through a login shell, with its environment and PORT.
autostartbooleanStart when the worktree is created, after setup succeeds.

agents

FieldTypeMeaning
idstringThe preset's id. The same id as a built-in (claude, codex, opencode, gemini, cursor) replaces it.
namestringShown in the app.
commandstringWhat to run.
prompt_flagstringHow the agent takes a first prompt, when it needs a flag (--prompt). Empty: the prompt is the last argument.

The built-ins are offered when their command is installed on the box: claude, codex, opencode (--prompt), gemini (-i) and cursor (cursor-agent).

hooks

FieldTypeMeaning
onstringRequired. An event type, a prefix like worktree.*, *, or before: and an action for a gate.
runstringRequired. Run through /bin/sh -c with the event on stdin and in BERTH_* variables.
timeoutstringA Go duration. Default 1m, or 30s for gates.
toolstringNever run for events whose origin is this tool.

The same shape is used in ~/.berth/hooks.json ({"hooks": [...]}) and in a plugin's manifest. See hooks.

flows

FieldTypeMeaning
idstringRequired. [a-z0-9][a-z0-9-]*, at most 48 characters, unique.
namestringRequired.
enabledbooleanDefault false: a flow runs only when it is true.
triggerobjectExactly one of event, schedule or github; see below.
stepsarrayAt least one; see below.
max_runs_per_hournumberDefault 20 when empty or 0.

trigger:

FieldTypeMeaning
eventstringAn event type or prefix. Not a before: gate.
schedulestringCron (m h dom mon dow) or @hourly, @daily, @midnight, @weekly, @monthly, @yearly, @annually; the box's local time.
each_worktreebooleanWith schedule only: once for every worktree.
githubobjecton: review_comment, pr_review, check_failed or pr_merged; poll: a duration, at least 1m, default 2m.
whereobjectlocation, agent, branch (a trailing * matches a prefix). Empty matches anything.

Each of steps:

FieldTypeMeaning
idstringOptional, unique in the flow. Unnamed steps are 1, 2, …
kindstringrun, prompt, wait, start_agent, notify or webhook.
whenstringsuccess (default), failure or always.
commandstringrun: required.
textstringprompt: required, the prompt. start_agent: its first prompt. notify: the body. webhook: the JSON body (default: every variable).
titlestringnotify: required.
sessionstringprompt: which session (default: the agent that triggered the flow).
forarraywait: states that end it (default finished, waiting).
agentstringstart_agent: required, a preset id.
new_worktree, nameboolean, stringstart_agent: in a new worktree, and its name.
urlstringwebhook: required, http or https.
timeoutstringA duration: run 10m, wait 30m, webhook 15s by default; at most 2h.

Variables and behaviour are in automations.

How layers merge

A location's effective config is the repository's file, then its kit's config, then the box's own config for it:

FieldMerge
setup, archiveThe later one wins if set
portsThe later one wins if set
envKey by key; the later one wins
services, agents, flowsBy name or id: a later one replaces, new ones are added
hooksAdded up: the file's, the kit's, then the box's

Only the effective flows run: a flow replaced by id never does, and a replacement with enabled: false switches the flow off on that box. GET /v1/flows lists every layer's flows, with overridden: true on the replaced ones.

berth location config BOX/LOC prints all three and the result.

kit.json

FieldTypeMeaning
idstringRequired. [a-z0-9][a-z0-9-]*, at most 48 characters.
namestringDefault: the id.
descriptionstring
versionstringShown, and compared to flag projects running an older one.
matchobjectslug: the owner/repo it is for. Selects matching projects in the app; nothing enforces it.
requiresarray{ "tool": "psql", "hint": "how to install it" }. A missing tool is a warning when the kit is applied.
configobjectA .berth/config.json, validated by the same rules.
filesobjectSmall files inline, { "scripts/setup.sh": "…" }. Paths stay inside the kit.

A kit's files are copied to each box it is applied to, and $BERTH_KIT_DIR points at them. Files starting with #! are made executable. See kits.

Task templates

~/.berth/templates/<id>.json on the laptop:

FieldTypeMeaning
idstringDefault: the file's name without .json.
namestringShown in the New worktree dialog.
descriptionstring
box, locationstringWhere the dialog starts.
agentstringA preset id.
commandstringRun instead of a preset.
branch, basestringThe branch (with {{name}} and variables) and what it starts from.
promptstringThe first prompt, with variables.
variablesarray{ "id", "label", "default", "multiline" } for each {{var}}.

See task templates.

Box files

In ~/.berth/ on a box:

FileShapeWhat it is for
hooks.json{ "hooks": [Hook] }Hooks for the box
flows.json{ "flows": [Flow] }Flows for any project on the box
env.json{ "env": { "KEY": "value" } }Environment for every worktree on the box, under each project's own; values may be secret references. OP_* keys reach op.
guard.json{ "enabled", "memory_percent", "sustain", "stop_services", "pause_agents" }The resource guard
plugins/<id>/berth-plugin.jsonA plugin manifestIts hooks run on the box too

Changing env, flows, the guard or a location's config through the API runs before:config.change gates and announces config.changed. Where every file lives is in files and environment.

On this page