Parallel Claude Code Sessions with LaborForest

Overview

If you've worked with Claude Code for a while, you've probably seen this message in your terminal:

Tip: Use git worktrees to run multiple Claude sessions in parallel.

If you're already using worktrees to run multiple Claude sessions in parallel, great. You're already familiar with the concepts LaborForest builds upon.

If you're new to git worktrees, below is a surface-level overview:

  • Git worktrees allow multiple branches of the same repository to be checked out in different directories simultaneously
    • The same branch cannot be checked out in multiple worktrees at the same time
  • Git worktrees do not require cloning the same repository more than once
    • You can switch contexts and work on different things in parallel without affecting other branches
  • Git worktrees have been built into Git since 2015, but AI coding agents are greatly popularizing their adoption

Git worktrees in practice

In practice, a development workflow can look something like this:

  1. Create a new branch or check out an existing branch for the feature or bug fix you're working on
  2. Plan your changes and kick off implementation using Claude Code
  3. While Claude Code works, create a new git worktree, on a new or existing branch, for another initiative
  4. In the new worktree's directory, plan your changes and kick off implementation using Claude Code
  5. Repeat steps 3 and 4 as much as you'd like
  6. When changes on a branch within a worktree are complete: commit and push the changes; open a pull request and remove the worktree

This allows you to switch between multiple Claude Code sessions on different branches within the same project, at the same time.

No more stashing changes to check behavior on another branch and no more abandoning current progress to tackle something more urgent.

Pain points

This works great in theory, but there's a part I glossed over above:

What if your repository requires some setup for the local development environment?

For some projects, this can just be a few commands you need to run per new worktree. For other projects, this can be a tedious sequence of steps, time that adds up and takes away from developer velocity.

Yes, you can write setup scripts for each project to address this. However, unless you have significant control over each repository, standardization can be difficult. You can easily end up with a collection of brittle bash spaghetti.

Take, for example, a Laravel project using Herd Pro for services. For each new worktree, you may need to:

  1. create an environment file from the example in the project
  2. update the environment file variables for just this worktree (to maintain isolation)
    1. APP_URL, AWS_BUCKET, DB_DATABASE, REDIS_PREFIX, etc.
  3. create a local S3-compatible bucket for storage using MinIO
  4. create a new MySQL schema
  5. install composer dependencies
  6. install NPM dependencies
  7. build front-end assets
  8. link and secure the site in Laravel Herd
  9. seed the new database with test data

Then of course, when you are done with a worktree, you should tear down these resources too.

Introducing LaborForest

LaborForest is a completely free and open source desktop app for macOS to manage git worktrees and local action workflows.

With LaborForest, all the steps above can become a few clicks. You can easily spin up or tear down local development environments, coupled to git worktrees, and visually keep track of your worktrees and development state of each.

LaborForest in action

The below gif is a demonstration of using LaborForest for a local Laravel project.

The steps taken are:

  1. Create a new workspace for a new branch feature/example, using main as the base branch
  2. Set up a local development environment for the new workspace (LaborForest term for the combination of a worktree and branch)
    1. Observe the sequence of steps executing in realtime via a UI loosely inspired by GitHub Actions
  3. Open a browser using the new environment's APP_URL to confirm the local site loads successfully

2026-08-18-parallel-claude-code-sessions-with-laborforest-demo.gif

An example with Laravel

Let's dive into what was required to record the above gif.

Project assumptions

The demonstration above was with a newly generated Laravel project, configured to match my preferences and setup with Herd.

  • SESSION_DRIVER set to redis
  • QUEUE_CONNECTION set to redis
  • REDIS_PREFIX set to example-laravel-database-
  • AWS_BUCKET set to example-laravel
  • AWS_ACCESS_KEY_ID set to herd
  • AWS_SECRET_ACCESS_KEY set to secretkey
  • AWS_URL set to http://localhost:9000/labor-forest-example-laravel
  • AWS_ENDPOINT set to http://localhost:9000
These settings are not prerequisites for using LaborForest.
You are free to customize your configuration and workflows as needed for your project.

Example workflows

Upon loading a project in LaborForest, a new directory is created at the root of your project: .laborforest. It is up to you if you'd like to commit this directory or ignore it by adding the path to .git/info/exclude.

Workflows are .yaml files placed in the .laborforest/workflows directory within your project. Each .yaml file describes:

  • The status the workspace must be in to allow running the workflow (suspended, ready, or null)
  • The status the workspace will be in upon successful execution of the entire workflow (suspended or ready)
  • Where in the list of workflows this specific workflow should appear (sort order)
  • The list of steps the workflow executes when run

Workflows: up, refresh, and down

The example workflows for a Laravel project, shipped with LaborForest, are below.

You are not limited to using these three workflows. You can have as many custom workflows in LaborForest as you'd like.

  • up.yaml is the workflow used when spinning up a new local development environment for a new workspace
    • copies the .env file from the primary project directory (if workspace is not the primary workspace)
    • updates the .env file with workspace-specific configuration, for isolation (if workspace is not the primary workspace)
    • creates a local S3 bucket (if it doesn't already exist)
    • creates the MySQL schema (if it doesn't already exist)
    • installs composer dependencies
    • installs NPM dependencies
    • builds front-end assets
    • links and secures the Laravel Herd site
    • runs the refresh workflow below
📁
.laborforest/workflows/up.yaml
1resource_type: workflow
2require_status: suspended
3ending_status: ready
4sort_order: 0
5steps:
6 - name: 'Copy .env file from primary project directory'
7 type: shell
8 if: 'test "{{ WORKSPACE_DIR }}" != "{{ PROJECT_PRIMARY_DIR }}"'
9 run: 'cp "{{ PROJECT_PRIMARY_DIR }}/.env" .env'
10 - name: 'Update .env file'
11 type: update_env
12 if: 'test "{{ WORKSPACE_DIR }}" != "{{ PROJECT_PRIMARY_DIR }}"'
13 map:
14 APP_URL: 'https://{{ WORKSPACE_SLUG_KEBAB }}.test'
15 AWS_BUCKET: '{{ WORKSPACE_SLUG_KEBAB }}'
16 DB_DATABASE: '{{ WORKSPACE_SLUG_SNAKE }}'
17 REDIS_PREFIX: '{{ WORKSPACE_SLUG_KEBAB }}-database-'
18 - name: 'Create S3 bucket'
19 type: shell
20 unless: 'aws --endpoint={{ ENV_AWS_ENDPOINT }} s3api head-bucket --bucket {{ ENV_AWS_BUCKET }}'
21 run: 'aws --endpoint={{ ENV_AWS_ENDPOINT }} s3api create-bucket --bucket {{ ENV_AWS_BUCKET }}'
22 env:
23 AWS_ACCESS_KEY_ID: '{{ ENV_AWS_ACCESS_KEY_ID }}'
24 AWS_SECRET_ACCESS_KEY: '{{ ENV_AWS_SECRET_ACCESS_KEY }}'
25 AWS_DEFAULT_REGION: '{{ ENV_AWS_DEFAULT_REGION }}'
26 - name: 'Create MySQL schema'
27 type: shell
28 run: 'mysql -h {{ ENV_DB_HOST }} -P {{ ENV_DB_PORT }} -u {{ ENV_DB_USERNAME }} $([[ -z "{{ ENV_DB_PASSWORD }}" ]] && echo "--skip-password" || echo "-p{{ ENV_DB_PASSWORD }}") -e "CREATE DATABASE IF NOT EXISTS {{ ENV_DB_DATABASE }} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"'
29 - name: 'Install Composer dependencies'
30 type: shell
31 run: 'composer install -v --ansi --no-interaction'
32 - name: 'Install NPM dependencies'
33 type: shell
34 run: 'npm ci'
35 - name: 'Build assets'
36 type: shell
37 run: 'npm run build'
38 - name: 'Link Laravel Herd site'
39 type: shell
40 run: 'herd link --no-interaction --secure {{ WORKSPACE_SLUG_KEBAB }}'
41 - name: 'Refresh application data'
42 type: workflow
43 run: refresh

  • refresh.yaml is the workflow used to reset a local development environment for an existing workspace
    • runs fresh migrations
    • empties the local S3 bucket
    • clears the default queue
    • wipes the Laravel log file
    • runs the database seeder
📁
.laborforest/workflows/refresh.yaml
1resource_type: workflow
2require_status: ready
3ending_status: ready
4sort_order: 1
5steps:
6 - name: 'Run fresh migrations'
7 type: shell
8 run: 'php artisan -vvv migrate:fresh'
9 - name: 'Empty S3 bucket'
10 type: shell
11 if: 'aws --endpoint={{ ENV_AWS_ENDPOINT }} s3api head-bucket --bucket {{ ENV_AWS_BUCKET }}'
12 run: 'aws --endpoint={{ ENV_AWS_ENDPOINT }} s3 rm s3://{{ ENV_AWS_BUCKET }} --recursive --include="*"'
13 env:
14 AWS_ACCESS_KEY_ID: '{{ ENV_AWS_ACCESS_KEY_ID }}'
15 AWS_SECRET_ACCESS_KEY: '{{ ENV_AWS_SECRET_ACCESS_KEY }}'
16 AWS_DEFAULT_REGION: '{{ ENV_AWS_DEFAULT_REGION }}'
17 - name: 'Clear the default queue'
18 type: shell
19 run: 'php artisan queue:clear'
20 - name: 'Wipe logs'
21 type: shell
22 run: 'truncate -s 0 storage/logs/laravel.log'
23 - name: 'Run database seeder'
24 type: shell
25 run: 'php artisan -vvv db:seed'

  • down.yaml is the workflow used to tear down a local development environment for a workspace
    • empties the local S3 bucket (prerequisite for deleting it)
    • deletes the local S3 bucket
    • drops the MySQL schema
    • removes the Laravel Herd site
📁
.laborforest/workflows/down.yaml
1resource_type: workflow
2require_status: ready
3ending_status: suspended
4sort_order: 100
5steps:
6 - name: 'Empty S3 bucket'
7 type: shell
8 if: 'aws --endpoint={{ ENV_AWS_ENDPOINT }} s3api head-bucket --bucket {{ ENV_AWS_BUCKET }}'
9 run: 'aws --endpoint={{ ENV_AWS_ENDPOINT }} s3 rm s3://{{ ENV_AWS_BUCKET }} --recursive --include="*"'
10 env:
11 AWS_ACCESS_KEY_ID: '{{ ENV_AWS_ACCESS_KEY_ID }}'
12 AWS_SECRET_ACCESS_KEY: '{{ ENV_AWS_SECRET_ACCESS_KEY }}'
13 AWS_DEFAULT_REGION: '{{ ENV_AWS_DEFAULT_REGION }}'
14 - name: 'Delete S3 bucket'
15 type: shell
16 if: 'aws --endpoint={{ ENV_AWS_ENDPOINT }} s3api head-bucket --bucket {{ ENV_AWS_BUCKET }}'
17 run: 'aws --endpoint={{ ENV_AWS_ENDPOINT }} s3api delete-bucket --bucket {{ ENV_AWS_BUCKET }}'
18 env:
19 AWS_ACCESS_KEY_ID: '{{ ENV_AWS_ACCESS_KEY_ID }}'
20 AWS_SECRET_ACCESS_KEY: '{{ ENV_AWS_SECRET_ACCESS_KEY }}'
21 AWS_DEFAULT_REGION: '{{ ENV_AWS_DEFAULT_REGION }}'
22 - name: 'Drop MySQL schema'
23 type: shell
24 run: 'mysql -h {{ ENV_DB_HOST }} -P {{ ENV_DB_PORT }} -u {{ ENV_DB_USERNAME }} $([[ -z "{{ ENV_DB_PASSWORD }}" ]] && echo "--skip-password" || echo "-p{{ ENV_DB_PASSWORD }}") -e "DROP DATABASE IF EXISTS {{ ENV_DB_DATABASE }}"'
25 - name: 'Remove Laravel Herd site'
26 type: shell
27 run: 'herd unlink --no-interaction {{ WORKSPACE_SLUG_KEBAB }}'

Claude Code in parallel

With these workflows in place, we can now easily manage our local development environments per workspace.

In a few clicks, we can:

  • create a new workspace
  • spin up the local development environment for the new workspace
  • launch our favorite IDE or Terminal with a working directory of the workspace

This allows us to use Claude Code on different copies of the same project in tandem. While waiting for Claude Code to finish responding to one prompt, you can be prompting in another isolated environment for the same project.

Conclusion

LaborForest is free and entirely open source. You can build from source, or grab the latest release binary for your Mac's architecture on the releases page.

Read the Docs

I encourage you to read the documentation included in the LaborForest repository.


Thanks for reading :)

🤖
Did you spot a mistake in this article? Have a suggestion for how something can be improved? Even if you'd just like to comment or chat about something else, I'd love to hear from you! Contact me.

Syntax highlighting by Torchlight.dev

End of article