mrkoopie/laravel-ai-harness
Laravel AI Harness gives your app one testable interface to AI providers: swap drivers, manage prompts, call tools, and assert on responses in tests. It hides provider quirks behind familiar Laravel patterns so AI features stay clean, mockable, and easy to ship.
Architecture fit. Laravel AI Harness is a dev-only Composer dependency plus a CLI (./.ai-harness for project installs, ai-harness for global installs). It has no production runtime footprint — no migrations, no service provider surface described, no request-path code — so it does not alter the application architecture. It bundles two distinct concerns that a TPM should track separately:
| Concern | Blast radius | Risk profile |
|---|---|---|
AI assistant context/config generation (Claude settings.local.json/CLAUDE.local.md, Codex AGENTS.override.md + local env) |
Developer tooling, repo-adjacent files | Low — additive, per-developer |
| Local runtime & site orchestration (Herd, Valet, Yerd 2.x, Sail, native PHP, cloud) | Developer machines, local sites, PHP selection, HTTPS | Medium — mutates local environment, creates and cleans up "harness-owned" sites |
That coupling is the main architectural question: the AI-config half is trivially reversible, the runtime half touches state outside the repo.
Integration feasibility. Feasible and well-documented. The release ships an upgrade guide, a doctor verification command, and an explicit recovery path for the failure case. Two supported topologies now exist (per-project and global Composer), which improves ergonomics but doubles the configuration-matrix an adopting team must standardize on.
Technical risk. Elevated for this specific release, not for the package overall:
.ai-harness.config.global, .ai-harness.config.local, and the primary checkout's personal files are inherited by linked worktrees. One stale key in one personal file can break composer require across every branch and worktree that developer touches. This is the single highest-risk characteristic of the release.--no-scripts unblocks the install but skips all Composer scripts, including unrelated project scripts. Recovery requires a manual follow-up audit.^0.5 does not include 0.6.0 (correct for 0.x semantics), which means teams floating a caret constraint will silently stay behind rather than break — and teams that do upgrade accept that further minor releases may break config again.https:// (cookie Secure flags, hardcoded redirect URIs, OAuth callbacks) may behave differently.^0.5 requires un-renaming the keys, so a failed rollout cannot be undone by a Composer command alone.Positive signals: 325 tests / 1,455 assertions, CI across PHP 8.2–8.5, ShellCheck, static analysis, and seven regression tests specifically covering the removed-key failure mode. Test coverage is proportionate to the risk introduced.
Key questions.
https:// for Herd sites, given the new HTTP-URL behavior when HTTPS is disabled?--no-scripts would skip, and what is the recovery procedure if we need that flag?.ai-harness.config.local and local_env.* values live, and are they excluded from version control in every repository and worktree (not just the primary checkout)?Stack fit. Laravel/PHP 8.2–8.5 and Composer 2. The runtime matrix the package spans is now four execution modes (Herd, Valet, Yerd 2.x, Sail) plus native PHP and cloud, with php_version, site_secure, and service_manager as the shared knobs and sail_services deliberately unchanged. Yerd 2.x is now first-class (runtime commands, PHP selection, HTTPS, worktree hooks, health checks, owned-site cleanup). If the team is homogeneous on one runtime, adoption is simple; if developers are split across runtimes, budget for per-runtime verification.
Migration path. The rename is mechanical and value-preserving — this is the table to circulate verbatim:
| Removed key | Replacement | Note |
|---|---|---|
herd_php |
php_version |
Collapse multiple runtime keys into one value for the selected runtime |
valet_php |
php_version |
"" |
yerd_php |
php_version |
"" |
herd_secure |
site_secure |
"" |
valet_secure |
site_secure |
"" |
yerd_secure |
site_secure |
"" |
services |
service_manager |
sail_services is not renamed |
Files in scope: .ai-harness.config.dist, .ai-harness.config, .ai-harness.config.global, .ai-harness.config.local — in the primary checkout, in every linked worktree's overrides, and in each developer's inherited personal files. Cloud settings and resource ownership state require no change.
Command sequence for project installs (host Composer, not Sail/containerised Composer, for this transition):
composer require --dev 'mrkoopie/laravel-ai-harness:^0.6'
./.ai-harness update
./.ai-harness doctor
./.ai-harness setup
Global-install users repeat the equivalent with composer global require ... and the bare ai-harness binary, run per configured project and per existing worktree.
Compatibility. Breaking for the configuration schema only. No application code, database, or deploy pipeline is affected. Two secondary compatibility notes: (a) ^0.5 will not resolve to 0.6.0, so the constraint must be changed explicitly; (b) Herd sites with HTTPS disabled now present as http://, which can surface as local-only auth/cookie/redirect anomalies that look like application bugs.
Sequencing. Recommend a four-stage rollout:
require → update → doctor → setup chain and deliberately verify the recovery path (--no-scripts → rename → resume) on a throwaway clone. Confirm https/http behavior for the pilot's Herd sites.composer operations so nobody hits the hook mid-migration. Land the shared config rename + Composer files + refreshed managed files in one commit; each collaborator migrates personal files individually and refreshes worktrees. Global-mode users do their own pass.doctor green on every repo/worktree, plus a short onboarding doc capturing the chosen topology, the rename table, and the --no-scripts recovery recipe.Ordering matters: rename before Composer, always. Doing it the other way converts a mechanical edit into an incident.
Maintenance. Treat the harness config schema as a public interface you own. Pre-1.0, expect further renames in minor releases; the no-alias policy is a deliberate design stance, so plan a recurring review of the changelog rather than a set-and-forget dependency. Assign one owner for the dependency and a cadence (e.g. quarterly or on security/dev-tooling triggers). Pin the version explicitly and bump deliberately — floating a ^0.6 constraint trades predictability for convenience.
Support. Support load is developer-facing, not customer-facing, which keeps severity low but volume non-trivial during rollout. Two artifacts do most of the work: the rename table above and a one-page "composer hook failed" runbook. The two-install-topology split will generate repeat questions unless the team picks one and documents it. Upstream documentation quality is good (dedicated upgrade guide with inheritance and recovery examples), which reduces bespoke internal docs.
Scaling. Cost scales linearly with developers × repositories × worktrees, and the runtime matrix (3 site runtimes × PHP 8.2–8.5 × 2 install modes) multiplies the verification surface. Worktree inheritance is a genuine productivity win but concentrates risk: a single developer's stale personal file propagates into every worktree derived from that checkout. For teams with heavy worktree usage, treat personal-file hygiene as part of the upgrade checklist, not an afterthought. Global installs scale well for onboarding (install once, init --global per project) but introduce version skew across projects pinned at different versions.
Failure modes.
| Failure | Symptom | Mitigation |
|---|---|---|
| Stale removed key in any config file | Composer refresh hook or harness command aborts | Pre-upgrade inventory across repos, worktrees, personal and global files |
| Upgrade attempted before rename | Install blocked mid-require |
Use --no-scripts, rename all seven keys, re-run update/doctor/setup |
--no-scripts used as recovery |
Unrelated project Composer scripts silently skipped | Audit and re-run skipped scripts manually afterward |
| Rollback to 0.5.x after renaming | Config no longer valid for the old version | Branch/snapshot before migrating; un-rename keys to roll back |
| Mixed global + project installs | Version skew, divergent config filenames, confusing bug reports | Standardize on one topology per repository |
| Herd HTTPS disabled | Local URLs switch to http://; auth/cookie/redirect oddities |
Verify local OAuth callbacks, Secure cookie flags, hardcoded URLs |
| Harness-owned site cleanup | A local site a developer expected to persist is removed | Confirm ownership semantics in the pilot before team rollout |
Ramp-up. Low for individual developers using an already-configured install (commands are update/doctor/setup, and doctor gives self-service feedback). Moderate for the person owning the upgrade — the work is not technically hard but is coordination-heavy and order-sensitive. Budget roughly 15–30 minutes per developer per repository for the rename and verification, plus additional time per worktree and for anyone on a global install; a two-developer pilot should take under an hour end to end. Because the impact is confined to developer productivity and local environments, a phased rollout with a short Composer freeze is proportionate — full change-control ceremony is not.
How can I help you explore Laravel packages today?