This file provides guidance to AI coding assistants when working with code in this repository. Adherence to these guidelines is crucial for maintaining code quality and consistency.
- Keep it clear: Write code that is easy to read, maintain, and explain.
- Match the house style: Reuse existing patterns, naming, and conventions.
- Search smart: Prefer
ast-grepfor semantic queries; fall back torg/grepwhen needed. - Log centrally: Route all logging through
loggerServicewith the right context—noconsole.log. - Research via subagent: Lean on
subagentfor external docs, APIs, news, and references. - Always propose before executing: Before making any changes, clearly explain your planned approach and wait for explicit user approval to ensure alignment and prevent unwanted modifications.
- Lint, test, and format before completion: Coding tasks are only complete after running
pnpm lint,pnpm test, andpnpm formatsuccessfully. - Write conventional commits: Commit small, focused changes using Conventional Commit messages (e.g.,
feat:,fix:,refactor:,docs:). - Sign commits: Use
git commit --signoffas required by contributor guidelines.
When creating a Pull Request, you MUST use the gh-create-pr skill.
If the skill is unavailable, directly read .agents/skills/gh-create-pr/SKILL.md and follow it manually.
When reviewing a Pull Request, do NOT run pnpm lint, pnpm test, or pnpm format locally.
Instead, check CI status directly using GitHub CLI:
- Check CI status:
gh pr checks <PR_NUMBER>- View all CI check results for the PR - Check PR details:
gh pr view <PR_NUMBER>- View PR status, reviews, and merge readiness - View failed logs:
gh run view <RUN_ID> --log-failed- Inspect logs for failed CI runs
Only investigate CI failures by reading the logs, not by re-running checks locally.
When creating an Issue, you MUST use the gh-create-issue skill.
If the skill is unavailable, directly read .agents/skills/gh-create-issue/SKILL.md and follow it manually.
IMPORTANT: Feature PRs that change Redux data models or IndexedDB schemas are temporarily blocked until v2.0.0 releases. Only bug fixes, performance improvements, docs, and non-data-model features are accepted. Track progress at #10162.
- Install:
pnpm install— Install all project dependencies (requires Node ≥22, pnpm 10.27.0) - Development:
pnpm dev— Runs Electron app in development mode with hot reload - Debug:
pnpm debug— Starts with debugging; attach viachrome://inspecton port 9222 - Build Check:
pnpm build:check— REQUIRED before commits (pnpm lint && pnpm test)- If having i18n sort issues, run
pnpm i18n:syncfirst - If having formatting issues, run
pnpm formatfirst
- If having i18n sort issues, run
- Full Build:
pnpm build— TypeScript typecheck + electron-vite build - Test:
pnpm test— Run all Vitest tests (main + renderer + aiCore + shared + scripts)pnpm test:main— Main process tests only (Node environment)pnpm test:renderer— Renderer process tests only (jsdom environment)pnpm test:aicore— aiCore package tests onlypnpm test:watch— Watch modepnpm test:coverage— With v8 coverage reportpnpm test:e2e— Playwright end-to-end tests
- Lint:
pnpm lint— oxlint + eslint fix + TypeScript typecheck + i18n check + format check - Format:
pnpm format— Biome format + lint (write mode) - Typecheck:
pnpm typecheck— Concurrent node + web TypeScript checks usingtsgo - i18n:
pnpm i18n:sync— Sync i18n template keyspnpm i18n:translate— Auto-translate missing keyspnpm i18n:check— Validate i18n completeness
- Bundle Analysis:
pnpm analyze:renderer/pnpm analyze:main— Visualize bundle sizes - Agents DB:
pnpm agents:generate— Generate Drizzle migrationspnpm agents:push— Push schema to SQLite DBpnpm agents:studio— Open Drizzle Studio
src/
main/ # Node.js backend (Electron main process)
renderer/ # React UI (Electron renderer process)
preload/ # Secure IPC bridge (contextBridge)
packages/
aiCore/ # @cherrystudio/ai-core — AI SDK middleware & provider abstraction
shared/ # Cross-process types, constants, IPC channel definitions
mcp-trace/ # OpenTelemetry tracing for MCP operations
ai-sdk-provider/ # Custom AI SDK provider implementations
extension-table-plus/ # TipTap table extension
| Alias | Resolves To |
|---|---|
@main |
src/main/ |
@renderer |
src/renderer/src/ |
@shared |
packages/shared/ |
@types |
src/renderer/src/types/ |
@logger |
src/main/services/LoggerService (main) / src/renderer/src/services/LoggerService (renderer) |
@mcp-trace/trace-core |
packages/mcp-trace/trace-core/ |
@cherrystudio/ai-core |
packages/aiCore/src/ |
Node.js backend services. Key services:
| Service | Responsibility |
|---|---|
WindowService |
Electron window lifecycle management |
MCPService |
Model Context Protocol server management |
KnowledgeService |
RAG / knowledge base (via @cherrystudio/embedjs) |
AnthropicService |
Anthropic API integration |
LoggerService |
Winston-based structured logging (daily rotate) |
StoreSyncService |
Syncs Redux state to/from main process |
BackupManager |
Data backup/restore (WebDAV, S3, Nutstore) |
ApiServerService |
Express HTTP API server (Swagger docs at /api-docs) |
AppUpdater |
electron-updater auto-update |
ShortcutService |
Global keyboard shortcuts |
ThemeService |
System theme detection/application |
SelectionService |
Text selection toolbar feature |
CopilotService |
GitHub Copilot OAuth integration |
PythonService |
Pyodide WASM Python runtime |
OvmsManager |
OpenVINO model server management |
NodeTraceService |
OpenTelemetry trace export |
Agents subsystem (src/main/services/agents/):
- Drizzle ORM + LibSQL (SQLite) schema at
database/schema/index.ts - Migrations in
resources/database/drizzle/ - Currently undergoing v2 refactor — only critical bug fixes accepted
React 19 + Redux Toolkit SPA. Key structure:
aiCore/ # Legacy middleware pipeline (deprecated, migrating to packages/aiCore)
api/ # IPC call wrappers (typed electron API calls)
components/ # Shared UI components (Ant Design 5 + styled-components + TailwindCSS v4)
databases/ # Dexie (IndexedDB) — topics, files, message_blocks, etc.
hooks/ # React hooks (useAssistant, useChatContext, useModel, etc.)
pages/ # Route pages (home, settings, knowledge, paintings, notes, etc.)
services/ # Frontend services (ApiService, ModelService, MemoryService, etc.)
store/ # Redux Toolkit slices
types/ # TypeScript type definitions
workers/ # Web Workers
windows/ # Multi-window entry points (mini, selection toolbar, trace)
Slices (redux-persist enabled):
| Slice | State |
|---|---|
assistants |
AI assistant configurations |
settings |
App-wide settings |
llm |
LLM provider/model configs |
mcp |
MCP server configs |
messageBlock |
Message block rendering state |
knowledge |
Knowledge base entries |
paintings |
Image generation state |
memory |
Memory system config |
websearch |
Web search settings |
shortcuts |
Keyboard shortcuts |
tabs |
Tab management |
BLOCKED: Do not add new Redux slices or change existing state shape until v2.0.0.
- IndexedDB (Dexie):
src/renderer/src/databases/index.ts- Tables:
files,topics,settings,knowledge_notes,translate_history,quick_phrases,message_blocks,translate_languages - Schema versioned with upgrade functions (
upgradeToV5,upgradeToV7,upgradeToV8) - BLOCKED: Do not modify schema until v2.0.0.
- Tables:
- SQLite (Drizzle ORM + LibSQL):
src/main/services/agents/- Used for the agents subsystem
- DB path:
~/.cherrystudio/data/agents.db(dev) /userData/agents.db(prod)
- Channel constants defined in
packages/shared/IpcChannel.ts - Renderer → Main:
ipcRenderer.invoke(IpcChannel.XXX, ...args)viaapi.*wrappers insrc/preload/index.ts - Main → Renderer:
webContents.send(channel, data) - Tracing:
tracedInvoke()in preload attaches OpenTelemetry span context to IPC calls - Typed API surface exposed via
contextBridgeaswindow.api
The @cherrystudio/ai-core package abstracts AI SDK providers:
src/core/
providers/ # Provider registry (HubProvider, factory, registry)
middleware/ # LanguageModelV2Middleware pipeline (manager, wrapper)
plugins/ # Built-in plugins
runtime/ # Runtime execution
options/ # Request option preparation
- Built on Vercel AI SDK v5 (
aipackage) withLanguageModelV2Middleware HubProvideraggregates multiple provider backends- Supports: OpenAI, Anthropic, Google, Azure, Mistral, Bedrock, Vertex, Ollama, Perplexity, xAI, HuggingFace, Cerebras, OpenRouter, Copilot, and more
- Custom fork of openai package:
@cherrystudio/openai
The renderer builds multiple HTML entry points:
index.html— Main application windowminiWindow.html— Compact floating window (src/renderer/src/windows/mini/)selectionToolbar.html— Text selection action toolbarselectionAction.html— Selection action popuptraceWindow.html— MCP trace viewer
import { loggerService } from "@logger";
const logger = loggerService.withContext("moduleName");
// Renderer only: loggerService.initWindowSource('windowName') first
logger.info("message", CONTEXT);
logger.warn("message");
logger.error("message", error);- Backend: Winston with daily log rotation
- Log files in
userData/logs/ - Never use
console.log— always useloggerService
packages/mcp-trace/provides trace-core and trace-node/trace-web adaptersNodeTraceServiceexports spans via OTLP HTTPSpanCacheServicecaches span entities for the trace viewer window- IPC calls can carry span context via
tracedInvoke()
| Layer | Technologies |
|---|---|
| Runtime | Electron 38, Node ≥22 |
| Frontend | React 19, TypeScript ~5.8 |
| UI | Ant Design 5.27, styled-components 6, TailwindCSS v4 |
| State | Redux Toolkit, redux-persist, Dexie (IndexedDB) |
| Rich Text | TipTap 3.2 (with Yjs collaboration) |
| AI SDK | Vercel AI SDK v5 (ai), @cherrystudio/ai-core |
| Build | electron-vite 5 with rolldown-vite 7 (experimental) |
| Test | Vitest 3 (unit), Playwright (e2e) |
| Lint/Format | ESLint 9, oxlint, Biome 2 |
| DB (main) | Drizzle ORM + LibSQL (SQLite) |
| DB (renderer) | Dexie (IndexedDB) |
| Logging | Winston + winston-daily-rotate-file |
| Tracing | OpenTelemetry |
| i18n | i18next + react-i18next |
- Strict mode enabled; use
tsgo(native TypeScript compiler preview) for typechecking - Separate configs:
tsconfig.node.json(main),tsconfig.web.json(renderer) - Type definitions centralized in
src/renderer/src/types/andpackages/shared/
- Biome handles formatting (2-space indent, single quotes, trailing commas)
- oxlint + ESLint for linting;
simple-import-sortenforces import order - React hooks:
eslint-plugin-react-hooksenforced - No unused imports:
eslint-plugin-unused-imports
- React components:
PascalCase.tsx - Services, hooks, utilities:
camelCase.ts - Test files:
*.test.tsor*.spec.tsalongside source or in__tests__/subdirectory
- All user-visible strings must use
i18next— never hardcode UI strings - Run
pnpm i18n:checkto validate;pnpm i18n:syncto add missing keys - Locale files in
src/renderer/src/i18n/
Several dependencies have patches in patches/ — be careful when upgrading:
antd,@ai-sdk/google,@ai-sdk/openai,@anthropic-ai/vertex-sdk@google/genai,@langchain/core,@langchain/openaiollama-ai-provider-v2,electron-updater,epub,tesseract.js@anthropic-ai/claude-agent-sdk
- Tests use Vitest 3 with project-based configuration
- Main process tests: Node environment,
tests/main.setup.ts - Renderer tests: jsdom environment,
tests/renderer.setup.ts,@testing-library/react - aiCore tests: separate
packages/aiCore/vitest.config.ts - All tests run without CI dependency (fully local)
- Coverage via v8 provider (
pnpm test:coverage) - Features without tests are not considered complete
Files marked with the following header are blocked for feature changes:
/**
* @deprecated Scheduled for removal in v2.0.0
* ⚠️ NOTICE: V2 DATA&UI REFACTORING
* STOP: Feature PRs affecting this file are currently BLOCKED.
*/Do not introduce new features to these files. Bug fixes only.
- Never expose Node.js APIs directly to renderer; use
contextBridgein preload - Validate all IPC inputs in main process handlers
- URL sanitization via
strict-url-sanitise - IP validation via
ipaddr.js(API server) express-validatorfor API server request validation