Conductor is a Mac app that lets you run multiple coding agents in parallel. If you've been using Claude Code or similar AI coding assistants, Conductor takes things to the next level by managing isolated workspaces where agents can work independently without stepping on each other's toes.
I've been using Conductor with my Laravel projects for a while now, and I've landed on a simple workflow that makes spinning up new workspaces pretty much effortless. Here's how I do it.
At the heart of Conductor's integration is a simple conductor.json file that lives in the root of your project:
{"scripts": {"setup": "bash scripts/setup.sh","run": "bash scripts/run.sh","archive": "bash scripts/archive.sh"}}{"scripts": {"setup": "bash scripts/setup.sh","run": "bash scripts/run.sh","archive": "bash scripts/archive.sh"}}
This file defines three lifecycle scripts that Conductor calls at different points:
The beauty of this approach is that it's just shell scripts. No special DSL to learn, no complex configuration format. If you can write a bash script, you can configure Conductor.
The setup script is the workhorse. It takes a fresh clone of your repository and turns it into a fully working development environment. Here's mine:
#!/usr/bin/env bashset -e# Copy .env from Conductor root (contains all secrets and config)# Falls back to .env.example if no root .env existsif [ -n "$CONDUCTOR_ROOT_PATH" ] && [ -f "$CONDUCTOR_ROOT_PATH/.env" ]; thencp "$CONDUCTOR_ROOT_PATH/.env" .envset -a && source .env && set +aelsecp .env.example .envfibranch=$(basename "$PWD")site=$(basename "$(dirname "$PWD")" .dev)site_name="${site}-${branch}"sed -i '' "s|^APP_URL=.*|APP_URL=https://${site_name}.test|" .envherd link "$site_name"herd isolate 8.4 --site="$site_name"herd secure "$site_name"herd restartherd composer config http-basic.nova.laravel.com "${NOVA_EMAIL}" "${NOVA_LICENSE_KEY}"herd composer install --no-interaction --prefer-dist --optimize-autoloaderherd php artisan key:generaterm -f database/database.sqlitetouch database/database.sqliteherd php artisan migrate --seednpm installnpm run build#!/usr/bin/env bashset -e# Copy .env from Conductor root (contains all secrets and config)# Falls back to .env.example if no root .env existsif [ -n "$CONDUCTOR_ROOT_PATH" ] && [ -f "$CONDUCTOR_ROOT_PATH/.env" ]; thencp "$CONDUCTOR_ROOT_PATH/.env" .envset -a && source .env && set +aelsecp .env.example .envfibranch=$(basename "$PWD")site=$(basename "$(dirname "$PWD")" .dev)site_name="${site}-${branch}"sed -i '' "s|^APP_URL=.*|APP_URL=https://${site_name}.test|" .envherd link "$site_name"herd isolate 8.4 --site="$site_name"herd secure "$site_name"herd restartherd composer config http-basic.nova.laravel.com "${NOVA_EMAIL}" "${NOVA_LICENSE_KEY}"herd composer install --no-interaction --prefer-dist --optimize-autoloaderherd php artisan key:generaterm -f database/database.sqlitetouch database/database.sqliteherd php artisan migrate --seednpm installnpm run build
Let's break this down:
if [ -n "$CONDUCTOR_ROOT_PATH" ] && [ -f "$CONDUCTOR_ROOT_PATH/.env" ]; thencp "$CONDUCTOR_ROOT_PATH/.env" .envset -a && source .env && set +aelsecp .env.example .envfiif [ -n "$CONDUCTOR_ROOT_PATH" ] && [ -f "$CONDUCTOR_ROOT_PATH/.env" ]; thencp "$CONDUCTOR_ROOT_PATH/.env" .envset -a && source .env && set +aelsecp .env.example .envfi
This is where the magic happens. Conductor provides a $CONDUCTOR_ROOT_PATH variable that points to the project root - one level above your workspace. We keep a fully-configured .env file there with all our secrets, database settings, and API keys. The script copies it into the workspace, then sources it so variables like NOVA_EMAIL and NOVA_LICENSE_KEY are available for the rest of the script.
If you haven't set up a root .env yet, it falls back to .env.example so things don't blow up.
This is where it gets interesting:
branch=$(basename "$PWD")site=$(basename "$(dirname "$PWD")" .dev)site_name="${site}-${branch}"sed -i '' "s|^APP_URL=.*|APP_URL=https://${site_name}.test|" .envbranch=$(basename "$PWD")site=$(basename "$(dirname "$PWD")" .dev)site_name="${site}-${branch}"sed -i '' "s|^APP_URL=.*|APP_URL=https://${site_name}.test|" .env
Conductor creates workspaces in a structured directory like ~/conductor/workspaces/projectname/branchname. We use this structure to automatically generate unique site names for Laravel Herd.
So if you're working on a branch called feature-invoices in the pushsilver project, you'd get a site at https://pushsilver-feature-invoices.test. Each workspace gets its own domain, SSL certificate, and clean isolation. Pretty slick.
The sed command updates the APP_URL in .env to match, so Laravel generates correct URLs everywhere.
herd link "$site_name"herd isolate 8.4 --site="$site_name"herd secure "$site_name"herd restartherd link "$site_name"herd isolate 8.4 --site="$site_name"herd secure "$site_name"herd restart
We link the site, isolate it to a specific PHP version (8.4 in this case), secure it with SSL, and restart Herd. The isolate command is super useful when different projects need different PHP versions.
herd composer config http-basic.nova.laravel.com "${NOVA_EMAIL}" "${NOVA_LICENSE_KEY}"herd composer install --no-interaction --prefer-dist --optimize-autoloaderherd composer config http-basic.nova.laravel.com "${NOVA_EMAIL}" "${NOVA_LICENSE_KEY}"herd composer install --no-interaction --prefer-dist --optimize-autoloader
If you're using Laravel Nova or other private Composer repositories, configure authentication first. The credentials come from your root .env file. We use herd composer instead of just composer to ensure we're using the isolated PHP version. The --no-interaction flag is important because this runs unattended.
herd php artisan key:generateherd php artisan key:generate
Generate a fresh application key for encryption. Standard Laravel stuff.
rm -f database/database.sqlitetouch database/database.sqliteherd php artisan migrate --seedrm -f database/database.sqlitetouch database/database.sqliteherd php artisan migrate --seed
I use SQLite for Conductor workspaces. It's simple, requires no external services, and each workspace gets its own isolated database. We remove any existing database file first to ensure a clean slate, then create a fresh one and run migrations. Easy.
npm installnpm run buildnpm installnpm run build
Install Node dependencies and build the assets. I run build rather than dev during setup so the workspace is immediately usable. You don't want to wait around for Vite to spin up just to verify things are working.
The run script starts your development servers:
#!/usr/bin/env bashset -enpx concurrently -k \-n "queue,schedule,logs,vite" \-c "#93c5fd,#c4b5fd,#fb7185,#fdba74" \"herd php artisan queue:listen --tries=1 --timeout=0" \"herd php artisan schedule:work" \"herd php artisan pail --timeout=0" \"npm run dev"#!/usr/bin/env bashset -enpx concurrently -k \-n "queue,schedule,logs,vite" \-c "#93c5fd,#c4b5fd,#fb7185,#fdba74" \"herd php artisan queue:listen --tries=1 --timeout=0" \"herd php artisan schedule:work" \"herd php artisan pail --timeout=0" \"npm run dev"
I use concurrently to run multiple processes at once. Here's what each one does:
--tries=1 to fail fast during development)The -n flag gives each process a name, and -c assigns hex colors so you can tell them apart in the output. The -k flag ensures all processes are killed when you stop the script.
Note that I don't run php artisan serve here - Laravel Herd handles the web server. Herd is already serving my app at the .test domain we configured in setup.
When you're done with a workspace, the archive script cleans up:
#!/usr/bin/env bashset -e# Derive site name (same logic as setup.sh)branch=$(basename "$PWD")site=$(basename "$(dirname "$PWD")" .dev)site_name="${site}-${branch}"# Unsecure and unlink from Laravel Herdif herd links | grep -q "$site_name"; thenherd unsecure "$site_name" 2>/dev/null || trueherd unlink "$site_name"fi#!/usr/bin/env bashset -e# Derive site name (same logic as setup.sh)branch=$(basename "$PWD")site=$(basename "$(dirname "$PWD")" .dev)site_name="${site}-${branch}"# Unsecure and unlink from Laravel Herdif herd links | grep -q "$site_name"; thenherd unsecure "$site_name" 2>/dev/null || trueherd unlink "$site_name"fi
This removes the site from Herd, cleaning up the SSL certificate and the symlink. The 2>/dev/null || true bit ensures the script doesn't fail if the site was never secured in the first place.
With these scripts in place, the workflow is dead simple:
Create a new workspace in Conductor for whatever I'm working on. Conductor clones my repo into an isolated directory and runs the setup script.
Wait a minute while dependencies install, the database seeds, and Herd gets configured.
Start coding. The agent has a fully working Laravel app to work with. Database, queues, assets - everything is ready to go.
Run the dev servers when I need to see changes live. Conductor shows me the output from the queue, logs, and Vite all in one place.
Archive when done. Conductor cleans up the Herd configuration and I can delete the workspace.
But the real power shows when you're running multiple agents in parallel. Each one gets its own workspace, its own database, its own Herd site. They can all be working on different features without stepping on each other.
MySQL and Postgres are great, but for AI-assisted development in isolated workspaces, SQLite just removes a lot of complexity. No need to create databases, manage users, or worry about connection limits. Each workspace is completely self-contained.
Here's the catch with automated setup scripts: you need API keys and tokens, but you can't commit them to the repo. The solution is to keep a complete .env file at your project root that gets copied into each workspace.
Conductor provides a $CONDUCTOR_ROOT_PATH environment variable that points to the project root - one level above your workspace. The directory structure looks like this:
$CONDUCTOR_ROOT_PATH/├── .env <-- your complete config with secrets├── main/ <-- workspace├── feature-invoices/ <-- workspace└── fix-bug/ <-- workspace$CONDUCTOR_ROOT_PATH/├── .env <-- your complete config with secrets├── main/ <-- workspace├── feature-invoices/ <-- workspace└── fix-bug/ <-- workspace
Create a .env file at your project root with all your settings:
# $CONDUCTOR_ROOT_PATH/.envAPP_NAME=MyAppAPP_ENV=localAPP_DEBUG=trueAPP_URL=https://placeholder.testDB_CONNECTION=sqliteNOVA_EMAIL=your@email.comNOVA_LICENSE_KEY=your-license-keyTORCHLIGHT_TOKEN=tok_your_actual_tokenSTRIPE_SECRET=sk_test_...# $CONDUCTOR_ROOT_PATH/.envAPP_NAME=MyAppAPP_ENV=localAPP_DEBUG=trueAPP_URL=https://placeholder.testDB_CONNECTION=sqliteNOVA_EMAIL=your@email.comNOVA_LICENSE_KEY=your-license-keyTORCHLIGHT_TOKEN=tok_your_actual_tokenSTRIPE_SECRET=sk_test_...
Then copy and source it at the start of your setup script:
if [ -n "$CONDUCTOR_ROOT_PATH" ] && [ -f "$CONDUCTOR_ROOT_PATH/.env" ]; thencp "$CONDUCTOR_ROOT_PATH/.env" .envset -a && source .env && set +aelsecp .env.example .envfiif [ -n "$CONDUCTOR_ROOT_PATH" ] && [ -f "$CONDUCTOR_ROOT_PATH/.env" ]; thencp "$CONDUCTOR_ROOT_PATH/.env" .envset -a && source .env && set +aelsecp .env.example .envfi
The set -a makes all variables exported automatically, so things like NOVA_EMAIL become available to the rest of your script. The setup script updates the APP_URL after copying, so each workspace gets its own unique domain. Everything else - database settings, API keys, feature flags - comes straight from your root .env.
This approach is dead simple: maintain one .env file per project, and every workspace inherits it automatically.
If someone runs the setup script twice, it shouldn't break things. Use commands that can be safely re-run, like touch for creating files that might already exist, or add checks before destructive operations.
Your scripts should create an environment where an AI agent can be productive. That means:
The goal is zero human intervention between cloning the repo and having a working app.
Conductor has changed how I work with AI coding assistants. Instead of one agent making changes to my main development environment, I can have multiple agents working in parallel on completely isolated copies of my project. Honestly, it feels like having a small team of developers who each get their own machine.
The conductor.json configuration is intentionally simple. It's just three shell scripts that do exactly what you'd do manually when setting up a new development environment. The difference is that now it's automated, repeatable, and happens in seconds.
If you're using Laravel Herd (and you really should be), the integration is particularly smooth. Each workspace gets its own domain and SSL certificate automatically. No more juggling Valet configurations or remembering which port each project is running on.
Give it a try. Set up your conductor.json, write your scripts, and let the agents do their thing. I think you'll be surprised how much smoother things get.