Context
pnpm new still rendered shapes the owner has since replaced. Packages came in three archetypes from
0004 (domain with four layers, platform, flat lib); a service rendered an
Encore unit at services/src/<name> with encore.service.ts and api.ts, which 0091
and 0124 rule out; there were app-next and app-expo kinds; and
0040 organised a service’s modules in DDD layers. The owner’s
locked decisions of 2026-10-19 and 2026-10-20 replace each of these: FW1 (entries-first packages), audit Q9 (action-centric
kind folders), G2 (each member declares its root module), console = Filament-style resources, TS1/TS2 (test tiers by
filename infix), CF1 (config as config/<pkg>.config.ts), the code conventions (no enum, component folders, private, no
Storybook), B16 (no Next.js), MR7 (a desktop app), audit Q10 (no app()/config()/logger() helpers), the declaration
rule, the devtools entry and FO5/FO7 (a separate private figentra-os repo). The templates are where a shape becomes real
for every new member, so they are decided here together.
Decision
-
Service.
pnpm new service <name>renders a plain-TypeScript member atservices/<name>,@figentra/service-<name>, with no Encore file:src/main.tsbootstraps the root module;src/<name>.module.tsis the root@Modulewith an emptyimportslist;package.jsondeclares"stackra": { "module": "./src/<name>.module.ts" }(0090).src/modules/starts empty; its README lists the kind folders of decision 3.src/contracts/index.tsis the types-only./contractsentry (0117).config/<name>.config.tsholds deploy-time defaults (CF1);src/__tests__/<name>.module.test.tsboots the root module.- Until
@stackra/containerships@Module, the root module is a plain class with a staticimportsfield, marked as a shortcut in the template.
-
Package. One entries-first shape replaces the domain, platform and lib archetypes of 0004:
- Entries are
.(core,src/core/),./contracts,./node,./react,./native,./testingand./devtools. Core is always present; the others are chosen with--entries(or a prompt on a terminal) and are declared only with real code. config/<pkg>.config.tsandresources/(exported as./resources/*) sit outsidesrc/.- An entry never imports another entry;
reactandnativeshare an internalsrc/ui/folder. toolingstays thetier:configpreset shape.
- Entries are
-
Kind folders inside a feature module (services and packages), created with their first file:
models/,actions/,queries/,services/,events/,listeners/,workflows/,policies/,permissions/,settings/,contracts/,resources/(Filament-style panel resources); andinterfaces/,types/,constants/,tokens/,errors/,decorators/once there are two or more files of that kind. There are nocontrollers/,dtos/,repositories/,helpers/orutils/folders. This replaces the four layers of 0040 decisions 1 and 2. -
Declarations. Decorators annotate code (classes, methods, fields);
define*creates values other code references (defineToken,defineConfig,definePermissions,defineEvents,defineMeters,defineEntitlements). A package that defines decorators ships an Explorer that registers them at bootstrap through the container’sDiscoveryService. -
Apps. Four kinds:
app:console: Vite, React Router 7 with code-based routes, HeroUI (through@stackra/uionce it exists), and a panel shell that hosts Filament-style resources.app:mobile: a copy ofapps/mobile, so Expo SDK 57, code-based React Navigation (no expo-router), HeroUI Native and Uniwind.app:desktop: Electron packaged by electron-builder (MR7), as a scaffold.app:docs: Mintlify.
-
Rules in every template. Config is YAML where the reader supports it (
MUST_STAY_JSONC,MUST_STAY_JSON); versions arecatalog:orworkspace:*only; tests are<subject>.test.tsin__tests__/, with.int,.contract,.e2eor.loadbefore.testfor those tiers, and the unittesttask excludes the infixed tiers; every source file opens with a contract block (0007); noenum, no#private, noapp()/config()/logger()helpers; a component is a folderx/{x.tsx, index.ts, __tests__/x.test.tsx}; no*.stories.*. -
The generator.
pnpm new <kind> <name>takes the kindsservice,package,tooling,app:console,app:mobile,app:desktopandapp:docs. Every option is a flag (--category,--entries,--description,--title,--port,--dry-run), and--repo <path>renders into another monorepo with that repo’sLICENSE.
Consequences
- A new member starts in its final shape and passes
pnpm validatewithout edits; the scaffold test proves it for every kind. services/exampleandservices/healthgain a root module andstackra.module; the reference services of FW10 replace them later.- The figentra-os repo is scaffolded with the same generator, so both repos share one member shape.
- The service and package templates carry shortcuts until
@stackra/containerand@stackra/configexist; each is marked in the file it affects. - The
electroncatalog entry is unused until the first desktop app, which also addselectrontoallowBuilds.
Enforcement
tools/scripts/__tests__/scaffold.test.mjsrenders every kind and runs the validator’s member, service and exports checks on the result.validate-repository.mjscheckService: a service hassrc/main.ts, astackra.modulethat exists, and noencore.service.tsorencore.app;checkTestPlacementbans*.stories.*.- Planned: a validator check that a package’s entry folders match its
exportsandtsdown.config.ts, and an oxlint rule that entries never import each other.
Supersedes and sources
Supersedes: 0004. Amends 0040 (decisions 1 and 2: kind folders replace layers) and 0010 (decision 1: a service also declares its root module and holdsconfig/). Sources: owner decisions FW1, audit Q9 and Q10, G2, TS1/TS2,
CF1, B16, MR7, FO5/FO7, the code conventions, the declaration rule and the devtools entry (2026-10-19 and 2026-10-20).