mrkoopie / laravel-ai-harness
A small Composer tool that gives Codex and Claude a consistent Laravel runtime through Herd, Sail, or native PHP.
Requires
- php: ^8.2
- symfony/console: ^7.4|^8.0
- symfony/process: ^7.4|^8.0
Requires (Dev)
- illuminate/console: ^11.0|^12.0|^13.0
- laravel/pint: ^1.27
- pestphp/pest: ^3.0|^4.0
- phpstan/phpstan: ^2.1
Suggests
None
Provides
None
Conflicts
None
Replaces
None
- dev-main
- v0.3.0
- v0.2.0
- v0.1.9
- v0.1.8
- v0.1.7
- v0.1.6
- v0.1.5
- v0.1.4
- v0.1.3
- v0.1.2
- v0.1.1
- v0.1.0
- dev-feature/herd-cleanup-followup
- dev-feature/cloud-agent-setup
- dev-feature/herd-runtime-cleanup-pruning
- dev-fix/worktree-heal-env-on-recycle
- dev-fix/parallel-default-incompatible-flags
- dev-codex/process-harness-feedback-release
- dev-codex/fix-boost-marker-collision
This package is auto-updated.
Last update: 2026-09-22 12:29:33 UTC
README
Laravel AI Harness is a small Composer development tool that gives Codex and Claude one stable command for Laravel projects running through native PHP, Laravel Herd, or Laravel Sail.
Application lifecycle logic stays in the Composer package. A consuming project receives a tiny .ai-harness bootstrap, an optional cloud provisioning helper, a strict project configuration file, concise agent instructions, and native Codex/Claude lifecycle configuration.
Requirements
- PHP 8.2 or newer.
- Composer 2.2 or newer.
- Bash on macOS, Linux, or WSL for the project bootstrap.
- Optional: Laravel Herd.
- Optional: Laravel Sail and Docker.
Install
Add the package once and initialize the project files:
composer require --dev mrkoopie/laravel-ai-harness ./vendor/bin/ai-harness init
Commit the generated project files. From then on, people and coding agents use:
./.ai-harness doctor
init adds one guarded, package-owned command to Composer's root post-install-cmd and post-update-cmd events. Future Composer installs and updates therefore refresh the managed integration files automatically. Existing project scripts are preserved, and repeated initialization does not add duplicates. The hook exits successfully when Composer runs with --no-dev or the development package binary is unavailable.
Package installation and project refresh are deliberately separate operations:
composer update mrkoopie/laravel-ai-harnessdownloads a newer package release../.ai-harness updaterefreshes the project files from the currently installed release.
For recovery or debugging, run Composer with --no-scripts, then refresh explicitly:
composer update mrkoopie/laravel-ai-harness --no-scripts ./vendor/bin/ai-harness update
When recovering an upgrade from v0.1, use the temporary Artisan compatibility bridge instead so the old configuration and environment choices are migrated before the new project files are created:
composer update mrkoopie/laravel-ai-harness --no-scripts php artisan ai-harness:update --ansi
When vendor/bin/ai-harness is missing, .ai-harness runs composer install --no-interaction --prefer-dist, falling back to herd composer install when Composer is not on PATH. It never adds or updates package requirements. After dependencies exist, the bootstrap executes Composer's vendor/bin/ai-harness proxy.
Project Files
The default installation manages only:
.ai-harness
.ai-harness-cloud # cloud=true: provisioning and lifecycle entrypoint
.ai-harness.config
.gitignore # one managed block
AGENTS.md # one managed block
CLAUDE.md # one managed block
.codex/environments/environment.toml
.claude/settings.json # merges only package-owned hooks
composer.json # two guarded package-owned script entries
The package does not copy runtime executors, database scripts, skills, MCP configuration, or per-agent shell scripts into projects.
Configuration
Configuration is strict key=value data:
runtime=herd services=sail agents=codex,claude sail_services=mysql,redis,mailpit herd_secure=true herd_php=8.4 worktrees=true
Files are loaded from lowest to highest priority:
.ai-harness.config.dist.ai-harness.config.ai-harness.config.local
The local file and harness state file are ignored automatically. Unknown keys, invalid values, duplicate keys within one file, and oversized configuration files fail clearly. Configuration files are parsed as data and are never sourced as shell scripts.
Runtimes
runtime selects where PHP-related commands execute:
| Runtime | Artisan | Composer | PHP | npm |
|---|---|---|---|---|
native |
php artisan |
composer |
php |
npm |
herd |
herd php artisan |
herd composer |
herd php |
npm |
sail |
sail artisan |
sail composer |
sail php |
sail npm |
There is no automatic runtime fallback. doctor reports when the configured runtime is unavailable.
Services
services=sail lets Sail manage supporting containers independently of the PHP runtime. This supports both full Sail projects and Herd PHP with Sail-provided MySQL, Redis, or Mailpit.
An empty sail_services value starts and stops the full stack. A comma-separated list starts only those services; down then uses sail stop for that selected subset. With runtime=sail, the harness always includes Sail's laravel.test application container, even when services=none. The harness never deletes Docker volumes.
When Herd or native PHP uses Sail's MySQL service, DB_PORT follows the standard Sail FORWARD_DB_PORT value in .env (default 3306). Set FORWARD_DB_PORT=3307, for example, when another local MySQL service already uses port 3306. The harness derives a MySQL-safe database name from the checkout path plus a short hash, and uses a _testing suffix for the isolated test database. Names leave room for Laravel's parallel worker suffix within MySQL's 64-character limit. This makes every worktree distinct without querying Git or agent metadata.
Commands
./.ai-harness init
./.ai-harness update
./.ai-harness doctor
./.ai-harness artisan migrate
./.ai-harness composer install
./.ai-harness php -v
./.ai-harness npm run build
./.ai-harness test --filter=ExampleTest
./.ai-harness up
./.ai-harness down
./.ai-harness setup
./.ai-harness cleanup
Runtime arguments are executed as an argument array, not through a shell command string. Options, spaces, and shell metacharacters are forwarded unchanged.
init, update, doctor, setup, cleanup, up, and down accept --path=/path/to/project; runtime commands operate in the current directory.
init and update only synchronize project integration files. They do not install dependencies, start containers, create databases, link Herd sites, run migrations, or inspect or update Git. Environment work happens through setup, cleanup, up, down, and the explicit cloud commands below.
Setup and Cleanup
Outside a detected cloud environment, setup performs predictable local preparation:
- Run Composer install when the target checkout has no
vendor/autoload.php. - Copy
.env.exampleto.envwhen.envis absent. - Configure and normalize MySQL values when Sail manages its
mysqlservice, using127.0.0.1for native or Herd runtime andmysqlfor Sail runtime. Commented database defaults are activated rather than duplicated. - Start configured Sail services and ensure the checkout-specific development and testing databases exist.
- Link the directory in Herd when
runtime=herdand set its path-derived HTTPS URL. - Secure the Herd site and isolate its PHP version when configured.
- Generate
APP_KEYwhen the project has an empty key. - Create
.env.testingwhen absent, using Sail'stestingdatabase for MySQL or isolated SQLite defaults otherwise; update the default SQLite entries inphpunit.xmlto Sail's MySQL testing database.
It does not run migrations, rewrite compose.yaml, or inject test-runner options. It creates only its checkout-specific Sail MySQL databases and updates PHPUnit's selected test database when Sail manages MySQL. cleanup drops only those deterministic, harness-owned databases after validating the recorded Herd site; Codex worktree cleanup then stops the configured Sail services without deleting Docker volumes.
MySQL cleanup also removes this checkout's numeric parallel test databases (including Laravel's _test_1 form), but preserves similarly named databases without a numeric worker suffix and databases belonging to other checkouts. It retains ownership state if database cleanup fails, so cleanup can be retried.
cleanup only removes HTTPS and unlinks a Herd site previously recorded as harness-owned. Before each action, it verifies that the recorded site name is the deterministic name for the current project path. Sail shutdown is always the explicit down command.
Codex
init adds concise runtime instructions to AGENTS.md. With worktrees=true, it also writes one Codex local environment whose setup and cleanup scripts call ./.ai-harness setup and ./.ai-harness cleanup directly. .codex/environments/environment.toml is package-owned and overwritten during each refresh; put custom Codex configuration elsewhere.
There are no duplicate SessionStart fallbacks or Codex-specific executor scripts. Select the generated Laravel AI Harness local environment in Codex when creating a worktree.
Claude Code
init adds concise runtime instructions to CLAUDE.md. With worktrees=true, it merges four package-owned command hooks into .claude/settings.json:
SessionStartprepares an existing Claude worktree.PostToolUsewithEnterWorktreeprepares the worktree reported by Claude.PreToolUsewithExitWorktreecleans the worktree before removal.WorktreeRemovecleans--worktreeand isolated-subagent worktrees before Claude removes them.
Every hook calls .ai-harness hook claude ...; JSON payload parsing and lifecycle logic stay in the Composer package. Existing settings and unrelated hooks are preserved. Disabling worktree automation removes the worktree-specific hooks on the next refresh. SessionStart and SessionEnd remain while cloud automation is enabled; disable both worktrees and cloud to remove all harness hooks.
Cloud Environments
Run ./.ai-harness update in each consuming project and commit the generated
.ai-harness-cloud, .ai-harness, agent instructions, and Claude settings.
The cloud helper can provision system tools before vendor/ exists. Cloud
execution always uses native PHP rather than the project's local Herd/Sail runtime.
Detection and configuration
- Set
AI_HARNESS_ENV=codex-cloudin Codex cloud environment variables. - Claude automatically uses its documented
CLAUDE_CODE_REMOTE=truesignal. SetAI_HARNESS_ENV=claude-cloudin the environment as well when using the provisioning script, which runs before the agent starts. - An explicit
AI_HARNESS_ENV=localoverrides automatic detection. Unknown values fail clearly. Linux, checkout paths, and installed agent binaries do not imply cloud execution.
Cloud options in .ai-harness.config are independent of worktrees:
cloud=true cloud_services=mysql,redis cloud_migrate=false cloud_seed=false cloud_build=false cloud_browser=false
The default service is mysql. Set cloud_services= for SQLite and no managed
services. Redis uses the PHP Redis extension. Migrations are opt-in and run
artisan migrate for development and testing; no migrate:fresh runs. Seeding
requires migrations enabled and invokes the development seeder on every setup,
so enable it only with seeders that are safe to rerun. Builds use npm run build.
Browser installation requires Playwright already declared in project dependencies
and installs Chromium plus its OS dependencies. These options never affect local setup.
Claude cloud
- Set the environment variables above and configure the environment setup script
to run
./.ai-harness-cloud provisionfrom the repository root. This installs system dependencies and benefits from the provider's filesystem cache. - The generated repository
SessionStarthook runs project setup for ordinary cloud clones, including resumes, even withworktrees=false. It installs the current locked dependencies and starts/checks services on every session. - The generated
SessionEndhook performs test-only cleanup with a 60-second timeout. Cleanup is retryable with./.ai-harness cloud cleanup. - Multi-repository Claude sessions do not load repository hooks. Run
./.ai-harness-cloud setupexplicitly in each checkout. Do not rely on a cached provisioning script to restart services.
Claude's setup budget is approximately five minutes. Put system provisioning in the environment setup script and project setup in SessionStart. Package installs need the appropriate registry/archive hosts in the environment network allowlist. See Claude cloud environments and SessionEnd hooks.
Codex cloud
Set AI_HARNESS_ENV=codex-cloud as an environment variable, then configure
these commands in the cloud environment UI, running from the repository root:
# Setup script: system provisioning followed by project preparation.
./.ai-harness-cloud provision
./.ai-harness-cloud setup
# Maintenance script: reconcile the selected branch after restoring a cache.
./.ai-harness-cloud maintain
The generated .codex/environments/environment.toml remains a local worktree
integration; it does not configure the cloud environment UI. Both setup and
maintenance must be wired there. Setup has internet access; dependency refreshes
need network access in the phase where they execute. Install required test tools
before the agent phase if agent internet access is disabled.
Codex environment secrets are setup-only. Use them for private dependency
authentication during setup, and ensure maintenance can reinstall branch-specific
dependencies without assuming those secrets remain available. Do not persist
package credentials in tracked files. No guaranteed Codex cloud teardown hook is
assumed; run ./.ai-harness cloud cleanup explicitly when useful, and allow the
provider to discard its ephemeral container. See
Codex cloud environments.
Preparation and boundaries
- Provisioning requires Ubuntu/Debian, root or passwordless
sudo, and apt access. It selects the distribution's default PHP CLI (minimum 8.2), installs common Laravel extensions, Composer, MySQL, Redis, and missing Node/npm. SetAI_HARNESS_PHP_VERSION=8.4, for example, only if that version exists in the environment's configured apt repositories. Images whose default PHP is older than 8.2 need a compatible image or an explicit available version. The harness never adds third-party apt repositories. Pin Node in the provider image/settings to satisfy the project'senginesrequirement. When present, provisioning usesubuntu.sourcesordebian.sourcesalone, avoiding unrelated image repositories that the cloud proxy may block. SetAI_HARNESS_APT_SOURCE_LISTto an existing absolute source-list path to override that choice. Package signature verification remains enabled. If the image puts phpenv shims first inPATH, select/usr/binfirst in setup and maintenance to use the provisioned PHP and its installed extensions. - Project setup requires a committed
composer.lock, installs development dependencies and runscomposer check-platform-reqs. It does not skip platform requirements. Frontend projects requirepackage-lock.jsonand usenpm ci --include=dev; other package managers need project-specific setup. AI_HARNESS_COMPOSER_PREFER=sourceopts into Git source installs when archive downloads are blocked. It applies to the initial bootstrap too. This is an explicit network workaround, not a blanket fallback or a TLS bypass.- Setup replaces standard Laravel database/Redis connection settings with local
cloud values, clears the default config cache, normalizes
APP_CONFIG_CACHE, and reconciles inline PHPUnit connection overrides. Inherited standard connection variables are removed for harness-run application commands. Custom application connection names/configuration remain the application's responsibility. - MySQL administration uses only the local Unix socket, ignores user option/login
files, and creates a checkout-specific development/testing pair plus a scoped
localhost application user. Its fixed
harnesspassword is for disposable development containers only.AI_HARNESS_MYSQL_SOCKETcan select another absolute local socket; the same socket is written into Laravel configuration. - Cloud cleanup requires recorded ownership, preserves the development database,
and drops only the exact testing name and numeric
<testing>_1/<testing>_test_1worker forms. Similar names, backups and other checkouts are excluded. Ownership stays recorded so failed or repeated cleanup can be retried. - Keep required install failures visible. A passing local suite does not verify a provider's actual image, network allowlist or cache lifecycle: validate a fresh start, cached start and resume in each configured cloud environment.
Laravel Boost
When Laravel Boost is installed in the consuming application, it can discover this package's short guideline at resources/boost/guidelines/core.blade.php. That guideline explains configuration and environment boundaries; the AI Harness managed blocks in AGENTS.md and CLAUDE.md remain the source for command syntax. No Boost dependency or additional project file is required by AI Harness.
Upgrading From 0.1
Version 0.2 retains the old artisan ai-harness:update command and service-provider class for one release so an existing v0.1 Composer hook can complete the upgrade. That compatibility command replaces the old hook with the new guarded ./vendor/bin/ai-harness update hook.
When no .ai-harness.config, .dist, or .local file exists, the bridge translates the old Codex, Claude, Herd, Docker, and PHP-version choices. Old Docker support becomes services=sail with sail_services=mysql. Unsupported skills and Polyscope generation, plus obsolete generated files, produce explicit warnings and are not silently deleted. Existing new-format configuration always wins.
After the first successful refresh, use ./.ai-harness update; the Artisan compatibility command is temporary and may be removed in 0.3.
Git Scope
The harness does not create, remove, update, or select Git branches or worktrees. It never runs git fetch, pull, checkout, switch, branch, rebase, or worktree. Codex or Claude provides the current directory; the harness only prepares that directory.
Development
composer install
composer test
composer format:check
composer analyse
composer shellcheck
composer validate --strict
The test suite covers configuration layering, command mapping, argument-injection resistance, safe managed-file writes, bootstrap recovery, Herd/Sail composition, ownership-checked cleanup, Claude hook payloads, Codex/Claude installation, and the no-Git invariant.