Architecture Skill
Determine correct file placement and structure for an Electron multi-process project.
Detailed References
- Renderer layer (components, hooks, utils, pages, CSS): references/renderer.md
- Main process & shared layer (bridges, services, worker, preload): references/process.md
- Project root & src/ layout (directory structure, migration status): references/project-layout.md
Decision Tree — Where Does New Code Go?
Is it UI (React components, hooks, pages)?
└── YES → src/renderer/ → see references/renderer.md
Is it an IPC handler responding to renderer calls?
└── YES → src/process/bridge/ → see references/process.md
Is it business logic running in the main process?
└── YES → src/process/services/ → see references/process.md
Is it an AI platform connection (API client, message protocol)?
└── YES → src/process/agent/<platform>/
Is it a background task that runs in a worker thread?
└── YES → src/process/worker/
Is it used by BOTH main and renderer processes?
└── YES → src/common/
Is it an HTTP/WebSocket endpoint?
└── YES → src/process/webserver/
Is it a plugin/extension resolver or loader?
└── YES → src/process/extensions/
Is it a messaging channel (Lark, DingTalk, Telegram)?
└── YES → src/process/channels/
Process Boundary Rules
Hard rules — violating them causes runtime crashes.
| Process |
Can use |
Cannot use |
Main (src/process/) |
Node.js, Electron main APIs, fs, path, child_process |
DOM APIs (document, window, React) |
Renderer (src/renderer/) |
DOM APIs, React, browser APIs |
Node.js APIs (fs, path), Electron main APIs |
Worker (src/process/worker/) |
Node.js APIs |
DOM APIs, Electron APIs |
Preload (src/preload.ts) |
contextBridge, ipcRenderer |
DOM manipulation, Node.js fs |
Cross-process communication:
- Main ↔ Renderer: IPC via
src/preload.ts + src/process/bridge/*.ts
- Main ↔ Worker: fork protocol via
src/process/worker/WorkerProtocol.ts
// NEVER in renderer
import { something } from '@process/services/foo'; // crashes at runtime
// Use IPC instead
const result = await window.api.someMethod(); // goes through preload
Naming Conventions
Directories
| Scope |
Convention |
Reason |
| Renderer component/module dirs |
PascalCase |
React convention — dir name = component name |
| Everything else |
lowercase |
Node.js convention |
| Categorical dirs (everywhere) |
lowercase |
components/, hooks/, utils/, services/ |
| Platform dirs (everywhere) |
lowercase |
acp/, codex/, gemini/ — cross-process consistency |
Quick test: "Inside src/renderer/ AND represents a specific component/feature (not a category)?" → PascalCase. Otherwise → lowercase.
Files
| Content |
Convention |
Examples |
| React components, classes |
PascalCase |
SettingsModal.tsx, CronService.ts |
| Hooks |
camelCase with use prefix |
useTheme.ts, useCronJobs.ts |
| Utilities, helpers |
camelCase |
formatDate.ts, cronUtils.ts |
| Entry points |
index.ts / index.tsx |
Required for directory-based modules |
| Config, types, constants |
camelCase |
types.ts, constants.ts |
| Styles |
kebab-case or Name.module.css |
chat-layout.css |
Structural Rules
- Directory size limit: Max 10 direct children. Split into subdirectories by responsibility when approaching.
- No single-file directories: Merge into parent or related directory.
- Single file vs directory: If a component needs a private sub-component or hook, convert to a directory with
index.tsx.
- Page-private first: Start code in
pages/<PageName>/. Promote to shared only when a second consumer appears.
Test File Mapping
Tests mirror source files in tests/ subdirectories:
| Source |
Test |
src/process/services/CronService.ts |
tests/unit/cronService.test.ts |
src/renderer/hooks/ui/useAutoScroll.ts |
tests/unit/useAutoScroll.dom.test.ts |
src/process/extensions/ExtensionLoader.ts |
tests/unit/extensions/extensionLoader.test.ts |
When tests/unit/ exceeds 10 direct children, group into subdirectories matching source structure.
Quick Checklist
1---2name: architecture3description: Project architecture and file structure conventions for all process types. Use when: (1) Creating new files or modules, (2) Deciding where code should go, (3) Converting single-file components to directories, (4) Reviewing code for structure compliance, (5) Adding new bridges, services, agents, or workers.4---56# Architecture Skill78Determine correct file placement and structure for an Electron multi-process project.910## Detailed References1112- **Renderer layer** (components, hooks, utils, pages, CSS): [references/renderer.md](references/renderer.md)13- **Main process & shared layer** (bridges, services, worker, preload): [references/process.md](references/process.md)14- **Project root & src/ layout** (directory structure, migration status): [references/project-layout.md](references/project-layout.md)1516---1718## Decision Tree — Where Does New Code Go?1920```21Is it UI (React components, hooks, pages)?22 └── YES → src/renderer/ → see references/renderer.md2324Is it an IPC handler responding to renderer calls?25 └── YES → src/process/bridge/ → see references/process.md2627Is it business logic running in the main process?28 └── YES → src/process/services/ → see references/process.md2930Is it an AI platform connection (API client, message protocol)?31 └── YES → src/process/agent/<platform>/3233Is it a background task that runs in a worker thread?34 └── YES → src/process/worker/3536Is it used by BOTH main and renderer processes?37 └── YES → src/common/3839Is it an HTTP/WebSocket endpoint?40 └── YES → src/process/webserver/4142Is it a plugin/extension resolver or loader?43 └── YES → src/process/extensions/4445Is it a messaging channel (Lark, DingTalk, Telegram)?46 └── YES → src/process/channels/47```4849---5051## Process Boundary Rules5253**Hard rules — violating them causes runtime crashes.**5455| Process | Can use | Cannot use |56| ---------------------------------- | ---------------------------------------------------------- | ----------------------------------------------- |57| **Main** (`src/process/`) | Node.js, Electron main APIs, `fs`, `path`, `child_process` | DOM APIs (`document`, `window`, React) |58| **Renderer** (`src/renderer/`) | DOM APIs, React, browser APIs | Node.js APIs (`fs`, `path`), Electron main APIs |59| **Worker** (`src/process/worker/`) | Node.js APIs | DOM APIs, Electron APIs |60| **Preload** (`src/preload.ts`) | `contextBridge`, `ipcRenderer` | DOM manipulation, Node.js `fs` |6162Cross-process communication:6364- Main ↔ Renderer: IPC via `src/preload.ts` + `src/process/bridge/*.ts`65- Main ↔ Worker: fork protocol via `src/process/worker/WorkerProtocol.ts`6667```typescript68// NEVER in renderer69import { something } from '@process/services/foo'; // crashes at runtime7071// Use IPC instead72const result = await window.api.someMethod(); // goes through preload73```7475---7677## Naming Conventions7879### Directories8081| Scope | Convention | Reason |82| ---------------------------------- | ---------- | ------------------------------------------------------- |83| **Renderer** component/module dirs | PascalCase | React convention — dir name = component name |84| **Everything else** | lowercase | Node.js convention |85| **Categorical dirs** (everywhere) | lowercase | `components/`, `hooks/`, `utils/`, `services/` |86| **Platform dirs** (everywhere) | lowercase | `acp/`, `codex/`, `gemini/` — cross-process consistency |8788> Quick test: "Inside `src/renderer/` AND represents a specific component/feature (not a category)?" → PascalCase. Otherwise → lowercase.8990### Files9192| Content | Convention | Examples |93| ------------------------- | ------------------------------- | ------------------------------------- |94| React components, classes | PascalCase | `SettingsModal.tsx`, `CronService.ts` |95| Hooks | camelCase with `use` prefix | `useTheme.ts`, `useCronJobs.ts` |96| Utilities, helpers | camelCase | `formatDate.ts`, `cronUtils.ts` |97| Entry points | `index.ts` / `index.tsx` | Required for directory-based modules |98| Config, types, constants | camelCase | `types.ts`, `constants.ts` |99| Styles | kebab-case or `Name.module.css` | `chat-layout.css` |100101---102103## Structural Rules1041051. **Directory size limit**: Max **10** direct children. Split into subdirectories by responsibility when approaching.1062. **No single-file directories**: Merge into parent or related directory.1073. **Single file vs directory**: If a component needs a private sub-component or hook, convert to a directory with `index.tsx`.1084. **Page-private first**: Start code in `pages/<PageName>/`. Promote to shared only when a second consumer appears.109110## Test File Mapping111112Tests mirror source files in `tests/` subdirectories:113114| Source | Test |115| ------------------------------------------- | ----------------------------------------------- |116| `src/process/services/CronService.ts` | `tests/unit/cronService.test.ts` |117| `src/renderer/hooks/ui/useAutoScroll.ts` | `tests/unit/useAutoScroll.dom.test.ts` |118| `src/process/extensions/ExtensionLoader.ts` | `tests/unit/extensions/extensionLoader.test.ts` |119120When `tests/unit/` exceeds 10 direct children, group into subdirectories matching source structure.121122---123124## Quick Checklist125126- [ ] Code is in the correct process directory (no cross-process imports)127- [ ] Renderer code does not use Node.js APIs128- [ ] Main process code does not use DOM APIs129- [ ] New IPC channels are bridged through `preload.ts`130- [ ] Renderer component/module dirs use PascalCase; categorical dirs use lowercase131- [ ] Platform dirs use lowercase everywhere132- [ ] Directory-based modules have `index.tsx` / `index.ts` entry point133- [ ] Page-private code is under `pages/<PageName>/`, not in shared dirs134- [ ] No single-file directories135- [ ] No directory exceeds 10 direct children136- [ ] New source files are auto-included in coverage — verify they are not accidentally excluded in `vitest.config.ts` → `coverage.exclude`137- [ ] New services separate pure logic from IO