Build

One typed application, not six libraries you glued together.

A route, the action behind it, the model under that, and the view it renders are all first-party and all typed against each other. Rename a model attribute and the compiler finds every caller, because there is no boundary where the types stop.

What you get.

All of it in the same install, with nothing to wire together first.

Routing

Verb helpers, groups, prefixes, named routes, and route model binding. Routes live in routes/ and register through app/Routes.ts.

Actions

A route points at an action rather than a controller method. Actions are single-purpose files in app/Actions/, and models with the useApi trait generate their own.

Models

defineModel() declares schema, validation, factories, relationships, and traits in one file. Migrations are diffed out of it, not hand-written.

STX views

Single-file components with a server/client script split, Blade-style directives, and signals for reactivity. No build config to own.

Middleware

Request middleware in app/Middleware/, registered in app/Middleware.ts, applied per route or per group.

Validation

Attribute rules live on the model, so the same schema validates the request, the factory, and the generated API.

Typed API client

Register routes with createTypedRouter() and createTypedClient() infers every path, body, and response from the actions themselves. No generation step, nothing committed to go stale.

OpenAPI

buddy generate:openapi-spec writes the spec for consumers outside TypeScript, from the same routes and validations.

Privacy by model

Mark an attribute personal and buddy gdpr:export, gdpr:erase, and gdpr:prune answer data-subject requests and retention rules, with a processing register beside them.

From the command line.

Buddy scaffolds, runs, and ships this the same way it does the rest of the app.

buddy make:model Post buddy generate:migrations buddy migrate

These share the same models, config, and types, so using them together costs nothing extra.