src/main/index.ts → main.ts and src/preload/index.ts → preload.ts, so the process entries stop occupying the barrel-reserved index filename (§6.4) without needing an exemption list. The rename is wired through electron.vite (main build.lib.entry — rollupOptions.input would bypass electron-vite's output-format detection — and the preload input key), package.json main (out/main/main.js), WindowManager's default preload filename, MainWindowService's webview preload path, and DbService's slow-query stack filter, which matches the bundled artifact name. preload.d.ts becomes globals.d.ts: sharing preload.ts's basename makes TypeScript drop the .d.ts as that file's presumed output declaration, and tsgo only applies its global Window augmentation when the declaration sorts before its importer, so the file keeps a distinct, alphabetically-early name. Entry-path mentions in code comments and reference docs follow.
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.
Main previously imported all 12 renderer translation JSONs by relative path to
build its t() table — a main->renderer boundary violation that also inlined
~3.86 MB of translations the main process never uses. Main now owns a small,
independent catalog under src/main/i18n (~59 keys: app menu, tray, dialogs,
context menu, the OAuth callback page and a few shared strings), statically
imported for all 12 languages (~48 KB total).
- src/main/utils/language.ts -> src/main/i18n/index.ts (git mv): swap the renderer
JSON imports for the local catalog, add an en-US fallback to t(), and narrow the
now-internal `locales` export. AppMenuService reads getI18n() instead of the
locales map; the OAuth callback drops its duplicate translator for t().
- src/main/i18n/{locales,translate}/*.json: the main catalog, extracted from the
renderer catalog (zero translation loss), aligned and sorted across all 12 files.
- Renderer catalog: delete the now main-exclusive keys (appMenu.*, tray.*, dialog.*,
settings.mcp.oauth.callback.*, common.{inspect,paste,cut},
agent.session.workspace_status.{missing,not_directory}).
- Composer delete buttons used t('appMenu.delete') by mistake; switch to
t('common.delete') (byte-identical in all 12 languages) so appMenu is fully
main-owned.
- readErrorMessage: take a pre-translated `fallback` string instead of an i18next
key, and move it from @shared/ai into src/main/ai/provider/custom (main-only after
the change); its 6 provider call sites pass main's t(...).
- Tooling: check-i18n now validates the main catalog's 12 files plus a literal-t()
key-coverage check for main sources; sync-i18n and auto-translate-i18n cover both
catalogs. eslint bans relative **/renderer/** in main/preload; TopicNamingService
test reads the renderer catalog from disk instead of importing it.
- Docs: main-process-architecture.md records i18n as a governed top-level expansion
and closes the resolved deviation; CLAUDE.md lists the new directory.
Dissolve the renderer types/index.ts re-export barrel (Phase 2):
- Repoint 252 consumers to @renderer/types/<topic> (intra-types files use
relative ./topic); covers @renderer/types, @types, and the equivalent
'./', './index', '@renderer/types/index' specifier forms.
- Delete src/renderer/types/index.ts.
- Remove the @types alias from tsconfig.web.json, electron.vite.config.ts,
and the eslint main/preload boundary guard.
- Retire the resolved types-barrel and @types deviations from the renderer
and main architecture docs.
main-process-architecture.md §3: state the no-renderer-imports rule (src/main + src/preload must not import renderer code; cross-process types → @shared, main-only → src/main), now enforced by the ESLint no-restricted-imports rule; clarify that the existing 'no automated enforcement yet' note refers to the internal direction edges. §7: track the lone remaining exception — main/utils/language.ts's relative renderer i18n import, deferred to the i18n migration PR.
renderer-architecture.md §7: add the anti-pattern of importing a shared bucket root (@renderer/utils, @renderer/types) instead of the specific file/topic, or giving types/ or utils/ a re-export root index.ts.
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).