Claude Code remote setup for Laravel
When you use Claude Code on the web, your code runs in a sandboxed VM that starts fresh each session. The VM is configured for typical dev workflows, but won't have everything your project needs.
At InterNACHI, we use the SessionStart hook to automatically provision Claude VMs
in a way that doesn't slow the process down too much…
The setup script
You'll need a script for Claude to run in your project. Here's the minimal shell:
1#!/bin/bash 2set -euo pipefail 3 4# Only run in remote Claude Code environments 5if [ "${CLAUDE_CODE_REMOTE:-}" != "true" ]; then 6 exit 0 7fi 8 9# Run in the background so the session starts immediately10echo '{"async": true, "asyncTimeout": 300000}'11 12# Ensure our 'sentinel' file is missing13SENTINEL_FILE="/tmp/.claude-vm-setup-complete"14rm -f "$SENTINEL_FILE"15 16# Do whatever your project needs to set up the VM17# ...18 19# Signal that setup is done by touching the 'sentinel' file20touch "$SENTINEL_FILE"
From here, install whatever your project needs. In our case, we set up composer and php extensions:
1# Install Composer if missing 2if ! command -v composer &> /dev/null; then 3 EXPECTED_CHECKSUM="$(php -r 'copy("https://composer.github.io/installer.sig", "php://stdout");')" 4 php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" 5 ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")" 6 7 if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]; then 8 echo 'ERROR: Invalid composer installer checksum' >&2 9 rm composer-setup.php10 exit 111 fi12 13 php composer-setup.php --quiet --install-dir=/usr/local/bin --filename=composer14 rm composer-setup.php15fi16 17cd "$CLAUDE_PROJECT_DIR"18 19# Install missing PHP extensions20PHP_VERSION="$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')"21MISSING_EXTS=()22for ext in gmp; do23 if ! php -m 2>/dev/null | grep -qi "^${ext}$"; then24 MISSING_EXTS+=("php${PHP_VERSION}-${ext}")25 fi26done27if [ ${#MISSING_EXTS[@]} -gt 0 ]; then28 apt-get update -qq29 apt-get install -y -qq "${MISSING_EXTS[@]}"30fi
Then we set up our environment files for the VM:
1if [ ! -f .env ]; then2 cp .env.example .env3 sed -i 's/^CACHE_DRIVER=.*/CACHE_DRIVER=file/' .env4 sed -i 's/^SESSION_DRIVER=.*/SESSION_DRIVER=file/' .env5 sed -i 's/^QUEUE_CONNECTION=.*/QUEUE_CONNECTION=sync/' .env6 php artisan key:generate --no-interaction7fi
Then we install dependencies:
1composer install --no-interaction --no-progress2yarn install --frozen-lockfile --non-interactive
Once your script is good to go, make it executable:
1chmod +x bin/setup-claude-vm.sh
And then register the hook in your project's .claude/settings.json file:
1{ 2 "hooks": { 3 "SessionStart": [ 4 { 5 "matcher": "startup", 6 "hooks": [ 7 { 8 "type": "command", 9 "command": "\"$CLAUDE_PROJECT_DIR\"/bin/setup-claude-vm.sh"10 }11 ]12 }13 ]14 }15}
Commit this to your repo. $CLAUDE_PROJECT_DIR is provided by Claude Code and
points to your project root.
When to wait
Because the script runs asynchronously, there's a window where the session is active
but dependencies aren't installed yet. You can tell Claude Code about this in your
main CLAUDE.md file. Something like:
1## Remote VM Setup2 3The `SessionStart` hook (`bin/setup-claude-vm.sh`) runs asynchronously when a4remote session starts. Before running tests, linters, or any command that depends5on project dependencies, wait for setup to finish:6 7 if [ "$CLAUDE_CODE_REMOTE" = "true" ]; then8 while [ ! -f /tmp/.claude-vm-setup-complete ]; do sleep 2; done9 fi
It's not absolutely necessary, but can help Claude know when to wait for the setup to complete.
Have Claude do it for you…
If you want Claude to set this up for you, feel free to append .md to the end of this
URL to get this article in agent-friendly markdown :)