Skip to content

How Kumiko thinks

Kumiko keeps the important shape of an app in a few readable definitions. Each area of the app is a feature. A feature describes its data, the actions people may perform, and the screens they use.

When data changes, Kumiko keeps a permanent record of the change and updates the tables used by the UI. Before the app starts, it checks that features, permissions, screens, configuration, and data rules agree. This makes the code more explicit, but many mistakes appear during boot instead of after a user finds them.

These choices explain most of Kumiko’s API and folder structure. They are useful when deciding where new code belongs or why the framework rejects a shortcut.

A feature owns one area of behavior. An orders feature can declare the order entity, create and update handlers, events, screens, navigation, jobs, and translations. Authentication, audit, files, and notifications use the same feature mechanism.

Framework infrastructure supplies the dispatcher, event store, tenant database context, and process lifecycle. Business behavior stays in features.

This makes features removable and replaceable. The cost is that one feature cannot reach directly into another feature’s tables or private helpers. It uses registered queries, writes, events, hooks, or extension points.

Read Features and composition for those communication paths.

An entity is a configuration value:

const taskEntity = createEntity({
fields: {
title: createTextField({ required: true, sortable: true, personal: false, reason: "is_business_data" }),
done: createBooleanField({ default: false }),
},
});

Kumiko derives validation and database metadata from the fields. Declarative screens use the same entity to render lists and forms. Search, access rules, and translation conventions also read the definition.

A plain value can be inspected by boot validation and authoring tools. It is more verbose than hiding behavior in a class, but it gives the framework one source of truth.

Read Schemas as data for stored fields, derived values, and reference data.

The defineFeature callback contains visible registrar calls such as r.entity, r.crud, r.screen, and r.nav. Entity and screen definitions can live in the feature’s schema/ folder, while handlers live under handlers/. The registration graph should not depend on runtime options that a source tool would have to execute.

This lets the designer, code transformations, and AI authoring tools edit the same source reviewed by a developer. The trade-off is a regular folder and registration structure instead of arbitrary factories.

Read Inline authoring for the boundary between inspectable registration and normal runtime code.

A successful entity write appends an event and updates its read model. Both changes share a transaction for the standard entity path. Lists and detail screens read projections rather than scanning event history.

The event log supports replay, point-in-time investigation, and optimistic locking. Cross-entity projections can process events after commit and may lag behind briefly. Permanent history also means personal and sensitive fields need explicit encryption rules.

Read Events and projections and Commands and queries for the write and read paths.

5. Configuration is checked before traffic

Section titled “5. Configuration is checked before traffic”

At boot, Kumiko checks the complete feature graph. It catches missing requirements, invalid screen and handler references, access-rule mistakes, inconsistent personal-data annotations, and schema drift before the process becomes ready.

The same validation can run in CI without database connections:

Terminal window
bun run boot

Boot checks cannot prove that an external provider contains the right data or that a business workflow works. Production verification still needs health checks and a real application probe.

Read Lifecycle and hooks for startup, readiness, and shutdown.