AionUi architecture
install
source · Clone the upstream repo
git clone https://github.com/iOfficeAI/AionUi
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/iOfficeAI/AionUi "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.claude/skills/architecture" ~/.claude/skills/iofficeai-aionui-architecture && rm -rf "$T"
manifest:
.claude/skills/architecture/SKILL.mdsource content
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 () | Node.js, Electron main APIs, , , | DOM APIs (, , React) |
Renderer () | DOM APIs, React, browser APIs | Node.js APIs (, ), Electron main APIs |
Worker () | Node.js APIs | DOM APIs, Electron APIs |
Preload () | , | DOM manipulation, Node.js |
Cross-process communication:
- Main ↔ Renderer: IPC via
+src/preload.tssrc/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 | , , , |
| Platform dirs (everywhere) | lowercase | , , — cross-process consistency |
Quick test: "Inside
AND represents a specific component/feature (not a category)?" → PascalCase. Otherwise → lowercase.src/renderer/
Files
| Content | Convention | Examples |
|---|---|---|
| React components, classes | PascalCase | , |
| Hooks | camelCase with prefix | , |
| Utilities, helpers | camelCase | , |
| Entry points | / | Required for directory-based modules |
| Config, types, constants | camelCase | , |
| Styles | kebab-case or | |
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
. Promote to shared only when a second consumer appears.pages/<PageName>/
Test File Mapping
Tests mirror source files in
tests/ subdirectories:
| Source | Test |
|---|---|
| |
| |
| |
When
tests/unit/ exceeds 10 direct children, group into subdirectories matching source structure.
Quick Checklist
- Code is in the correct process directory (no cross-process imports)
- Renderer code does not use Node.js APIs
- Main process code does not use DOM APIs
- New IPC channels are bridged through
preload.ts - Renderer component/module dirs use PascalCase; categorical dirs use lowercase
- Platform dirs use lowercase everywhere
- Directory-based modules have
/index.tsx
entry pointindex.ts - Page-private code is under
, not in shared dirspages/<PageName>/ - No single-file directories
- No directory exceeds 10 direct children
- New source files are auto-included in coverage — verify they are not accidentally excluded in
→vitest.config.tscoverage.exclude - New services separate pure logic from IO