Amended by 0249: one app member builds
web, PWA and desktop targets.
Amended by 0259: where a feature module lives. The
service shape of decision 1 stands.
Amended by 0264:
The kind folders
hooks/, widgets/, pages/, links/, drivers/ and ai/ join decision 3’s
list, each created with its first file.Amended 2026-10-21 (STA-219): config lives in
src/config/, package static files in assets/, the
root-module test is <name>.module.int.test.ts, and the kind-folder list is the one in ADR
0130. See the amendment at the end of this page.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.
Amended by 0269 (decision 6):
decision 2’s entry list has one named exception, the
./e2e and ./contract entries of
@stackra/testing.Amendment 2026-10-21: config, assets and the root-module test (STA-219)
Context. Decisions 1 and 2 put config besidesrc/ and shipped files in resources/, and decision 1 named the root-module
test <name>.module.test.ts. The scaffold and the preview repository differ on the test name, and the 2026-10-19 CF1 rule
(config as config/<pkg>.config.ts) sits outside src/, against the rule that every member keeps its code in src/. The
owner settled these on 2026-10-21.
Decision.
- Config is inside
src/. A service’s deploy-time defaults aresrc/config/<name>.config.ts, and a package’s aresrc/config/<pkg>.config.ts. Replace theconfig/paths in decisions 1 and 2 with these. ADR 0177 carries the package side forward. - Static files are
assets/, notresources/. Files shipped with a package sit in anassets/folder at the package root, exported as./assets/*.resources/is the kind folder of@Resourcedeclarations (ADR 0130), and never a folder of static files. Theresources/path in decision 2 is withdrawn, and the scaffold template is changed to match (T3). - The root-module test is
<name>.module.int.test.ts. It lives insrc/__tests__/and boots the root module, so it is an integration test under the.inttier of ADR 0182. The unit name<name>.module.test.tsin decision 1 is withdrawn. - Reference services.
services/exampleandservices/healthdo not yet havesrc/config/,src/contracts/orsrc/__tests__/(the gap in Consequences stands). Closing it belongs to the golden-members work (L7); this amendment does not move them.
- The scaffold test (
tools/scripts/__tests__/scaffold.test.mjs) must check the new paths; the template changes are T3. - A reader looking for config looks in
src/config/; a reader looking for static files looks inassets/.
checkService in tools/scripts/validate-repository.mjs
checks src/config/ once the structure work (STA-220) lands. Until then the paths in decisions 1 and 3 are not checked.
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).