# A database per branch for parallel agents

URL: https://briq.cloud/docs/guides/database-per-branch

> Give each git worktree its own fork of your stack, data included, made with the branch and destroyed with it.

Agents working in parallel on one repository each need a database they can migrate without
breaking the others. Fork your main stack for each branch: every worktree gets a copy of the data
and its own env file.

```bash
briq fork --stack main --branch feat/login --env .env.local --expose
```

1. Every briq of `main` is forked into a new stack, `feat-login`, with its data.
2. `--expose` makes the fork reachable from your machine: its databases over TLS, its web
   services at private URLs.
3. `.env.local` gets the fork's outputs (`DATABASE_URL`, `REDIS_URL`…), pointing there. Its other
   lines are kept, so `pnpm dev` in the worktree runs against the fork.
4. `briq destroy --branch feat/login` destroys the fork and its endpoints when the branch is done.

## Prepare main

* Fork main while it sleeps or is stopped: the copies are then of one moment, and the fork does
  not wake it. See [Forks](https://briq.cloud/docs/concepts/fork#a-stack-at-one-moment).
* Make main once, from the repo's [stack file](https://briq.cloud/docs/stack-file) (`briq up`) or with `briq run`.
* Keep seed or staging data in it, never production: every fork copies all of it.
* Add `.env.local` to `.gitignore`: it holds passwords, and git refuses to remove a worktree
  with untracked files.
* Sign the [CLI](https://briq.cloud/docs/cli) in once: `briq login`. Where no one can open a link (CI, a server),
  export `BRIQ_API_KEY` instead.

## With git: a post-checkout hook

`git worktree add` runs `post-checkout` with the null commit as the previous `HEAD`. The hook
forks only then, not on every checkout. Worktrees share the repository's hooks, so install it once.

```sh title=".git/hooks/post-checkout"
#!/bin/sh
# Fork the main stack for a new worktree's branch.
[ "$1" = 0000000000000000000000000000000000000000 ] || exit 0
branch=$(git rev-parse --abbrev-ref HEAD)
case "$branch" in HEAD | main) exit 0 ;; esac
briq fork --stack main --branch "$branch" --env .env.local --expose
```

```bash
chmod +x .git/hooks/post-checkout
git worktree add ../app-login -b feat/login    # forks main into feat-login
git worktree remove ../app-login && briq destroy --branch feat/login
```

Git runs no hook when a worktree is removed: destroy the fork in the same command.

## With Claude Code: WorktreeCreate and WorktreeRemove

Claude Code runs `WorktreeCreate` instead of its own `git worktree add` (`claude --worktree`, a
subagent with `isolation: "worktree"`), and `WorktreeRemove` when it removes that worktree. The
first hook makes the worktree and forks; it prints the worktree's path last, on stdout.

```sh title=".claude/hooks/briq-worktree-create.sh"
#!/bin/sh
set -e
input=$(cat)
name=$(printf '%s' "$input" | jq -r .name)
root=$(git -C "$(printf '%s' "$input" | jq -r .cwd)" rev-parse --show-toplevel)
dir="$root/.claude/worktrees/$name"
branch="worktree-$name"
# without git's hooks: the fork is made here, once
git -C "$root" -c core.hooksPath=/dev/null worktree add -b "$branch" "$dir" >&2
# a refused fork still leaves a worktree: say so, and hand it back
(cd "$dir" && briq fork --stack main --branch "$branch" --env .env.local --expose >&2) ||
  echo "briq: no fork for $branch; run briq fork in $dir" >&2
echo "$dir"
```

```sh title=".claude/hooks/briq-worktree-remove.sh"
#!/bin/sh
dir=$(jq -r .worktree_path)
branch=$(git -C "$dir" rev-parse --abbrev-ref HEAD)
main=$(git -C "$dir" rev-parse --path-format=absolute --git-common-dir)/..
git -C "$main" worktree remove "$dir" >&2 || exit 1
briq destroy --branch "$branch" >&2 || echo "briq: destroy stack $branch yourself" >&2
```

```json title=".claude/settings.json"
{
  "hooks": {
    "WorktreeCreate": [
      { "hooks": [{ "type": "command", "command": "sh .claude/hooks/briq-worktree-create.sh" }] }
    ],
    "WorktreeRemove": [
      { "hooks": [{ "type": "command", "command": "sh .claude/hooks/briq-worktree-remove.sh" }] }
    ]
  }
}
```

* Claude Code keeps a subagent's worktree when the subagent finishes, and runs no
  `WorktreeRemove` for it: remove it, and its fork, yourself.
* The remove hook keeps the branch, as Claude Code does.

## Only inside briq

Leave out `--expose` when nothing outside briq uses the fork: an agent that works through
`briq exec`, or an app that runs as a briq of the same stack. The outputs are then the fork's
internal addresses, which only the briqs of its stack reach, and nothing gets a hostname on the
internet.

```bash
briq fork --stack main --branch feat/login --env .env.briq
```

To expose one database later, see
[Connect to a database from outside](https://briq.cloud/docs/guides/connect-to-a-database-from-outside).

## When it does not fork

| The CLI says                                                        | Fix                                                                       |
| ------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| `invalid_state: a briq named db already exists in stack feat-login` | The branch has a fork. Use it, or `briq destroy --branch <branch>` first  |
| `invalid_state: briq … is stopping`                                 | A briq of main is mid-move. Fork again once it lands                      |
| `quota_exceeded`, `payment_required`, `plan_limit`                  | A fork counts as new briqs and new disk. Destroy forks of merged branches |

## Good to know

* One fork per branch at a time. The stack is named after the branch (`feat/Login_v2` →
  `feat-login-v2`), with a hash of the branch added when another stack has that name.
* `--branch` names the stack after the branch on both `fork` and `destroy`.
* An agent connected over MCP forks the same way: `briq_fork({ stack: "main", into: "feat-login" })`.
* A fork sleeps when unused and keeps its disk until it is destroyed.
* `--env` replaces only the keys it writes. A new file is readable by you only.
