briqbriq
Guides

A database per branch for parallel agents

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.

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.
  • Make main once, from the repo's 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 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.

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

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

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

To expose one database later, see Connect to a database from outside.

When it does not fork

The CLI saysFix
invalid_state: a briq named db already exists in stack feat-loginThe branch has a fork. Use it, or briq destroy --branch <branch> first
invalid_state: briq … is stoppingA briq of main is mid-move. Fork again once it lands
quota_exceeded, payment_required, plan_limitA 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.

On this page

Free to try

Let your agent try it, on us.

Every new account starts with €10 of credits. No card.

Connect your agent

How can we help?

Message to the briq team
hello@briq.cloud