Skip to content
Hozu
Menu
How it works chapters
How it works

From source to a running application

Follow one feature through recording, validation, render planning and execution.

On this page

Follow a feature through Hozu

Select a stage to see what it takes in and what it makes explicit. You can also use the arrow keys within the group.

SourceFeature IRValidatorCompilerRuntimeSourceFeature IRValidatorCompilerRuntime
Pipeline stage

Source: Declare the intent

Typed feature builders describe views, queries, events and behaviour. References point to declarations, not copied strings.

Feature IR: Record the program

The intermediate representation stores those declarations and their relationships. The same structure is available to every tool.

Validator: Check the relationships

Rules catch invalid references and unsafe data flow. Contracts exercise machine transitions against the intended result.

Compiler: Derive the plan

Scope and freshness determine rendering regions. Machine bindings determine the islands that need client JavaScript.

Runtime: Execute the plan

The server renders HTML and serializes data. The browser only hydrates the interactive islands that the plan calls for.

One representation connects the tools

Hozu's pipeline is feature() source → Feature IR → validator → compiler → runtime. Each stage has a different responsibility. The author describes the program, the builder records it, the validator checks its relationships, the compiler derives execution decisions and the runtime carries them out.

The intermediate representation keeps those stages connected. A view event, a machine transition and an invoked mutation become related entries in structured data. Tools can inspect those relationships directly instead of trying to infer them from arbitrary application functions. ADR 0002 explains why the IR is the source of truth.

Source records a program

TypeScript gives declarations useful editor feedback and typed references. A route describes its parameters, an event describes its payload and a query describes its input and output. A feature registers those declarations under stable names, together with its views and any machine or contracts.

The callbacks used to author a view or machine run as recorders. A value such as ctx.draft represents a path that the eventual program will read. It is not the current contents of an input field while the builder runs. This distinction explains the deliberate syntax for conditions and assignments.

For example, a view can record whether an error message exists:

typescript
ui.if(
  op.neq(ctx.error, null),
  [ui.p({ role: 'alert' }, [ctx.error])],
  [],
)

The condition and both branches remain visible in the IR. A JavaScript if over the recorded reference would instead try to decide the branch during recording. For computation outside the operation vocabulary, a named fn() supplies input and output schemas and a pure implementation. It is an explicit boundary the tools can identify.

Validation checks the relationships

The validator checks more than the shape of individual declarations. It can find a reference to an unregistered mutation, an event that a visible control sends into a state that cannot handle it, or a feature that accesses another feature's private declaration. Render-related checks also prevent user-scoped data from entering a shared cacheable region.

Contracts add execution to those structural checks. They place a machine in a known state, send events or effect results and compare the resulting state, context and effects with the author's expectation. Transition coverage identifies paths that have no contract. The behavior lock compares changes with the contracts that cover them.

Diagnostics identify a location, cause and suggested fix. The JSON form supports tooling, while the text form makes the same information readable in a terminal. Some failures require a decision about intent, so a useful diagnostic does not always include an automatic patch. The diagnostic design is documented in ADR 0003.

Compilation derives the plan

The compiler reads the validated program and follows its dependencies. Query scope and freshness determine cache and request behavior. Machine bindings determine which nodes need client execution. A page can therefore combine a static shell, request-specific content and small interactive islands without one manually selected rendering mode for the entire route.

Server HTML uses generated JavaScript for subtrees that do not suspend. Query streaming retains an interpreted path around suspension points, so the server can flush earlier content before waiting for data. A production build writes the render module for deployment; Node development uses the same generator at startup. ADR 0024 describes that division.

The runtime then executes the plan. Server resolvers provide query and mutation results, the machine interpreter processes events and the browser runtime updates the islands that require it. Static nodes need no client application runtime merely because they share a page with an interactive control.

Ask the narrowest useful question

Start a change with hozu map. It lists routes, data declarations, events, states, views and contracts with source locations. Open the relevant application code, then use a more focused tool when the relationship you need is still unclear.

bash
pnpm exec hozu map
pnpm exec hozu inspect items
pnpm exec hozu explain items.idle
pnpm exec hozu plan home

inspect exposes a feature's summary and IR. explain describes a state's transitions, effects and covering contracts. plan shows the rendering decision for a named route, including islands and persistence opportunities. These commands answer different questions, so running all of them for every small edit adds unnecessary work.

After an intended change, hozu check runs the combined verification. Use hozu get for rendered text, attributes and forms, and hozu post for a native form flow. Browser checks remain useful for layout, focus and interactions that require a real browser. The CLI reference lists the commands, and machines and contracts explains the behavior checks in detail.

Edit this page on GitHub