GuideAugust 31, 2026

How to Set Up Agent Worktrees Without Port or Database Collisions

File isolation is only useful when every checkout can boot, test, and clean up without borrowing another agent's state.

A new Git worktree isolates repository files, not the environment around them. To run several coding agents reliably, each checkout needs repeatable dependencies, the right ignored configuration, a unique port, and an explicit policy for databases and other mutable services.

Three isolated agent worktrees with separate ports, environment files, and build artifacts

Agentastic runs .agentastic/setup.sh whenever it creates a worktree. This guide builds a safe baseline you can adapt to your stack.

The environment contract#

For every new workspace, answer these questions before the agent starts:

  1. How are dependencies installed?
  2. Which ignored files are copied, generated, or fetched?
  3. Which ports belong to this worktree?
  4. Does it get a database, schema, container, or serialized test lane?
  5. Which generated artifacts must be refreshed?
  6. How can a human rerun and debug setup?

If the answer exists only in a developer's memory, agents will improvise.

Start with an idempotent setup script#

Create .agentastic/setup.sh in the repository and make it executable:

bash
mkdir -p .agentastic touch .agentastic/setup.sh chmod +x .agentastic/setup.sh

Agentastic supplies these useful values:

VariableMeaning
AGENTASTIC_BRANCHNew worktree branch
AGENTASTIC_BASE_BRANCHSelected base branch
AGENTASTIC_WORKTREE_PATHAbsolute path to the new checkout
AGENTASTIC_MAIN_REPO_PATHAbsolute path to the original repository
AGENTASTIC_COMMITStarting commit
AGENTASTIC_REPO_NAMERepository folder name

The script runs from the new worktree. Agentastic shows its output in the setup task and lets you rerun it.

A practical Node.js example#

bash
#!/usr/bin/env bash set -euo pipefail echo "Preparing $AGENTASTIC_REPO_NAME on $AGENTASTIC_BRANCH" # 1. Copy only the ignored local files this project actually needs. for file in .env .env.local; do source_file="$AGENTASTIC_MAIN_REPO_PATH/$file" if [ -f "$source_file" ] && [ ! -f "$file" ]; then cp "$source_file" "$file" echo "Copied $file" fi done # 2. Install from the committed lockfile. if [ -f pnpm-lock.yaml ]; then pnpm install --frozen-lockfile elif [ -f package-lock.json ]; then npm ci elif [ -f yarn.lock ]; then yarn install --frozen-lockfile fi # 3. Allocate a stable local port from a dedicated range. branch_checksum=$(printf '%s' "$AGENTASTIC_BRANCH" | cksum | awk '{print $1}') app_port=$((4100 + branch_checksum % 700)) cat > .env.agentastic.local <<EOF AGENTASTIC_WORKTREE=1 APP_PORT=$app_port EOF echo "APP_PORT=$app_port" # 4. Generate code only after dependencies and environment exist. if npm run | grep -q 'generate'; then npm run generate fi echo "Setup complete"

The port range is an example, not a universal standard. Reserve a range that does not overlap with normal local services, CI, or other repositories. Your run script must actually read the generated value.

Handle environment files deliberately#

Do not recursively copy every .env* file from the main repository. That can pull production credentials, stale overrides, or files belonging to another package into the worktree.

Prefer one of these patterns:

  • Copy an explicit allowlist of development-only files.
  • Generate .env from a committed .env.example and fetch secrets from your normal secret manager.
  • Write worktree-specific values to a separate ignored file such as .env.agentastic.local.
  • Use container environment configuration for sensitive or highly isolated tasks.

Never commit the copied result. Add generated local files to .gitignore.

Choose a database strategy#

Relative SQLite databases#

If the database file lives inside the repository directory and is ignored, each worktree naturally gets a separate path. Confirm the application does not resolve it back to one global directory.

One Postgres database per worktree#

Create a safe database identifier from the branch name:

bash
safe_branch=$(printf '%s' "$AGENTASTIC_BRANCH" \ | tr '[:upper:]' '[:lower:]' \ | tr -c 'a-z0-9_' '_' \ | cut -c1-40) database_name="${AGENTASTIC_REPO_NAME}_${safe_branch}" echo "DATABASE_NAME=$database_name" >> .env.agentastic.local

Database creation needs credentials and permissions. Keep those operations in a trusted local script or development service rather than granting every agent unrestricted administrative access.

One schema per worktree#

A schema is lighter than a full database, but only if the application and migrations consistently respect the search path. Test cleanup and cross-schema extensions before adopting it.

One container stack per worktree#

For stateful applications, a container-backed Agentastic workspace is often simpler. Give the task its own application process and database service, then remove the runtime when the workspace is discarded.

Serialize shared-state tasks#

Some systems cannot cheaply duplicate their dependencies. In that case, run only one migration or integration-test task at a time. Honest serialization is safer than pretending shared mutable state is isolated.

Prevent package and build-cache surprises#

Each worktree should have its own repository-local dependency directory unless your package manager provides a concurrency-safe global store. Avoid symlinking one live node_modules directory between checkouts.

Use committed lockfiles and deterministic install commands:

  • npm ci
  • pnpm install --frozen-lockfile
  • yarn install --frozen-lockfile
  • uv sync --frozen
  • a new Python virtual environment per worktree

Shared download caches are usually fine. Shared mutable build output is not.

Make setup observable#

Setup failures should be obvious before the coding agent begins reasoning about application code.

Use:

bash
set -euo pipefail echo "Step 1/4: copying local config" echo "Step 2/4: installing dependencies" echo "Step 3/4: generating clients" echo "Step 4/4: preparing services"

Validate syntax locally:

bash
bash -n .agentastic/setup.sh

Test with explicit values in a disposable checkout. Do not use /tmp/test if the script can delete or migrate resources without a unique namespace.

Keep setup fast#

A perfect ten-minute bootstrap encourages people to bypass it. Improve the feedback loop:

  • Use package-manager stores and lockfile installs.
  • Build base container images with slow system dependencies already present.
  • Generate only what the task needs.
  • Keep databases as small development fixtures.
  • Move optional checks out of workspace creation and into a validation task.

Cleanup is part of the design#

Before removing a worktree:

  1. Stop its local processes.
  2. Remove its database, schema, or container if the data is disposable.
  3. Preserve logs or fixtures only when they matter to the pull request.
  4. Remove or archive the Agentastic workspace.
  5. Run git worktree prune only for stale Git metadata, not as a substitute for intentional cleanup.

Agentastic automatically removes the runtime for container-backed workspaces. Local services started by project scripts still need a project-specific shutdown path.

A good setup script is product infrastructure#

Every agent benefits from the same reproducible environment: Claude Code, Codex, Gemini, Cursor, review agents, and your own terminal. Treat setup as part of the repository, test it, and improve it whenever a workspace fails for an environmental reason.

Download Agentastic for macOS or read the complete Setup & Teardown Scripts documentation.