Building a Feature Extraction Engine for Laravel

The core engineering challenge in kit isn't building features — it's removing them cleanly. When a buyer selects Billing + Teams but not Notifications, the generated project can't have a single reference to notifications anywhere. No unused imports, no dead routes, no orphaned migrations.

Here's how the extraction system works.

The Annotation Layer

Every piece of code that belongs to a specific module gets annotated with a comment tag:

PHP

Annotations work in any file type:

TSX
PHP

The key insight: annotations mark entire files and individual code blocks within shared files. A route file might have some routes that belong to billing and others that belong to teams.

The Manifest

The features.json manifest is the single source of truth:

JSON

Dependencies are important. If billing depends on teams, selecting billing automatically includes teams. Users don't need to figure this out.

The Extraction Process

When extraction runs, it follows these steps:

Step 1: Resolve Dependencies

Given a set of selected features, expand the list to include all dependencies. If the user selected billing, the resolved set becomes billing + teams.

Step 2: Remove Annotated Files

Any file annotated with a feature that isn't in the resolved set gets deleted entirely:

Text

Step 3: Strip Inline Annotations

For shared files that contain code blocks from multiple features, strip the unselected blocks:

PHP

Step 4: Clean Up Imports

After removing code blocks, there will be unused imports. The cleanup pass removes them:

PHP

Step 5: Remove Annotations

Finally, strip all #feature: comments from the remaining code. The buyer never sees the annotation system.

Extraction Process

Validation

The extraction engine includes a validation step that runs after every extraction:

  • Are there any dangling references to removed classes?
  • Do all remaining routes resolve to existing controllers?
  • Are there any orphaned migration files?
  • Do the remaining tests pass?

If validation fails, the extraction aborts and reports what went wrong. This catches mistakes when I add new code and forget to annotate it properly.

The Hard Part: Shared Code

The trickiest aspect is code that's used by multiple modules. A User model might have relationships for teams, billing, and notifications. The extraction engine needs to selectively remove relationship methods without breaking the model.

The solution: annotate individual methods, not just files.

PHP

This granularity is what makes the system work. It's more work to maintain, but the output is worth it — every generated project looks like it was built from scratch. The CLI installer orchestrates this entire flow, from license validation to project delivery.

Related articles