PHPackages                             coding-sunshine/ensemble - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. coding-sunshine/ensemble

ActiveLibrary[API Development](/categories/api)

coding-sunshine/ensemble
========================

AI-native full-stack Laravel code generation. Reads ensemble.json schemas and generates models, migrations, controllers, views, and more.

3.2.0(2mo ago)031↓100%MITPHPPHP ^8.2

Since Nov 6Pushed 2mo agoCompare

[ Source](https://github.com/coding-sunshine/ensemble)[ Packagist](https://packagist.org/packages/coding-sunshine/ensemble)[ Docs](https://github.com/coding-sunshine/ensemble)[ RSS](/packages/coding-sunshine-ensemble/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (2)Dependencies (13)Versions (86)Used By (0)

Laravel Ensemble
================

[](#laravel-ensemble)

AI-native full-stack Laravel code generation. Reads `ensemble.json` schemas and generates models, migrations, controllers, views, routes, tests, and more.

Part of the [Ensemble](https://github.com/coding-sunshine) ecosystem:

- **[ensemble-cli](https://github.com/coding-sunshine/ensemble-cli)** — Global CLI for creating Laravel projects with AI-powered schema generation
- **ensemble** (this package) — Project-level code generation from schemas

Built on top of [Laravel Blueprint](https://github.com/laravel-shift/blueprint) with full backward compatibility.

---

How It Works
------------

[](#how-it-works)

### The Core Idea: AI writes the schema, your machine writes the code

[](#the-core-idea-ai-writes-the-schema-your-machine-writes-the-code)

Ensemble draws a hard line between two concerns:

LayerWho does itSpeedDeterminism**Schema authoring** (`ensemble.json`)You, AI, or bothSecondsFlexible**Code generation**Local deterministic pipelineMilliseconds100% reproducible**AI is never asked to write PHP.** It only ever reads or writes the JSON schema. Once the schema exists, all code generation runs locally through typed Lexers and template-based Generators — no network call, no token cost, no hallucinated imports.

---

### Full Flow Diagram

[](#full-flow-diagram)

 ```
flowchart TD
    subgraph SOURCES["📥  Schema Authoring  (choose any path)"]
        direction LR
        M["✏️  Manual edit\nensemble.json"]
        CLI_DRAFT["🤖  ensemble draft\n(AI interview)"]
        CLI_AI["💬  ensemble ai\n'add a comments model'\n(natural-language patch)"]
        STUDIO_CANVAS["🎛  Studio ER canvas\n(drag-and-drop)"]
        STUDIO_CHAT["💬  Studio AI chat\n(streaming patch)"]
        STUDIO_URL["🌐  Studio URL → Schema\n(reverse-engineer a site)"]
        ADOPT["🔍  ensemble:adopt\n(scan existing app)"]
        DB["🗄  ensemble:from-database\n(reverse-engineer DB)"]
        TEMPLATE["📦  Template / Demo\n(saas, blog, ecommerce…)"]
    end

    SCHEMA["📄  ensemble.json\n─────────────────\nmodels · fields · relationships\ncontrollers · pages · workflows\npolicies · recipes · roles"]

    subgraph BUILD["⚙️  Local Build Pipeline  (zero AI, zero network)"]
        direction TB
        LEX["🔍  Lexers\nparse schema into\ntyped model objects"]
        TREE["🌳  Tree\nin-memory graph of\nall schema entities"]
        GEN["🏭  Generators\n23 deterministic generators\none per output type"]
    end

    subgraph OUTPUT["📂  Generated Laravel Files"]
        direction LR
        G1["Models\nMigrations\nFactories\nSeeders\nEnums"]
        G2["Controllers\nForm Requests\nRoutes\nPolicies"]
        G3["Views / Inertia Pages\nLivewire Components\nDashboards"]
        G4["Events · Jobs · Mail\nNotifications\nObservers"]
        G5["Pest / PHPUnit Tests\nOpenAPI Spec\nTypeScript Types"]
    end

    subgraph AI_OPT["🤖  Optional AI Helpers  (always schema-level, never code-level)"]
        FIX["ensemble:fix\nrepair validation errors"]
        SCAFFOLD["ensemble:scaffold\none-shot schema from goal"]
        EXPLAIN["ensemble:explain\nstream AI explanation\nof a generated file"]
        GHOST["Studio ghost-text\nfield name suggestions"]
        ADVISOR["Studio proactive advisor\nrules-based schema hints\n(no AI, runs client-side)"]
    end

    SOURCES --> SCHEMA
    SCHEMA --> LEX --> TREE --> GEN
    GEN --> G1 & G2 & G3 & G4 & G5

    FIX & SCAFFOLD --> SCHEMA
    GHOST --> SCHEMA
    EXPLAIN -.->|reads only| GEN
    ADVISOR -.->|reads only| SCHEMA

    style SCHEMA fill:#1e3a5f,stroke:#3b82f6,color:#e2e8f0
    style BUILD fill:#1a2e1a,stroke:#22c55e,color:#e2e8f0
    style AI_OPT fill:#2d1f3d,stroke:#8b5cf6,color:#e2e8f0
    style SOURCES fill:#1f1f2e,stroke:#64748b,color:#e2e8f0
    style OUTPUT fill:#1e2a1e,stroke:#4ade80,color:#e2e8f0
```

      Loading ---

### Step-by-step walkthrough

[](#step-by-step-walkthrough)

#### 1 — Describe your app (schema authoring)

[](#1--describe-your-app-schema-authoring)

You have nine entry points, all producing the same `ensemble.json`:

Entry pointBest forAI?`ensemble draft` (CLI interview)New projects; guided Q&amp;AYes — creates schema`ensemble ai "…"` (patch command)Iterating on an existing schemaYes — edits schema**Studio ER canvas**Visual drag-and-drop editingNo**Studio AI chat**Natural-language schema changesYes — returns schema patch**Studio "Quick Generate"**One sentence → full schemaYes — creates schema**Studio URL → Schema**Reverse-engineer a websiteYes — creates schema`ensemble:adopt`Existing Laravel appsNo (static analysis)`ensemble:from-database`DB-first workflowsNo (reads migrations)Template / DemoKick-start from a known patternNo> **AI at this layer only writes JSON.** The worst it can do is produce a bad schema — which `ensemble:validate` or `ensemble:lint` will immediately flag. No PHP is ever generated by AI.

#### 2 — The schema is validated locally

[](#2--the-schema-is-validated-locally)

```
php artisan ensemble:validate   # structural checks
php artisan ensemble:lint       # design heuristics (missing indexes, N+1 risks, security)
php artisan ensemble:check      # validate + lint + dry-run in one pass, with health score
```

All three commands run **entirely on your machine**. No AI is called unless you explicitly run `ensemble:fix` to repair errors.

#### 3 — Deterministic code generation

[](#3--deterministic-code-generation)

```
php artisan ensemble:build
```

This is the core engine — no network, no randomness:

```
ensemble.json
    ↓
Lexers          — parse raw JSON into typed PHP objects (ModelLexer, ControllerLexer, …)
    ↓
Tree            — an in-memory graph connecting all entities and their relationships
    ↓
Generators      — 23 classes, each responsible for one output type (ModelGenerator, MigrationGenerator, …)
    ↓
Generated files — written atomically; hashes stored in .ensemble/file-hashes.json

```

Because generators are pure functions of the schema, running `ensemble:build` twice on the same schema always produces bit-for-bit identical output.

#### 4 — Merge-only protection

[](#4--merge-only-protection)

`merge_only_generation = true` (the default) means Ensemble only overwrites files **it originally created** (tracked by sha256 hash in `.ensemble/file-hashes.json`). Any file you have manually edited since the last build is skipped. You can see conflicts with `ensemble:audit` or in the Studio Conflicts panel.

#### 5 — AI helpers (optional, always schema-level)

[](#5--ai-helpers-optional-always-schema-level)

Once code is generated, AI can still assist — but only by reading:

- `ensemble:explain app/Models/Post.php` — streams an explanation of a generated file
- Studio field-suggestion ghost text — suggests field names as you type (one API call per suggestion)
- Studio proactive advisor — **fully client-side rule-based analysis**, zero API calls

The only commands that write AI output back to disk are `ensemble:fix` and `ensemble:scaffold` — and both write to `ensemble.json`, never to PHP/Blade files directly.

---

### Why this design?

[](#why-this-design)

Traditional AI code genEnsembleAI writes PHP → hard to reviewAI writes JSON → easy to reviewEach run may differSame schema = same code, alwaysHard to version-control`ensemble.json` is a clean git diffHallucinated imports break buildsSchema validation catches errors before buildRebuilding overwrites manual editsMerge-only + hash tracking protects your changesVendor lock-in to one AI provider8 providers; swap with one env varAPI key requiredWorks fully offline with local providers (`claude-cli`, `gemini-cli`, `ollama`)---

Installation
------------

[](#installation)

```
composer require coding-sunshine/ensemble --dev
```

If you used `ensemble-cli` to create your project, this package is already installed.

Quick Start
-----------

[](#quick-start)

### From an `ensemble.json` schema

[](#from-an-ensemblejson-schema)

```
php artisan ensemble:build
```

### From a Blueprint-compatible YAML draft

[](#from-a-blueprint-compatible-yaml-draft)

```
php artisan ensemble:build draft.yaml
```

### Full-schema health check

[](#full-schema-health-check)

Run validate, lint, and dry-run plan in a single command:

```
php artisan ensemble:check
php artisan ensemble:check --json   # Includes health score (0–100) and machine-readable result
```

### Create a starter draft

[](#create-a-starter-draft)

```
php artisan ensemble:new
```

### Adopt an existing Laravel application

[](#adopt-an-existing-laravel-application)

Comprehensive adoption for apps that already have Eloquent models, controllers, and installed packages:

```
php artisan ensemble:adopt                  # scan + generate ensemble.json
php artisan ensemble:adopt --dry-run        # preview without writing
php artisan ensemble:adopt --force          # overwrite without prompting
```

`ensemble:adopt` scans every Eloquent model (fields, relationships, SoftDeletes, timestamps, primary key type), detects installed packages and matches them to Ensemble recipes, identifies resource controllers, and produces a complete `ensemble.json`. It also prints an adoption report and actionable suggestions.

### Reverse-engineer DB columns only

[](#reverse-engineer-db-columns-only)

```
php artisan ensemble:trace                  # writes model cache (legacy .ensemble file)
php artisan ensemble:trace --write-schema   # also merges models into ensemble.json
php artisan ensemble:trace --dry-run        # preview without writing
```

The package uses a `.ensemble/` directory for file hashes, snapshots, and build metadata. The legacy `.ensemble` file (when present) is still used for merge-only generation cache.

### Explore demo schemas

[](#explore-demo-schemas)

Try pre-built, realistic schemas for common app types:

```
php artisan ensemble:demo                              # interactive picker
php artisan ensemble:demo saas                         # preview SaaS schema
php artisan ensemble:demo blog --apply                 # write blog schema to ensemble.json
php artisan ensemble:demo --list                       # list all demos
```

Available demos: **saas** (teams, billing, subscriptions), **blog** (posts, categories, tags, comments), **ecommerce** (products, variants, orders, coupons), **crm** (contacts, deals, pipeline), **api** (UUID PKs, Sanctum, webhooks), **project-management** (boards, tasks, sprints, time tracking).

### Validate a schema

[](#validate-a-schema)

```
php artisan ensemble:validate
php artisan ensemble:validate --json   # AI/automation-friendly output with fix suggestions
```

### AI-powered repair

[](#ai-powered-repair)

```
php artisan ensemble:fix
php artisan ensemble:fix --dry-run    # Show the suggested fix without writing
```

Runs `ensemble:validate`, and if errors are found calls the configured AI provider to suggest and apply a corrected schema.

### File provenance tracing

[](#file-provenance-tracing)

```
php artisan ensemble:why app/Models/Post.php
```

Shows which generator produced a given file, whether it has been manually modified since it was generated, and which schema model it came from.

### Explain generated code (AI)

[](#explain-generated-code-ai)

```
php artisan ensemble:explain app/Models/Post.php
php artisan ensemble:explain app/Models/Post.php --aspect=relationships
```

Streams an AI explanation of what the file does and how it maps to the schema. Optional `--aspect` focuses the explanation (e.g. `fillable`, `casts`, `relationships`). Uses the configured Studio AI provider (API or local CLI).

### One-liner scaffold from a goal (AI)

[](#one-liner-scaffold-from-a-goal-ai)

```
php artisan ensemble:scaffold "SaaS blog with subscriptions and team workspaces"
php artisan ensemble:scaffold "CRM with contacts and deals" --dry-run
```

Generates a full `ensemble.json` from a natural-language goal, then runs `ensemble:build`. `--dry-run` previews the schema and plan without writing. Refuses to run in production unless `ENSEMBLE_ALLOW_PRODUCTION` is set.

### MCP server (for AI agents / IDEs)

[](#mcp-server-for-ai-agents--ides)

```
php artisan ensemble:mcp
```

Runs a JSON-RPC MCP server over stdio. Exposes tools: `get_schema`, `update_schema`, `validate_schema`, `build`, `dry_run`, `append_model`, `trace`, `get_file`, `run_migrate`, `snapshot`, `audit`. Disabled in production by default.

### Audit modified generated files

[](#audit-modified-generated-files)

```
php artisan ensemble:audit
php artisan ensemble:audit --modified-only   # Only show changed/deleted files
php artisan ensemble:audit --json            # Machine-readable output
```

Reads `.ensemble/file-hashes.json` (written after every build) and compares stored sha256 hashes against current file contents. Exit code 1 if any file differs — useful in CI to detect unintentional overwrites.

### CI schema health gate

[](#ci-schema-health-gate)

```
php artisan ensemble:ci
php artisan ensemble:ci --plan   # Also run dry-run build check
```

Single-pass validate + lint, minimal output, exit 1 on any error. Designed for GitHub Actions or any CI pipeline — no interactive prompts.

### Named schema snapshots

[](#named-schema-snapshots)

```
php artisan ensemble:snapshot                          # Auto-named by timestamp
php artisan ensemble:snapshot before-auth-redesign     # Custom name
php artisan ensemble:snapshot --list                   # List all snapshots
php artisan ensemble:snapshot --rollback               # Restore latest
php artisan ensemble:snapshot --rollback=name          # Restore by name
php artisan ensemble:snapshot --delete=name            # Delete a snapshot
```

Stores snapshots in `.ensemble/snapshots/`. Think of it as `git stash` for `ensemble.json` — great before a large AI-assisted refactor. Rollback automatically backs up the current schema first.

### Live package introspection

[](#live-package-introspection)

```
php artisan ensemble:packages
php artisan ensemble:packages --all    # Show all installed packages, not just known ones
```

Inspects `vendor/composer/installed.json`, cross-references against the known recipe catalog, and shows which features are missing from your schema along with the recipe command to add them.

### Erase generated code

[](#erase-generated-code)

```
php artisan ensemble:erase
```

### Preview changes (dry run)

[](#preview-changes-dry-run)

```
php artisan ensemble:build --dry-run
php artisan ensemble:build --dry-run --output=plan.json   # Machine-readable plan
```

### Diff schema vs last build

[](#diff-schema-vs-last-build)

```
php artisan ensemble:diff
```

### Analyze your project

[](#analyze-your-project)

```
php artisan ensemble:analyze
```

### Relationship-first schema edits

[](#relationship-first-schema-edits)

```
php artisan ensemble:relationship User hasMany Post
php artisan ensemble:relationship Post belongsTo User --fk=owner_id
php artisan ensemble:relationship Post belongsToMany Tag
```

Displays a preview of **both sides** of the relationship (parent and child) before writing, so you can confirm the full impact.

### Watch database for migration changes

[](#watch-database-for-migration-changes)

```
php artisan ensemble:from-database --watch
```

Polls `database/migrations/` for new or modified files. Re-runs the schema import automatically each time a migration changes. Combine with `--build` to also regenerate code on each re-import.

### Diagram export

[](#diagram-export)

```
php artisan ensemble:diagram --format=mermaid --output=schema.mmd
php artisan ensemble:diagram --format=schema-graph --output=schema-graph.json
```

### AI-friendly workflow

[](#ai-friendly-workflow)

- **Append a model** — `ensemble:append Post --controller --fields=title:string,body:text`
- **Remove a model** — `ensemble:reduce Post [--erase]`
- **Schema from database** — `ensemble:from-database [table] [--build] [--sample] [--suggest-relationships]`
- **Apply a fragment** — `ensemble:apply ai-generated.json [--build]`
- **Validate with suggestions** — `ensemble:validate --json`

Commands
--------

[](#commands)

CommandDescription`ensemble:build [path]`Generate code from `ensemble.json` or `draft.yaml``ensemble:build --dry-run`List planned changes without writing files`ensemble:build --force`Skip confirmation prompts`ensemble:check [path] [--json]`Validate + lint + dry-run plan; `--json` includes health score (0–100)`ensemble:ci [path] [--plan]`**New** — CI health gate: validate + lint, exit 1 on any error`ensemble:validate [path] [--json]`Validate schema structure; `--json` returns errors and fix suggestions`ensemble:lint [path] [--fix]`Lint schema for design errors (FK indexes, N+1 risks, security, orphaned controllers)`ensemble:fix [path] [--dry-run]`AI-powered repair of validation errors`ensemble:audit [--modified-only] [--json]`**New** — Show which generated files have been manually modified`ensemble:snapshot [name] [--list] [--rollback] [--delete]`**New** — Save/restore named schema snapshots`ensemble:why `Show which generator produced a file and its source schema model`ensemble:explain  [--aspect=...]`**New** — AI explanation of generated file and its schema mapping (streaming)`ensemble:scaffold "" [--dry-run]`**New** — Generate full schema from a goal, then build (AI one-liner)`ensemble:mcp`**New** — Run MCP server over stdio for AI agents / IDE integrations`ensemble:packages [--all]`List installed packages and available Ensemble integration`ensemble:diff [path]`Compare schema with last build`ensemble:erase [--model=Name]`Delete files from last build`ensemble:adopt [--dry-run] [--force] [--no-check] [--output=]`**New** — Comprehensive adoption: scan models, relationships, controllers, packages → generate `ensemble.json``ensemble:demo [name] [--list] [--apply] [--force]`**New** — Browse/apply pre-built demo schemas (saas, blog, ecommerce, crm, api, project-management)`ensemble:trace [--write-schema] [--dry-run]`Reverse-engineer existing models into `.ensemble` (add `--write-schema` to also update `ensemble.json`)`ensemble:new`Create a starter draft file`ensemble:init`Alias for `ensemble:new``ensemble:analyze`Analyze project stack and database`ensemble:append  [--controller] [--fields=...] [--belongs-to=Parent] [--has-many=Child]`Add a model to `ensemble.json``ensemble:reduce  [--erase]`Remove a model from schema`ensemble:relationship    [--fk=...]`Add a relationship — previews both sides before writing`ensemble:from-database [table] [--build] [--replace] [--sample] [--suggest-relationships] [--watch]`**New `--watch`** — Generate/update schema from DB, re-run on migration changes`ensemble:apply  [--build]`Merge a JSON fragment into `ensemble.json``ensemble:diagram [--format=mermaid|schema-graph] [--output=file]`Export schema as ER diagram or graph`ensemble:split`Split a large schema into partial files`ensemble:watch`Watch schema file for changes and rebuild automatically`ensemble:stubs`Publish customizable stubs`ensemble:make:generator`Scaffold a new custom generator class`ensemble:make:lexer`Scaffold a new custom lexer class`ensemble:install [--force] [--no-interaction]`**New** — First-run setup wizard: publish config, detect AI provider, init schema (adopt/demo/trace/scaffold/starter), bootstrap `.ensemble/`, patch `.gitignore``ensemble:setup`**New** — Alias for `ensemble:install` (safe to re-run)OpenAPI / Scramble Integration
------------------------------

[](#openapi--scramble-integration)

When you include an API resource controller in your schema, Ensemble generates an OpenAPI **3.1.0** spec (`openapi.yaml`) with:

- Fully typed request/response schemas per model
- Reusable error schemas (`ErrorResponse`, `ValidationErrorResponse`)
- Paginated list responses (`PaginatedResponse`)
- Bearer auth / API key security schemes
- Per-endpoint `operationId`, parameters, and error codes (401, 403, 404, 422)

**Tip:** Pair with [Scramble](https://scramble.dedoc.co/) (`dedoc/scramble`) to keep your docs auto-updated from your PHP code — no PHPDoc annotations needed:

```
composer require dedoc/scramble
php artisan scramble:generate     # generate full OpenAPI 3.1 spec from code
```

**Tip:** Use [spatie/laravel-openapi-cli](https://spatie.be/docs/laravel-openapi-cli/v1/introduction) to turn any OpenAPI spec into typed Artisan commands for consuming external APIs:

```
composer require spatie/laravel-openapi-cli
# Then register an API spec in a ServiceProvider and get typed commands
```

Both packages are available as Ensemble recipes — add them via `php artisan ensemble:packages` or directly in `ensemble.json` under `features`.

Schema Format
-------------

[](#schema-format)

The `ensemble.json` file describes your entire application:

```
{
    "version": 1,
    "app": {
        "name": "my-app",
        "stack": "livewire",
        "ui": "mary"
    },
    "models": {
        "Post": {
            "description": "A blog post written by a user.",
            "fields": {
                "title": "string:200",
                "body": "text",
                "status": "enum:draft,published,archived default:draft",
                "author_id": "id:user"
            },
            "relationships": {
                "comments": "hasMany:Comment",
                "author": "belongsTo:User"
            },
            "softDeletes": true,
            "meta": {
                "seeder_count": 50,
                "seeder_states": ["published"]
            }
        }
    },
    "controllers": {
        "Post": { "resource": "web" }
    },
    "pages": {
        "posts.index": {
            "layout": "sidebar",
            "columns": ["title", "status", "author.name"]
        }
    },
    "recipes": [
        { "name": "roles-permissions", "package": "spatie/laravel-permission" }
    ]
}
```

Field syntax follows Laravel Blueprint conventions: `string:200`, `id:user`, `enum:a,b,c`, `nullable`, `unique`, `default:value`.

### Model Description

[](#model-description)

Add a `description` field at the model level (or inside `meta.description`) to auto-generate a doc-comment on the Eloquent model class:

```
"Post": {
    "description": "A blog post written by a user.",
    "fields": { ... }
}
```

Generates:

```
/**
 * A blog post written by a user.
 */
class Post extends Model
```

Descriptions are emitted even when `generate_phpdocs` is disabled, so you always get a one-line class summary without exposing full property type hints.

### Seeder Metadata

[](#seeder-metadata)

Control how many records the seeder creates and which factory states to apply:

```
"meta": {
    "seeder_count": 100,
    "seeder_states": ["published", "verified"]
}
```

This generates `Post::factory()->count(100)->published()->verified()->create();` — no custom stubs needed.

What Gets Generated
-------------------

[](#what-gets-generated)

From a single schema, Ensemble generates:

- **Models** — Eloquent models with fillable, casts, relationships
- **Migrations** — Database migrations with proper column types
- **Controllers** — Resource controllers or custom actions
- **Factories** — Model factories with realistic fake data
- **Seeders** — Database seeders (with configurable count and factory states)
- **Routes** — Web and API route registrations
- **Form Requests** — Validation rules derived from schema
- **Policies** — Authorization policies
- **Events, Jobs, Mail, Notifications** — From controller statements
- **Views / Inertia Pages** — Blade views or React/Vue/Svelte pages
- **Tests** — PHPUnit or Pest test files
- **Enums** — PHP 8.1+ backed enums from enum columns

Linting
-------

[](#linting)

`ensemble:lint` (and the `ensemble:check` checklist) catch design problems before you generate code:

CategoryWhat it checks**Structural**Orphaned controllers (no matching model), undefined model refs in relationships and FK fields**Indexes**FK fields (`*_id`) missing a database index**Types**Ambiguous column types (`string`, `integer`, etc. without length/precision)**Performance**`hasManyThrough`, `morphMany`, `morphOne`, `morphToMany` relationships that risk N+1 queries; missing FK indexes on the child side of `hasMany`/`hasOne`**Security**Sensitive field names (`password`, `token`, `api_key`, `secret`, …) that may be unintentionally mass-assignable**Completeness**Models with no fields or relationships (likely incomplete definitions)Run `ensemble:lint --fix` to auto-apply safe corrections (adds missing indexes; prompts before removing orphaned controllers).

Ensemble Studio
---------------

[](#ensemble-studio)

Ensemble Studio is a visual schema builder and AI chat UI embedded in your Laravel app — at `https://yourapp.test/ensemble/studio`.

**No build step in your app.** The Studio frontend is pre-built and shipped with the package. After `composer require coding-sunshine/ensemble`, the assets are served from the package; you do not run `npm run build` in your Laravel project. If you see "Studio assets not built yet", run `composer update coding-sunshine/ensemble` to install a release that includes the built assets.

**Features:**

- **ER canvas** — Drag-and-drop model cards, columns, and relationships; cardinality badges on edges; inline field editor; model descriptions
- **Theme** — Dark/light toggle (persisted)
- **AI chat** — Persistent, streaming chat that returns schema patches; optional snapshot before applying AI changes
- **Build visibility** — Schema diff modal (current vs last-saved + planned actions), code preview panel with dry-run preview and “Fix with AI” on build errors
- **Conflicts** — Panel listing files that differ from last build (from `.ensemble/file-hashes.json`); view diff or overwrite all
- **Snapshots** — Create/list/restore named schema snapshots from the header dropdown
- **CI &amp; health** — Status bar CI pill (from `ensemble:lint --json`) and header health score (0–100, from `ensemble:check --json`); green ≥80, yellow 60–79, red &lt;60
- **Inline AI** — Table options panel can suggest fields from the configured AI provider (with graceful fallback if unconfigured)
- **Pages** — Grid of page cards with wireframe preview and configure

**Enable Studio:** On by default. Set `ENSEMBLE_STUDIO_ENABLED=false` to disable. Configure path with `ENSEMBLE_STUDIO_PATH` (default `ensemble/studio`). The asset base URL is derived from the Studio route, so JS/CSS load correctly even if you change the path.

**AI:** Set `ENSEMBLE_AI_KEY` and optionally `ENSEMBLE_AI_PROVIDER` and `ENSEMBLE_AI_MODEL`. Studio also supports **local AI** with no API key: set `ENSEMBLE_AI_PROVIDER` to `claude-cli`, `gemini-cli`, or `lmstudio` (LM Studio at `localhost:1234`). Run `php artisan ensemble:doctor` (or `ensemble doctor` from the CLI) to detect and recommend local providers.

Configuration
-------------

[](#configuration)

Publish the config file:

```
php artisan vendor:publish --tag=ensemble-config
```

Key settings in `config/ensemble.php`:

SettingDefaultDescription`namespace``App`Application namespace`models_namespace``Models`Models sub-namespace`controllers_namespace``Http\Controllers`Controllers namespace`use_constraints``false`Add foreign key constraints to migrations`use_guarded``false`Use `$guarded` instead of `$fillable``property_promotion``false`Constructor property promotion`generators``[...]`Registered generator classes`test_framework``null``pest`, `phpunit`, or `null` to auto-detect`livewire_volt``false`Generate single-file Volt components`merge_only_generation``true`Only overwrite files Ensemble generated (hash-tracked in `.ensemble`)`allow_production``false`**New** — Allow schema-modifying commands in production (`ENSEMBLE_ALLOW_PRODUCTION=true`)`hooks.post_build``[]`**New** — Commands or callables to run after a successful `ensemble:build``log_channel``stack`**New** — Laravel log channel for Ensemble warnings/errors (`ENSEMBLE_LOG_CHANNEL`)`studio.enabled``true`Enable Ensemble Studio`studio.path``ensemble/studio`URL path segment for Studio`studio.middleware``['web']`Middleware for Studio routes`studio.ai_provider``openai`AI provider: `openai`, `anthropic`, `openrouter`, `ollama`, `claude-cli`, `gemini-cli`, `lmstudio`, `prism``studio.ai_api_key`—Set via `ENSEMBLE_AI_KEY``studio.ai_model``null`Override model (e.g. `gpt-4o`, `claude-sonnet-4-20250514`)### Production Safety Guard

[](#production-safety-guard)

By default, `ensemble:build`, `ensemble:fix`, and other schema-modifying commands are **blocked in the `production` environment**. To allow them (e.g. in a CI/CD deploy step):

```
ENSEMBLE_ALLOW_PRODUCTION=true php artisan ensemble:build
```

Or set `'allow_production' => true` in `config/ensemble.php`.

### Post-Build Hooks

[](#post-build-hooks)

Run commands or callables automatically after every successful `ensemble:build`:

```
// config/ensemble.php
'hooks' => [
    'post_build' => [
        'php artisan ide-helper:models -W',
        'php artisan event:cache',
        fn ($generated) => cache()->flush(),
    ],
],
```

Each hook is either a shell command string or any PHP callable that receives the `$generated` array.

AI Providers
------------

[](#ai-providers)

Ensemble Studio and `ensemble:fix` use the provider configured under `studio.ai_provider`:

ProviderConfig valueAPI key neededNotesOpenAI`openai`Yes — `ENSEMBLE_AI_KEY`Default.Anthropic`anthropic`Yes — `ENSEMBLE_AI_KEY`OpenRouter`openrouter`Yes — `ENSEMBLE_AI_KEY`Access many models via one key.Ollama`ollama`NoLocal. Set `ENSEMBLE_AI_MODEL` to the model name.Claude CLI`claude-cli`NoFree local AI via the `claude` CLI tool. Auto-detected by `ensemble:install`.Gemini CLI`gemini-cli`NoFree local AI via the `gemini` CLI tool. Auto-detected by `ensemble:install`.LM Studio`lmstudio`NoLocal. Runs at `localhost:1234`. Auto-detected by `ensemble:install`.Prism`prism`Via Prism configRequires `composer require prism-php/prism`.Run `php artisan ensemble:install` (or `php artisan ensemble:doctor`) to auto-detect which local providers are available on your machine.

JSON Schema (IDE validation)
----------------------------

[](#json-schema-ide-validation)

Ensemble ships with a JSON Schema for `ensemble.json`. Add autocomplete and validation in VS Code:

```
{ "$schema": "./vendor/coding-sunshine/ensemble/ensemble-schema.json", "version": 1, ... }
```

Custom Stubs
------------

[](#custom-stubs)

```
php artisan ensemble:stubs          # Publish to stubs/ensemble/
php artisan ensemble:stubs --list   # List stubs and custom overrides
```

Any stub with the same filename as a built-in stub overrides the default.

Custom Generators
-----------------

[](#custom-generators)

```
use CodingSunshine\Ensemble\Contracts\Generator;
use CodingSunshine\Ensemble\Tree;

class MyGenerator implements Generator
{
    public function output(Tree $tree): array
    {
        return ['created' => [['MyType', 'path/to/file.php']]];
    }

    public function types(): array
    {
        return ['my_type'];
    }
}
```

Register in `config/ensemble.php`:

```
'generators' => [
    // ... existing generators ...
    'my_type' => \App\Generators\MyGenerator::class,
],
```

Security
--------

[](#security)

### Studio in Production

[](#studio-in-production)

Ensemble Studio is **disabled by default in the `production` environment** (controlled by `ENSEMBLE_STUDIO_ENABLED`). If you enable it in production:

- **Restrict access** — set `studio.middleware` to `['web', 'auth', 'can:manage-ensemble']` or similar. Never expose Studio publicly in production.
- **Console panel** — `studio.console.enabled` defaults to `false`. Enabling it lets users run arbitrary Artisan commands; restrict the `allowlist` carefully.

```
// config/ensemble.php — production-safe Studio config
'studio' => [
    'enabled'    => env('ENSEMBLE_STUDIO_ENABLED', false),
    'middleware' => ['web', 'auth', 'role:admin'],
    'console'    => ['enabled' => false],
],
```

### MCP Server (`ensemble:mcp`)

[](#mcp-server-ensemblemcp)

`ensemble:mcp` is **blocked in production** by default (uses `RefusesInProduction`). The MCP server exposes schema read/write, build, and file-read tools over stdio. Only enable it (`ENSEMBLE_ALLOW_PRODUCTION=true`) inside a private, trusted environment (e.g. local dev or an authenticated IDE integration).

### AI Keys

[](#ai-keys)

Store `ENSEMBLE_AI_KEY` only in `.env` (never in `config/ensemble.php` directly). The `.env` file must be in `.gitignore`.

### Schema-Modifying Commands

[](#schema-modifying-commands)

`ensemble:build`, `ensemble:fix`, `ensemble:scaffold`, `ensemble:apply`, and `ensemble:mcp` are blocked in production by default. Use `ENSEMBLE_ALLOW_PRODUCTION=true` only in CI/CD pipelines where deploy access is already protected.

Blueprint Compatibility
-----------------------

[](#blueprint-compatibility)

Ensemble is fully backward compatible with Laravel Blueprint. Any `draft.yaml` will work unchanged. File resolution order:

1. `ensemble.json`
2. `draft.yml`
3. `draft.yaml`

Development
-----------

[](#development)

```
{
    "repositories": [{ "type": "path", "url": "../ensemble", "options": { "symlink": true } }],
    "require-dev": { "coding-sunshine/ensemble": "@dev" }
}
```

When developing the Studio frontend, run `npm install && npm run build` inside `resources/studio/` and commit the updated `resources/studio/dist/` before tagging a release so the package ships the latest build.

License
-------

[](#license)

Laravel Ensemble is open-sourced software licensed under the [MIT license](LICENSE).

###  Health Score

55

—

FairBetter than 97% of packages

Maintenance94

Actively maintained with recent releases

Popularity10

Limited adoption so far

Community19

Small or concentrated contributor base

Maturity85

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 56.1% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~27 days

Recently: every ~0 days

Total

84

Last Release

60d ago

Major Versions

0.5.1 → 1.0.02019-12-02

v1.25.0 → v2.0.02021-08-17

v0.1.0 → v3.0.02026-03-10

### Community

Maintainers

![](https://www.gravatar.com/avatar/d07f33e087402622624634afe8e1994a346a9732e24b9802aad264a3c5de0961?d=identicon)[coding-sunshine](/maintainers/coding-sunshine)

---

Top Contributors

[![jasonmccreary](https://avatars.githubusercontent.com/u/161071?v=4)](https://github.com/jasonmccreary "jasonmccreary (277 commits)")[![coding-sunshine](https://avatars.githubusercontent.com/u/3206025?v=4)](https://github.com/coding-sunshine "coding-sunshine (92 commits)")[![Pr3d4dor](https://avatars.githubusercontent.com/u/13210429?v=4)](https://github.com/Pr3d4dor "Pr3d4dor (16 commits)")[![laravel-shift](https://avatars.githubusercontent.com/u/15991828?v=4)](https://github.com/laravel-shift "laravel-shift (14 commits)")[![ghostwriter](https://avatars.githubusercontent.com/u/9754361?v=4)](https://github.com/ghostwriter "ghostwriter (14 commits)")[![nicodevs](https://avatars.githubusercontent.com/u/3766839?v=4)](https://github.com/nicodevs "nicodevs (13 commits)")[![benjam-es](https://avatars.githubusercontent.com/u/1738602?v=4)](https://github.com/benjam-es "benjam-es (11 commits)")[![devmsh](https://avatars.githubusercontent.com/u/9499808?v=4)](https://github.com/devmsh "devmsh (8 commits)")[![promatik](https://avatars.githubusercontent.com/u/1838187?v=4)](https://github.com/promatik "promatik (5 commits)")[![jyrkidn](https://avatars.githubusercontent.com/u/2447042?v=4)](https://github.com/jyrkidn "jyrkidn (4 commits)")[![bingtsingw](https://avatars.githubusercontent.com/u/10382462?v=4)](https://github.com/bingtsingw "bingtsingw (3 commits)")[![nexxai](https://avatars.githubusercontent.com/u/4316564?v=4)](https://github.com/nexxai "nexxai (3 commits)")[![spaceemotion](https://avatars.githubusercontent.com/u/429147?v=4)](https://github.com/spaceemotion "spaceemotion (3 commits)")[![adevade](https://avatars.githubusercontent.com/u/1066486?v=4)](https://github.com/adevade "adevade (3 commits)")[![dmason30](https://avatars.githubusercontent.com/u/20278756?v=4)](https://github.com/dmason30 "dmason30 (3 commits)")[![axit-joost](https://avatars.githubusercontent.com/u/13835397?v=4)](https://github.com/axit-joost "axit-joost (3 commits)")[![YannikFirre](https://avatars.githubusercontent.com/u/3316758?v=4)](https://github.com/YannikFirre "YannikFirre (2 commits)")[![diogogomeswww](https://avatars.githubusercontent.com/u/11543163?v=4)](https://github.com/diogogomeswww "diogogomeswww (2 commits)")[![justinwhite15](https://avatars.githubusercontent.com/u/841517?v=4)](https://github.com/justinwhite15 "justinwhite15 (2 commits)")[![LorenzoPapi](https://avatars.githubusercontent.com/u/42911751?v=4)](https://github.com/LorenzoPapi "LorenzoPapi (2 commits)")

---

Tags

laravelopenapiaiscaffoldcode-generationensembleblueprintstudio

###  Code Quality

TestsPHPUnit

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/coding-sunshine-ensemble/health.svg)

```
[![Health](https://phpackages.com/badges/coding-sunshine-ensemble/health.svg)](https://phpackages.com/packages/coding-sunshine-ensemble)
```

###  Alternatives

[spatie/laravel-health

Monitor the health of a Laravel application

85810.0M83](/packages/spatie-laravel-health)[laravel-zero/framework

The Laravel Zero Framework.

3371.4M368](/packages/laravel-zero-framework)[tightenco/jigsaw

Simple static sites with Laravel's Blade.

2.2k438.5k29](/packages/tightenco-jigsaw)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9682.1M97](/packages/roots-acorn)[laravel-shift/blueprint

An expressive, human readable code generation tool.

3.1k1.4M30](/packages/laravel-shift-blueprint)[laravel/vapor-cli

The Laravel Vapor CLI

31310.7M8](/packages/laravel-vapor-cli)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
