Early alpha Chronicler is pre-release software and changes often. Join the waitlist
Architecture

Modules & Editions

How one build serves both a free self-host edition and a paid hosted one, with closed features that light up only where they belong.

Chronicler ships as one artifact but lives two lives: a free edition someone runs themselves, and a hosted edition with features that cannot be open, like billing. The naive answers are both bad. Two separate builds means two things to keep in step. A single build with the closed code always present means the self-host edition carries features it must never run. Chronicler wants one build where the closed parts simply stay dark unless they are configured.

The base mechanism: an optional port with a no-op default

The simplest version of the idea is a port with a do-nothing default. Error reporting is the first example. A self-host install boots with the no-op and reports nothing to anyone. A hosted deploy sets a DSN and the real adapter takes over. The feature is present in the code and absent in behaviour until configuration lights it up. Nothing has to be compiled out.

The structural seam for closed features

Some features need more than a port. Billing owns aggregates, migrations, an event namespace, projectors, and scheduled chores. For those, the same idea grows into a structural module seam: a set of optional capability interfaces the core asks each module about at the right moment during boot. A closed module contributes all of that machinery without editing the shared core assembly, owns a reserved migration range that cannot collide with core, and lives in a separate code module the core never imports.

A module obeys the same boundary as a context

A module is not allowed to reach into the core however it likes. It observes the same ports-and-adapters discipline a core context does. A port only a module uses is owned by the module SDK. A port the core also uses is owned by the core context and re-exported through the SDK. Either way, the module depends on the SDK and on shared domain types, never on a core context's service or store directly. The same lint that polices the boundaries between core contexts polices this one, and a module declares the capabilities it needs so that a missing one fails the boot loudly instead of misbehaving later.

Where this connects

The hosted billing described in Workspaces, plans and billing is the first module to use this seam, and the boundary lint is the same one from Platform.

Read the record for the detail

This page is the guide. The full records under docs/adrs carry the capability interfaces, the SDK ownership rules, and the alternatives that were weighed and rejected.