Search by

abdelhmed / chimera

abdelhmed

Describe a feature in plain language; Chimera plans it with Gemini, generates the files in batches, injects them into your Laravel app with AST, and verifies them with tests.

Package info

github.com/3bdel7med/Chimera

pkg:composer/abdelhmed/chimera

Statistics

Installs: 8

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v1.0.2 2026-10-28 14:06 UTC

This package is auto-updated.

Last update: 2026-10-30 11:59:57 UTC


README

Describe a feature in plain language. Chimera plans it with Google Gemini, generates the files in batches, merges them into your Laravel app through the PHP AST, runs the tests it wrote, and lets you undo everything with one command.

⚠️ Development tool only. Chimera writes PHP files, injects routes and runs migrations. Install it with --dev; it refuses to run when APP_ENV=production. Review every change before committing.

How it works

 php artisan chimera:morph "A task manager with projects and due dates"
        │
        ▼
 1. Scan        AST summary of your models, controllers, routes, tables (never reads .env)
 2. Conventions how YOUR project writes validation, responses, models, tests (learned from your AST)
 3. Plan        Gemini answers with a BLUEPRINT: the list of files and what each is for (no code yet)
 4. Confirm     you see the plan as a file tree; --dry-run stops here
 5. Generate    files are written in stages sized by TOKENS, not file count (see "Big plans" below).
                Each stage is saved; a truncated reply is split in half; PHP that does not parse is sent
                back with the error
 6. Audit       generated code is checked against your conventions; violations go back to the AI
                BEFORE anything touches your disk
 7. Apply       a checkpoint is opened, originals are backed up, files are created / modified / injected
 8. Migrate     only the migrations generated by this run
 9. Verify      the generated tests run on SQLite :memory:; failures are fed back to Gemini (self-healing)
10. Trust       deliberate bugs are planted in the generated code to see whether those tests notice
11. Summary     file tree with each file's state, trust score, what to `composer require`, how to roll back

What you see in the terminal

Every step is announced as it happens (so VS Code's terminal, CI logs and SSH all read the same), and the plan and the result are drawn as a file tree. While files are being read, a one-line status (analysing app/Models/User.php) is overwritten in place on real terminals.

▸ Scanning your project  reading models, controllers, routes and migrations
✔ Scanning your project  13 files analysed with the AST  (0.7s)
▸ Loading your conventions  how your project writes validation, responses, models and tests
✔ Loading your conventions  16 active conventions, learned from your code just now  (0.7s)
▸ Planning with the AI  sending your request and the project summary to the AI
✔ Planning with the AI  3 files planned  (0.7s)
▸ Reviewing the plan  Notes API

app/Http/
├─ Controllers/
│  └─ ○ NoteController.php  controller · CREATE — store a note
└─ Requests/
   └─ ○ StoreNoteRequest.php  request · CREATE — validates title
tests/Feature/
└─ ○ NoteTest.php  test · CREATE — store test

✔ Reviewing the plan  approved  (0.7s)
▸ Generating code  3 files in 2 batch(es)
  ● generated app/Http/Requests/StoreNoteRequest.php  batch 1/2
  ● generated app/Http/Controllers/NoteController.php  batch 1/2
  ● generated tests/Feature/NoteTest.php  batch 2/2
✔ Generating code  3 files generated and syntax-checked  (0.7s)
▸ Checking your conventions  checking the generated code against 16 conventions
✔ Checking your conventions  fixed 3 violation(s) in 1 file(s) before writing anything  (0.7s)
▸ Applying changes  backing up originals, then writing files
  ✔ written   app/Http/Requests/StoreNoteRequest.php  created
  ✔ written   app/Http/Controllers/NoteController.php  created
  ✔ written   tests/Feature/NoteTest.php  created
✔ Applying changes  3 created, 0 modified, 0 injected  (0.7s)
▸ Verifying with tests  running the generated tests on an isolated database
✔ Verifying with tests  tests pass  (0.7s)
▸ Stress-testing the tests  planting deliberate bugs in the generated code to see whether the tests notice
✔ Stress-testing the tests  trust score 75% (3 of 4 bugs caught)  (0.7s)

app/Http/
├─ Controllers/
│  └─ ✔ NoteController.php  created
└─ Requests/
   └─ ✔ StoreNoteRequest.php  created
tests/Feature/
└─ ✔ NoteTest.php  created

Trust score 75%: the tests caught 3 of 4 deliberate bugs.
These bugs went unnoticed, so the tests do not cover them yet:
  - app/Http/Controllers/NoteController.php:14 changed status code 403 to 404 in abort()

Set NO_COLOR=1 to disable colours. This sample is the real pipeline and renderer run with a scripted AI: the AI's first controller broke three of the project's conventions, so it was sent back and fixed before anything was written.

Installation

composer require --dev abdelhmed/chimera
php artisan vendor:publish --tag=chimera-config     # optional
GEMINI_API_KEY=your-key
CHIMERA_GEMINI_MODEL=gemini-2.5-flash               # any Gemini model your key can use

Requires PHP 8.1+ and Laravel 10, 11 or 12.

Commands

Command What it does
chimera:morph {prompt?} Run the full flow. Options: --dry-run, --yes, --no-migrate, --no-tests, --no-trust, --no-conventions, --max-tokens=N
chimera:resume {id?} Continue a saved plan or an interrupted run without planning or regenerating again
chimera:learn Learn your project's conventions, choose which to keep, save .chimera/conventions.json (--show only prints, --yes saves all)
chimera:history {id?} List runs (or the files of one run)
chimera:rollback {id?} Roll back the run's migrations, restore modified files, delete created ones (default: latest)

Skeletons: the AI writes only what is specific

Every new file of a known kind starts from a fixed skeleton that Chimera builds itself: the namespace, the class declaration, the base class and the standard traits. The AI returns only the new members (properties, methods, use imports), and Chimera injects them into the skeleton with the same AST injector it uses for your existing files.

New file The skeleton already has
Model namespace, class X extends Model, use HasFactory
Controller / Form Request / API Resource namespace, extends Controller / FormRequest / JsonResource
Job implements ShouldQueue and the four standard job traits
Event the three standard event traits
Listener / Middleware / Service / Policy namespace and the class
Factory / Seeder / Notification namespace and extends Factory / Seeder / Notification
Enum enum X: string (the AI may choose int) and its cases
Migration return new class extends Migration (the AI writes up() and down())
Routes file the header and use Route (the AI writes only the routes)

Tests, views, config and other free-form files have no skeleton; the AI writes them whole.

  • It still shows as created. A skeleton file is a new file, so a missing routes/api.php or a new Vendor model is reported as created, while User.php (which exists) is reported as injected.
  • The skeleton follows your project. declare(strict_types=1); is added to new files under app/ only if your conventions say so, and HasFactory only if your models use it.
  • Safe against a wandering AI. If the AI repeats the namespace, extends or a trait, the merge ignores the duplicates. If its members cannot be merged, the answer is sent back for a retry before anything is written.
  • Less to write, less to pay for. The skeleton is not generated by the model, so the output is shorter. The estimator assumes about 30% fewer tokens for a skeleton file; that is a guess, not a measurement.
  • Consistent by construction. Every model starts the same way, so you no longer get casts() in one file and $casts in the next for the shell parts.
  • Set generation.skeletons to false to go back to whole files from the AI.

Big plans: 40, 60, 80 files

One reply can only hold so much, so Chimera never asks for everything at once.

  • Estimate first. After the plan, before you approve it, you see what it will cost: Estimated generation: 20 AI call(s), about 71k input + 38k output tokens. It is a heuristic (about 3.5 bytes per token, typical size per file type), so expect ±40%, and retries and test healing are extra. --dry-run shows it without spending anything; --max-tokens=150000 stops the run when the estimate is above your limit. Set CHIMERA_PRICE_INPUT / CHIMERA_PRICE_OUTPUT (per million tokens) to also see a cost.
  • Stages sized to the model. Files are generated in dependency order (migrations, models, ... tests last). A stage is closed when it reaches generation.files_per_batch files or generation.output_tokens_per_batch estimated tokens, whichever comes first, so 60 files become as many calls as needed.
  • Adaptive. If the model still cuts a reply short, that batch is split in half and every following batch gets smaller.
  • Patient. On 429, 5xx or network errors Chimera waits and tries again: 2s, 4s, 8s, 16s... (capped, with jitter, and never less than the wait the model asks for), up to retry.attempts times. Permanent errors such as a bad key fail immediately.
  • Plan saved immediately. Planning is the slowest single call (minutes on a thinking model). Its result is saved the moment it arrives, so --dry-run, answering "no", or a crash never costs it twice: php artisan chimera:resume reviews the saved plan and generates it.
  • Resumable. After every stage the plan and the files generated so far are saved to storage/chimera/runs/. If a stage fails for good, nothing is lost:
php artisan chimera:resume            # continues the latest unfinished run
php artisan chimera:resume run_20261024_101500_ab12

Resuming skips scanning, planning and the files that are already done, so you only pay for what is left. Nothing has been written to your project at that point; files are applied only after every stage has been generated.

If it feels slow

Most of the wait is the model, not Chimera. Many Gemini models think before answering and bill that thinking as output tokens, which adds minutes to a 40-file plan. Planning and code generation are structured tasks that rarely need it:

CHIMERA_THINKING_BUDGET=0      # Gemini 2.5 Flash: thinking off (2.5 Pro cannot be turned off; its minimum is 128)
CHIMERA_THINKING_LEVEL=low     # newer models: minimal | low | medium | high

Set one of them (not both) and compare. They are off by default because not every model accepts every option. A shorter plan also helps: ask for a smaller feature first, then extend it. After the plan, Chimera forecasts the generation time from how fast the plan itself was produced.

Trust Score: do the AI's tests actually test anything?

Green tests are not proof. AI-written tests often pass because they assert very little. After the generated tests pass, Chimera plants small deliberate bugs in the generated application code (through the AST) and re-runs the tests for each one. A bug the tests notice is killed; a bug nobody notices survived. The score is the share killed.

Deliberate bug Example
comparison flipped !== becomes ===, >= becomes <
logic flipped && becomes ||
negation removed if (! $task->isOpen()) becomes if ($task->isOpen())
status code changed json($x, 201) becomes 200, abort(403) becomes 404
validation weakened 'title' => 'required|string' becomes 'string'
guard deleted $this->authorize(...), abort_if(...) removed

Survivors are listed with file, line and what was changed, so you know exactly which test is missing. Notes:

  • It only measures code Chimera created or fully rewrote; INJECT fragments, migrations, routes, views and tests are not mutated.
  • Some mutants are equivalent (the change cannot alter behaviour), so 100% is not always reachable. Treat the score as a guide, not a grade.
  • It adds one (fail-fast) test run per bug, capped by trust.max_mutants (default 20) and trust.mutant_timeout. Disable with --no-trust or trust.enabled.
  • Your files are changed on disk for a moment. The original is restored in a finally block and also kept in storage/chimera/mutation-recovery.json; if the process is killed mid-run, the next chimera:morph restores it first.

Conventions: code that looks like your code

php artisan chimera:learn reads your project through the AST and writes down what it finds, for example:

validation.form-request     Validate input with dedicated Form Request classes; never validate inline in controllers.   (8 of 8 store/update actions)
architecture.services       Put business logic in service classes under app/Services; keep controllers thin.            (4 classes)
php.strict-types            Start every PHP file under app/ with declare(strict_types=1);                               (12 of 12 files)
tests.pest                  Write tests with Pest: it()/test() closures and expect() assertions.                        (3 of 3 test files)
  • A habit becomes a convention only when it clearly dominates (at least 70% of a meaningful sample); mixed projects get no rule rather than a wrong one.
  • The command lets you switch conventions off, and saves .chimera/conventions.json. Commit it: your team shares the same rules. Add your own by hand with "source": "custom"; relearning keeps your choices and custom rules.
  • Without the file, Chimera learns on the fly in memory, so the first run already benefits.
  • Every convention is shown to the AI in the plan and in every code request. The ones that can be checked mechanically (Form Requests instead of inline validation, no queries in controllers, strict_types, return types, Pest vs PHPUnit) are also verified on the generated code; violations are sent back to the AI once, with the exact problem and its own code, before any file is written. Anything still wrong is listed in the summary.
  • Disable with --no-conventions or conventions.enabled.

INJECT: changing files you already own

The model never rewrites your existing classes blindly. For existing PHP files it returns a skeleton with only the new members, and Chimera merges it through the AST, keeping your formatting:

  • new methods, properties, constants and traits are added; members that already exist are left untouched
  • list properties such as $fillable get only the missing entries
  • use imports are merged without duplicates or alias clashes
  • route statements are appended to the routes file, skipping any that are already there
  • injecting the same snippet twice changes nothing

Safety

  • Paths from the model are validated: only app/ routes/ database/ resources/ tests/ config/ lang/ are writable; .., absolute paths, .env*, vendor/, storage/, .git/ are always rejected.
  • Existing files are never silently overwritten: a CREATE on an existing path becomes a visible MODIFY, and every touched file is backed up in storage/chimera/checkpoints/<id>/.
  • If applying fails half-way, the checkpoint is rolled back automatically.
  • Migrations run with --path, so your own pending migrations are never executed.
  • Chimera never edits .env or composer.json; it tells you what to add.

Architecture

src/
├── Contracts/      LlmClient, ProjectFiles, ProjectScanner, Injector, CheckpointStore, MigrationRunner, TestRunner, Reporter, ProgressTracker, ConventionStore, MutationRecovery
├── Data/           Immutable DTOs: FileSpec, Blueprint, GeneratedFile, ExecutionReport, TestResult, Checkpoint
├── Enums/          FileAction (CREATE/MODIFY/INJECT), FileType (also defines generation order)
├── Analysis/       ClassSummarizer, RouteSummarizer, AstProjectScanner, PhpSyntax (php-parser)
├── Planning/       BlueprintPlanner, BlueprintParser, BlueprintNormalizer, BatchPlanner
├── Generation/     FileGenerator, BatchPromptBuilder, GeneratedFileValidator
├── Skeleton/       SkeletonCatalog (the shell of each kind of file), SkeletonRenderer, SkeletonExpander
├── Injection/      ClassMembersInjector, RouteInjector, ImportMerger, FormatPreservingEditor, InjectorRegistry
├── Application/    ChangeApplier
├── Checkpoint/     FilesystemCheckpointStore, RollbackService
├── Verification/   ProcessTestRunner, HealingService
├── Conventions/    ConventionLearner + 8 AST Detectors, ConventionChecker + 6 Checks, FilesystemConventionStore
├── Estimation/     TokenEstimator, FileSizeEstimator, GenerationEstimator (the token forecast shown before you approve)
├── Runs/           RunState, FilesystemRunStore (what makes chimera:resume possible)
├── Trust/          MutantGenerator + 6 Operators, MutationRunner (restores files), TrustAnalyzer, mutation recovery
├── Llm/            GeminiClient (the only class that knows Gemini's REST format), RetryingLlmClient + RetryPolicy (backoff for any model)
├── Pipeline/       MorphPipeline + one small Stage per step (Scan, Plan, Confirm, Generate, Apply, Migrate, Verify, Summary)
└── Console/        Thin commands + ConsoleReporter (Laravel Prompts)

Patterns: Pipeline / Chain of Responsibility (stages), Strategy / Adapter (LlmClient, TestRunner, CheckpointStore, MigrationRunner), Registry (InjectorRegistry), Visitor via nikic/php-parser, immutable DTOs. Everything outside Llm/, Console/, Migration/ and ChimeraServiceProvider is framework-agnostic and unit-tested with fakes.

Customising

  • Prompts: php artisan vendor:publish --tag=chimera-prompts copies blueprint.system.stub, generate.system.stub and heal.system.stub to stubs/chimera/. Edit them to enforce your house style (e.g. "always use Actions, never Services").
  • Another model: implement Abdelhmed\Chimera\Contracts\LlmClient (one method) and bind it in your own service provider.
  • Another checkpoint strategy (e.g. git commits): implement CheckpointStore.
  • Bigger / smaller batches: generation.files_per_batch. Lower it if your model has a small output limit.

Known limits

  • Token estimates are heuristics. If your prompt is mostly non-Latin text or your files are unusually big, adjust generation.output_tokens_per_batch; a wrong guess is corrected automatically (the batch is split and later batches shrink).

  • The retry notice is printed while a Laravel Prompts spinner may be running; I could not check how that looks in a real terminal.

  • Conventions are statistical: a habit seen in too few files is ignored, and a learned rule can be wrong for new code. Review .chimera/conventions.json once.

  • Trust scoring measures the generated tests against six kinds of bugs, not every possible bug.

  • Route summaries do not resolve Route::group prefixes.

  • Healing only fixes files the model can see in the test output; failures caused by missing packages or .env values need your help.

  • If routes/api.php does not exist (Laravel 11+), Chimera creates it but warns you to register it (php artisan install:api).

Testing the package

composer install
vendor/bin/pest

License

MIT