The api/index.ts barrel re-exported only infra types yet required domain DTOs
to deep-import schemas/<domain>, colliding with naming §6.4 rule 2
(enforced-or-no-barrel) and accounting for the bulk of barrel/closed lint
violations. Because schema files carry zod runtime values, any aggregating
barrel drags all 24 domains in on a single import — exactly what the barrel
reform removes.
- Remove api/index.ts; api/ is now an open namespace.
- Flatten infra file names: apiTypes/apiErrors/apiPaths -> types/errors/paths;
schemas/index.ts -> schemas/apiSchemas.ts.
- Rewrite all consumers: 71 deep-import path renames + 106 barrel imports split
to their owning module (types/paths/errors), including two dynamic imports and
the tests/__mocks__ fixtures.
- Sync data docs and codify the schemas/ `_xxx.ts` = cross-resource construct
convention in naming-conventions §3.2.
Rename the four directory-form index routes (settings/, settings/mcp/, app/mini-app/, app/paintings/) to TanStack's default-supported flat dot form (settings.index.tsx, …) so no file under routes/ is named index.* and the §6.4 iron rule — the index filename is reserved for barrels — holds across src with no exceptions. URLs and route ids are unchanged; routeTree.gen.ts regenerates with only the four import paths moved. Naming §6.4 drops the routes/ carve-out, §6.6 documents the dot-form token, and the routes READMEs replace a stale bare-index example.
Promote §6.4 from three loose rules to the full barrel contract (re-export-only, enforced-sole-entry-or-no-barrel, no nesting, one-cohesive-unit) and point shared §3.1 / main §2.1 / renderer §5 at it, fixing main's stale pointer to shared. Reserve the index filename for barrels — always index.ts, never .tsx outside routes/ — with implementations in named files; add the renderer component-directory form and align §4.2's component test. Note what the contract does not remove: dev builds load a barrel's full graph (rule 4 is the bound), and dynamic import() crosses a boundary through the barrel, with the React.lazy form in renderer §5. Docs only; lint enforcement and call-site fixes follow.
Replace the fuzzy business-orchestration routing criterion with an outward-side-effects test: stateless shared modules default to utils/ and promote to services/ only for a stated reason (side effects, or a forced services import).
Rekey the Service/Manager suffix from stateful classes to stateful singleton capabilities, mechanism-independent: module-scope mutable state must take the class + singleton form, multi-instance helper classes take no suffix, and what counts as state is defined.
Codify renderer services/<topic>/ topic directories (single barrel entry, private topic-specific satellites exempt from shape routing, no UI) mirroring the existing main-process rule, and add the middle growth step to Naming 4.10.
Align residual wording across the three docs: same-kind peering edges in the renderer dependency table, the section-6 corollary vs its own worked example, quick-reference suffix note, utils charter and examples.
Record the placement rule settled during the renderer cleanup: utils/ is
stateless and domain-agnostic and MAY import downward infra
(data/ipc/workers), while services/ owns state/lifecycle or performs
business/domain orchestration. A helper touching infra is still a helper;
the decisive test is role, not purity.
- renderer-architecture.md: co-equal utils/data/ipc/workers foundation
(§2); positive service identity and the revised utils row (§3).
- naming-conventions.md §5.2: add the stateless-orchestration -> services
routing row; note utils may call downward infra.
- main-process-architecture.md: Pure -> Stateless; route by role.
src/renderer/hooks/agents/ is a feature namespace grouping the agent
feature's hooks, not a collection of agents. Per naming conventions
§4.9 it should be singular, matching sibling namespaces hooks/chat/,
hooks/tab/, hooks/translate/.
- git mv src/renderer/hooks/agents -> src/renderer/hooks/agent
- update 62 import paths across 33 files
- clarify §4.9 so the plural `agents/` example is read by role
(collection bucket vs feature namespace), not by the word
Add main-process-architecture.md — the main-process peer of the renderer and shared-layer docs: a charter per top-level directory, placement rules, dependency direction, governance, and current deviations.
Refocus architecture-overview.md on the cross-process picture: refresh the process model and data flow to v2 (drop Redux), slim main-only sections to pointers, and replace the duplicated subsystem table with a reference map.
Cross-reference the new doc from naming-conventions §4.8 (per-root closed top-level) and §4.10 (feature vs type-bucket placement).
Add docs/references/shared-layer-architecture.md as the authoritative reference for src/shared: two invariants (cross-process; no mutable runtime state), the closed top-level set {ai, data, ipc, types, utils} by category, types/utils shape rules (single-file vs subdirectory, barrels, constants guardrail), the placement decision, anti-patterns, and a deferred migration section (config dissolution with constant.ts itemized).
Relocate @shared-internal rules out of renderer-architecture.md and architecture-overview.md into the new doc (leaving pointers); repoint command's cross-process cell to @shared/utils/command + @shared/types/command in renderer-architecture sections 6 and 8; link the per-root applications of the closed-top-level rule from naming-conventions section 4.8.
Add docs/references/renderer-architecture.md as the canonical reference for src/renderer organization: the two-axis model (type x domain), four-layer downward dependency direction, per-directory responsibilities, the features/ definition, curated-barrel public API with import/no-restricted-paths enforcement, closed top-level governance, anti-patterns, a target-vs-current-state section, and industry references.
Align the existing docs: collapse the renderer subtree in architecture-overview.md to a pointer, and in naming-conventions.md list renderer services/ in the type-bucket set and link features/ placement to the new doc.
The features/ vs type-bucket split applies to both process roots (src/main/features/, src/renderer/features/); update the definition and the sibling-bucket note to cover the renderer (components/, hooks/, utils/).
Establish when a main-process domain belongs in src/main/features/ versus the services/ and utils/ type-buckets: a domain earns its own features/<domain>/ tree only when it is large, complex, and multi-file, while a single cohesive service (even domain-specific) stays as services/<Domain>Service.ts with its lone helper in utils/.
Decouple naming from placement in §4.5, and surface the rule in the §1 quick reference and the §7 decision tree.
Unify the three coexisting styles for $inferSelect/$inferInsert type exports (XxxSelect/XxxInsert and Xxx/NewXxx) onto the dominant XxxRow / InsertXxxRow form, and document it as the convention.
- schemas: assistant, group, mcpServer, note, miniApp, pin, tagging, painting, userModel, userProvider -> *Row / Insert*Row
- update all consumers (services, migrators, mappings, seeders, tests)
- docs: add naming-conventions.md section 5.3 and a pointer in src/main/data/db/README.md
The Row suffix is chosen over Drizzle's docs-style SelectXxx/InsertXxx to keep the DB-row type visibly distinct from the API XxxEntity type. Table names, columns, indexes, and migrations are unchanged - this is a type-name-only change.
Move all renderer source from src/renderer/src/* up one level to
src/renderer/*, removing the redundant nested src directory.
- Update path aliases (@renderer, @types, @logger, @data) and TanStack
Router paths in electron.vite.config.ts; update tsconfig.{json,web,node}
path mappings and include globs.
- Fix Vite root-relative script paths in the 8 renderer HTML entries.
- Update cross-process relative imports in main/preload (language,
apiServer models, preload index) to drop the /src segment.
- Switch renderer test imports of the logger mock to the @test-mocks alias.
- Update hardcoded renderer paths in scripts and their fixtures, lint
configs (eslint/oxlint/biome), CODEOWNERS, docs, and the data-classify tool.
- Convert deep (../../+) relative imports within the renderer to the
@renderer alias (69 files, 108 imports); keep single-level relatives.
- Fix doc links broken by the move and correct one pre-existing broken
link in naming-conventions.md.
packages/shared was never a real pnpm workspace package (no package.json); it was referenced only through the @shared TypeScript path alias. Relocate it under src/ via git mv (143 files, detected as pure renames).
Repoint the @shared alias and include globs to src/shared across electron.vite.config.ts, tsconfig.{json,node,web}.json and vitest.config.ts; update scripts/check-custom-exts.ts, scripts/update-languages.ts, the eslint.config.mjs generated-file globs, the data-classify generator output targets, .github/CODEOWNERS path rules, and CLAUDE.md/docs/source-comment references.
The @shared alias name is unchanged, so all 1403 @shared/* import sites resolve without modification. Verified with typecheck:node, typecheck:web and the full test suite (700 files, 9739 tests passing).
Add closed-form rule for stateful class suffix (Service / Manager) with
shape-based routing for non-stateful modules and cross-link to
lifecycle-decision-guide. Add file-vs-subdirectory organization (§4.4),
top-level directories closed by default (§4.8), bucket anti-patterns
(§6.7), and extend the acronym rule to filenames (§6.1).
Provide a decision rule for choosing the Service vs Manager class suffix: Service is the default capability provider, Manager is reserved for classes whose defining job is owning a pool/registry of homogeneous instances.
The rule applies to new classes; existing names are not renamed.
Add §6.6 noting that src/renderer/src/routes/ files are
kebab-case (TanStack Router file→URL mapping, per §2.3).
List TanStack's reserved tokens. Extend §1 Quick Reference
and §7 Decision Tree so the exception is discoverable.