Skip to content

v0.8.0 — one-command install

Choose a tag to compare

@dberry37388 dberry37388 released this 04 Jun 17:00
· 238 commits to main since this release
61b7d2b

One-command install. A new swarm:install orchestrator plus four targeted sub-installers (swarm:install:durable, swarm:install:audit, swarm:install:pulse, swarm:install:examples) cut the read-the-docs-and-hand-wire-five-things ritual down to a single Artisan command, and a curated runnable starter example pack ships so a fresh Laravel app is up and dispatching swarms inside a minute. New concrete LogChannelSwarmAuditSink (the zero-config dev/staging sink the audit installer binds), new BuiltByBerry\LaravelSwarm\Testing\ScriptedAgent provider-free agent base class (the starter examples extend it; make:swarm:agent scaffolds it), and a polished make:swarm:swarm + make:swarm:agent generator pair with topology-aware stubs that match the starter pack. The legacy make:swarm keeps working as a deprecated alias. Getting Started and Advanced Setup docs rewritten around the new install flow. No migration changes. No breaking changes.

Added

  • php artisan swarm:install main interactive installer (#85). New orchestrator command — the single entry point an operator runs after composer require builtbyberry/laravel-swarm. Walks the user through Swarm setup with laravel/prompts (select for the persistence driver choice, confirm for every sub-installer offer), publishes config/swarm.php via a direct file copy (sidestepping vendor:publish's boot-time destination capture so the installer works inside the test harness from #92), seeds the canonical Swarm .env keys (SWARM_PERSISTENCE_DRIVER, SWARM_TOPOLOGY, SWARM_TIMEOUT, SWARM_MAX_AGENT_STEPS, SWARM_AUDIT_FAILURE_POLICY, the four SWARM_CAPTURE_* toggles) plus safe defaults additively to .env and .env.example (operator-overridden values are left untouched; missing keys are appended under a # Laravel Swarm — added by swarm:install header), runs php artisan migrate --force on the database persistence path or scaffolds a LaravelSwarm::ignoreMigrations() call into AppServiceProvider::register() (cache-only path, sentinel-fenced with // swarm:install — cache-only persistence; do not edit between markers so re-runs are no-ops, using the same BODY_INDENT + relaxed-regex pattern InstallAuditCommand established post-#102), warns to stderr via $this->output->getErrorStyle()->writeln(...) when QUEUE_CONNECTION=sync (refuses nothing — mutating config/queue.php is out of scope by design), then offers and dispatches each sub-installer via $this->call('swarm:install:durable', $args) etc., forwarding --no-interaction through. Sub-installer dispatch honors --with-<name> / --without-<name> flags for CI use, defaults to "yes" interactively for audit / examples (and durable when the database persistence driver was chosen), gates swarm:install:pulse on class_exists(\Laravel\Pulse\Pulse::class) so Pulse-absent hosts never see the offer, and forwards --all to swarm:install:examples under --no-interaction so the sub-installer does not refuse its "pass --all or --example" precondition. Closing "you're ready" panel emits a per-step summary plus next-step pointers (swarm:health, make:swarm:swarm, docs/getting-started.md). Idempotent by default — a second --no-interaction run is a byte-for-byte no-op (proven via assertSecondRunIsNoOp() from the #92 harness) for both the database and cache-only persistence paths. --force re-publishes config/swarm.php in place. Eleven feature tests in tests/Installer/InstallCommandTest.php cover the happy path, cache-only scaffold, both idempotency contracts, .env-override preservation, --persistence validation, the sync-queue warning, --with-examples / --with-audit dispatch (verified via on-disk effects of the sub-installers, not output scraping), the Pulse-absent silent skip (via a PulseAbsentInstallCommand subclass that overrides the detection method), and --force overwrite. Registered in SwarmServiceProvider::commands() as BuiltByBerry\LaravelSwarm\Commands\Install\InstallCommand. Documented at the top of the README Installation section as the recommended path; the legacy manual flow is retained as an "Advanced setup" subsection. The full docs/getting-started.md rewrite lands in #93.
  • php artisan swarm:install:pulse sub-installer (#88). New targeted installer that wires up the Laravel Pulse integration without hand-edits. Detects Pulse via class_exists(\Laravel\Pulse\Pulse::class) (no composer show shell-out) and refuses with an actionable copy-paste hint when Pulse is missing (composer require laravel/pulsevendor:publishmigrate). Confirms config/pulse.php is published and refuses with a publish hint when it is not. Inserts the SwarmRuns and SwarmStepDurations recorders inside the existing recorders array via balanced-bracket scan (not regex), fenced with // swarm:install:pulse recorders — managed sentinels. Publishes the stock Pulse dashboard view to resources/views/vendor/pulse/dashboard.blade.php if absent, then injects the <livewire:swarm.runs />, <livewire:swarm.steps />, and <livewire:swarm.audit-outbox /> cards inside a {{-- swarm:install:pulse cards --}} managed block immediately before the closing </x-pulse> tag. Card selection via interactive multiselect (laravel/prompts) or --cards=runs,steps,audit-outbox (with validation that surfaces unknown card names); --no-interaction defaults to all three. Each mutated file is copied to <file>.bak exactly once before the first write — re-running with --force rewrites the managed blocks in place but never clobbers the pre-install backup. Idempotent by default: a clean re-run with no --force detects both managed-block sentinels and exits 0 with no file mutations (proven byte-level by the installer test harness's assertSecondRunIsNoOp()). Registered in SwarmServiceProvider. Documented as the new "Quick Setup" section at the top of docs/pulse.md (manual two-edit instructions retained below for operators who prefer to install by hand). Feature tests in tests/Installer/InstallPulseCommandTest.php cover the refusal-when-Pulse-absent path (using a test-only subclass that overrides the detection method), the refusal-when-config-not-published path, --cards validation, the happy path on a clean skeleton (default cards + recorders + dashboard publication + .bak), --cards=runs,steps restricting the dashboard tags written, default-mode idempotency, and the --force rewrite + .bak-preservation contract.
  • Runnable starter example pack at stubs/examples/ (#89). Three curated, end-to-end runnable starter examples that the upcoming swarm:install:examples command (#90) will copy into a user's app: sequential-blog-pipeline (the three-agent hello world — outline → draft → polish, in-memory prompt()), parallel-research-fanout (three scouts run concurrently on the same task, demonstrating Parallel topology + container-resolvable agents + fan-out / join), and durable-approval-workflow (the showcase — two-step sequential swarm in durable mode with a RoutesDurableWaits checkpoint between the steps, resumed by a policy_decision signal). Each example ships as a complete app/Ai/Swarms/<Name>/, app/Ai/Agents/<Name>/, and app/Console/Commands/SwarmExample<Name>Command.php tree plus a per-example README; the namespace uses a {{ rootNamespace }} placeholder so the installer (#90) can rewrite to the user's App\ namespace. Index lives at stubs/examples/README.md. Each runner registers a swarm:example:<name> artisan command. Smoke tests in tests/Feature/Examples/ render the stubs into a temp directory under a test-only namespace and run them against the real SwarmRunner / DurableSwarmManager so the shipped stubs are proven runnable on every CI pass. Docs published as new docs/examples.md, cross-linked from docs/README.md. The existing 14 read-the-README reference examples under examples/ are unaffected.
  • BuiltByBerry\LaravelSwarm\Testing\ScriptedAgent abstract base class (#89). Runnable, provider-free agent that returns scripted text so starter examples, smoke tests, and "show the shape" demos execute end-to-end without configuring a Laravel AI provider or burning API credit. Subclasses implement instructions() and reply(string $prompt): string; the shipped prompt() wraps the reply in a standard AgentResponse. stream(), queue(), and the three broadcast helpers raise with a clear message pointing callers at the right next step (use a Promptable agent with Agent::fake()). Lives under src/Testing/ alongside SwarmFake and FakeDurableSwarmManager.
  • swarm:install:examples sub-installer (#90). New Artisan command that copies the curated starter example pack (#89) from the package's stubs/examples/ directory into the host Laravel app, rewriting the {{ rootNamespace }} (and legacy {{ namespace }}) placeholder in every PHP file to the host app's PSR-4 root read from composer.json (App\ by default; non-App\ PSR-4 layouts pointed at app/ are detected automatically). Auto-discovers available examples by scanning the bundled stubs directory and reads each one's one-line description from its README.md, so a new starter dropped under stubs/examples/<name>/ shows up in the picker with no installer change required. Interactive mode uses laravel/prompts multiselect() to pick one, several, or every example; CI / scripted use is covered by --example=<name> (repeatable, single-shot), --all (install everything), and --force (overwrite existing files in the host app); --no-interaction requires one of --all or --example, errors loudly otherwise. The full example tree is preserved on copy — app/Ai/Swarms/<Name>/, app/Ai/Agents/<Name>/, and app/Console/Commands/SwarmExample<Name>Command.php — so Laravel 11+ Artisan auto-discovery picks the runner commands up on the next boot without touching routes/console.php. The package-internal stubs/examples/<name>/README.md files are deliberately not copied; they remain reference material inside the package, not noise in the user's app/ tree. Skipping is per-example and additive: if app/Ai/Swarms/SequentialBlogPipeline/BlogPipeline.php already exists, the installer warns and leaves the on-disk file untouched while still installing the other selected examples in the same run. Idempotent by default (a second invocation with no --force is a byte-level no-op on every file in the skeleton). Prints "you can now run" hints with the exact php artisan swarm:example:<name> command for each freshly-installed example. Registered in SwarmServiceProvider; lives under the new src/Commands/Install/ namespace alongside the other v0.8.0 sub-installers. Documented in docs/examples.md as the recommended install path. Tests at tests/Installer/InstallExamplesCommandTest.php exercise discovery, namespace rewriting (default App\ plus a custom Acme\Platform\ PSR-4 root), refusal on existing files, --force overwrite, idempotency double-run, unknown-example rejection, non-interactive flag enforcement, the --all-vs---example mutual exclusion, and the runnable-hint output.
  • make:swarm:swarm and make:swarm:agent generators (#91). Split the v0.7-era single make:swarm generator into two dedicated commands so the generator surface matches the two kinds of class an app actually writes. make:swarm:swarm <Name> scaffolds a swarm class under app/Ai/Swarms/ and accepts --topology=sequential|parallel|hierarchical|static-hierarchical (default sequential; prompts interactively when omitted on a TTY, defaults silently to sequential under Artisan::call() or CI so scripts stay scriptable). make:swarm:agent <Name> is brand new — it scaffolds an agent under app/Ai/Agents/ extending BuiltByBerry\LaravelSwarm\Testing\ScriptedAgent (the same shape the starter examples in stubs/examples/ use), with instructions() and reply() carrying TODO markers pointing at the swap-to-Promptable upgrade path for plugging in a real LLM. Both generators ship publishable stubs (swarm.stub, swarm.parallel.stub, swarm.hierarchical.stub, swarm.static-hierarchical.stub, swarm.agent.stub) under the existing swarm-stubs publish tag and check base_path('stubs/') for a customized copy before falling back to the shipped version. Stubs were rewritten so generated code is visually consistent with the runnable starter examples in stubs/examples/ — same class header docblocks, same agents() return type, same // new \App\Ai\Agents\… placeholder shape. Documented in new docs/generators.md (linked from docs/README.md); docs/sequential.md, docs/parallel.md, docs/static-hierarchical-topology.md, docs/public-surface.md, and the README were updated to use the new commands.
  • swarm:install:audit sub-installer (#87). New targeted installer that wires the audit pipeline into a host application in a single command. Without it, audit users have to discover that the default SwarmAuditSink binding is NoOpSwarmAuditSink (silent discard), write the sink binding by hand, and remember the four optional extension contracts (SwarmAuditSigner, ActorResolver, CapturePolicy, SinkFailureHandler) that turn on the regulated-deployment behaviors. The installer scaffolds a SwarmAuditSink binding into app/Providers/AppServiceProvider::register() behind unique // swarm:install:audit — managed bindings sentinel comments (so re-runs are no-ops), accepts --sink=readable|noop|custom to pick the binding shape (default readable interactively, custom under --no-interaction so CI runs do not silently route evidence to the application log), confirms the swarm_audit_outbox table is present (and offers to run php artisan migrate when it is not, on the database persistence driver), prints the current SWARM_AUDIT_FAILURE_POLICY and SWARM_CAPTURE_* flags with one-line explainers so the operator sees what is being recorded before shipping, and cross-links to swarm:audit:status, swarm:audit:reconcile, and swarm:trace for verification. Three optional flags (--with-signer, --with-actor-resolver, --with-capture-policy) emit additional TODO-marker bindings for regulated deployments. Refuses cleanly when AppServiceProvider is missing or its register() method body cannot be located. Registered in SwarmServiceProvider, with full feature coverage via the installer test harness (tests/Installer/InstallAuditCommandTest.php).
  • php artisan swarm:install:durable sub-installer (#86). Targeted setup command for the durable execution runtime — drops the read-the-docs-and-hand-wire-five-things ritual that durable adopters previously faced. The command (a) verifies swarm.persistence.driver is database and refuses with an actionable error when it is cache, (b) probes the durable runtime tables (swarm_durable_runs, swarm_durable_outbox) and offers to run php artisan migrate --force when they are absent (or warns when --skip-migrate is set), (c) appends a managed scheduler block to routes/console.php registering Schedule::command('swarm:relay')->everyMinute(), swarm:recover (every five minutes), and swarm:prune (daily) — guarded by an idempotency marker (// swarm:install:durable schedule entries — managed; do not edit) and a per-line presence check so it never duplicates entries the user wired by hand, (d) inspects QUEUE_CONNECTION and refuses on sync (bypassable with --allow-sync-queue for local experiments only), and (e) prints copy-paste worker snippets for plain queue:work, the config/horizon.php supervisor queue list, and a Forge/Supervisor .conf block. Flags: --queue=<name> overrides the printed queue name (defaults to the configured swarm.durable.queue.name or the package convention swarm-durable); --migrate/--skip-migrate make the migration step explicit for non-interactive use; --allow-sync-queue opts in to the local-only sync path; --no-interaction skips prompts and warns when migrations are pending. Out of scope by design: installing Horizon, writing to config/queue.php, or spawning worker processes. Ships with a feature test suite under tests/Installer/InstallDurableCommandTest.php (eight tests via the v0.8.0 installer test harness, #92) covering the success path, double-run idempotency, both refusal paths, the sync-queue bypass, the --queue override, missing-tables warning, and the "user already wired schedule entries" merge case. Registered in SwarmServiceProvider::commands() as BuiltByBerry\LaravelSwarm\Commands\Install\InstallDurableCommand; documented in docs/durable-execution.md as the new Quick Setup entry point.
  • BuiltByBerry\LaravelSwarm\Audit\LogChannelSwarmAuditSink concrete sink. Log-channel-backed SwarmAuditSink implementation that writes every audit record as a structured log entry (swarm.audit.<category>) to the configured Laravel log channel (defaults to audit, falls back to the default channel when audit is not configured). Ships as the concrete class the swarm:install:audit --sink=readable installer binds — replacing an earlier draft that mistakenly pointed the binding at the ReadableSwarmAuditSink extension contract (an interface, not instantiable). Implements only SwarmAuditSink, not ReadableSwarmAuditSink, because log channels are not queryable; swarm:trace degrades gracefully when this sink is bound. Lives under src/Audit/ alongside NoOpSwarmAuditSink. Production deployments should still ship a bounded backend (database, queue, SIEM export); this sink is the zero-config dev/staging default.
  • Shared installer command test harness at tests/Installer/ (#92). New BuiltByBerry\LaravelSwarm\Tests\Installer\InstallerTestCase base class that materializes a minimal Laravel-shaped scratch skeleton (config/, routes/console.php, app/Providers/AppServiceProvider.php, .env, composer.json, plus the standard database/, resources/, storage/, bootstrap/, public/, tests/ directories) into a temp directory per test, re-points the booted testbench application at it via $this->app->setBasePath(...) so app_path() / config_path() / base_path() resolve into the fixture, and tears the directory down on tearDown() for full isolation and parallel safety. Ships ergonomic helpers — runInstaller(), assertInstallerFailsWith(), assertFileContains(), assertEnvKey(), assertScheduleEntry(), assertProviderBinding(), writeSkeletonFile(), skeletonPath(), snapshotSkeleton() — plus a fluent idempotency double-run check (runInstaller(...)->twice()->assertSecondRunIsNoOp()) that hashes every file in the skeleton before/after and fails loudly on any byte-level drift. Includes a NoOpInstallerCommand fixture and end-to-end smoke test (tests/Installer/NoOpInstallerSmokeTest.php) plus eleven self-tests covering every helper (tests/Installer/InstallerTestCaseHelpersTest.php). The harness uses lightweight filesystem fixtures only — no new composer require-dev entries beyond the already-present orchestra/testbench. Wired into the default composer test lane and the Installer PHPUnit testsuite; downstream consumers documented in tests/Installer/README.md. Foundational infrastructure for #85, #86, #87, #88, and #90 — no public swarm-runtime surface change.

Changed

  • make:swarm is now a deprecated alias for make:swarm:swarm (#91). Running it continues to produce a swarm class under app/Ai/Swarms/ exactly as before — no shape change, no flag change, no behavior change — but it now prints a deprecation notice on stderr pointing callers at make:swarm:swarm (for swarms) and make:swarm:agent (for agents). Existing scripts, docs, and tutorials keep working. The alias is slated for removal in a future major release; track #91 for the deprecation window.
  • Getting Started and Advanced Setup docs rewritten around swarm:install (#93). New docs/getting-started.md is the canonical new-user landing page: a single-command install via swarm:install, post-install verification with swarm:health, and a five-minute walkthrough of running the sequential-blog-pipeline starter from #89 end-to-end with no API key. New docs/advanced-setup.md preserves the manual flow as a stable appendix — it covers the manual equivalent of every step the installer performs (config publish, env seeding, database vs. cache persistence with the LaravelSwarm::ignoreMigrations() scaffold pattern, scheduler entries for swarm:relay / swarm:recover / swarm:prune, audit sink binding, Pulse recorder + dashboard registration, and copying the starter examples) for environments where the installer cannot run. README Installation section now points at both docs for further reading and at the per-feature Quick Setup sections (swarm:install:durable, swarm:install:audit, swarm:install:pulse, swarm:install:examples) for the targeted sub-installers. Cross-link audit pass added a one-paragraph "swarm:install is the broader entry point" pointer to the top of each Quick Setup section in docs/durable-execution.md, docs/audit-evidence-contract.md, docs/pulse.md, and docs/examples.md. docs/configuration.md now leads with swarm:install and demotes the bare vendor:publish --tag=swarm-config invocation to a manual fallback. docs/README.md index gains entries for both new docs at the top of the Getting Started section. The legacy 6-step bash block in the README is gone — the manual flow lives in docs/advanced-setup.md now. No public-surface change, no migration change, no breaking change.

Full entry in the CHANGELOG.