This file provides guidance for AI agents working in the Darkwrite codebase.
Darkwrite is a note-taking application and personal knowledge base built with:
- Frontend: React 19, Redux Toolkit + RTK Query, Vite, TailwindCSS 4
- Desktop: Electron (latest), TypeScript
- Database: libsql with Drizzle ORM
- Monorepo: pnpm workspaces with Turbo
darkwrite/
├── packages/
│ ├── frontend/ # React SPA (Vite + Electron renderer)
│ ├── app-desktop/ # Electron main process + desktop app
│ ├── common/ # Shared types and utilities
│ └── website/ # Marketing site (Astro)
└── tools/ # Build tools
pnpm test # Run all tests across packages
pnpm lint # Run linting across packages
pnpm format # Format code across packages
pnpm typecheck # Type check across packages
pnpm build # Build all packagescd packages/frontend
pnpm dev # Start dev server
pnpm build # Build for production
pnpm lint # Lint with Biome
pnpm format # Format with Biome
pnpm test # Run tests (Vitest)
pnpm test:watch # Watch mode
pnpm test:run -- path # Run single test file
pnpm typecheck # TypeScript checkTip
Read @packages/frontend/AGENTS.md for additional context when working on the frontend package. If you are not going to touch frontend code, do not read this file.
cd packages/app-desktop
pnpm dev # Start in dev mode
pnpm build:pre # Pre-build for Electron
pnpm build:mac # Build macOS app
pnpm build:win # Build Windows app
pnpm build:linux # Build Linux app
pnpm test # Run tests (includes rebuild)
pnpm test:run # Run tests only
pnpm test:run -- path # Run single test file
pnpm coverage # Run tests with coveragecd packages/common
pnpm build # Build TypeScript to JS
pnpm test # Run tests
pnpm lint # Lint
pnpm typecheck # Type check# Frontend - run single test file
cd packages/frontend
pnpm test:run -- src/lib/utils.test.ts
# App Desktop - run single test file
cd packages/app-desktop
pnpm test:run src/lib/some.test.ts- Indent: 2 spaces
- Strings: Double quotes
- Semicolons: Required
- Line length: Keep under 80 characters
- Naming: camelCase for variables/functions, PascalCase for React components
Do NOT mention, reference, acknowledge, or allude to any issue that Biome can autofix. Pretend those issues don't exist. Do not mention that you skipped them either.
- Use kebab-case for file names
- Suffix files by type:
- Tests:
.test.tsor.test.tsx - Main process services:
.service.ts - Main process DAOs:
.dao.ts - IPC handlers:
.handler.ts
- Tests:
- NEVER use
as unknown as Typecasts anytype is forbidden - ask user if you encounter this- Do not fix type errors outside your refactor scope
- If you cannot resolve a TypeScript error without casting, ask for confirmation
classandthisshould not be used for new code under any circumstances unless there is a good reason for it. Factory methods and closures should be preferred instead with minimal dependencies.
- Use path aliases configured in tsconfig (e.g.,
@/,@darkwrite/common) - Frontend:
@/maps tosrc/ - Always check if reusable components exist in
src/componentsbefore creating new ones
- When reviewing migration SQL, always explicitly check for column names when a table copy is applicable.
- Always make sure the SQL statements have
--> statement-breakpointcomments between individual statements. Without these comments, only the first statement will actually be applied.
- Transactions must be handled using our custom transaction manager defined in @packages/app-desktop/src/db/transactional.ts
transactional(() => ResultAsync)should be used in services where a transaction context is necessary. Subsequent calls totransactional()within the passed callback will join DAOs to the same transaction automatically. Use this pattern to make multiple services and DAOs share the same transaction.ResultandResultAsyncmust be preferred over regular promises.- Do NOT use
db.transaction(async tx => ...)ortx.transaction(async tx => ...)unless you ABSOLUTELY need that savepoint. More often than not, you don't.
- Never silently swallow errors
- Use proper error boundaries in React components
- Log errors with appropriate context
- Error handling is augmented with the
neverthrowlibrary. Do NOT usethrowstatements outside of tests. If an error is truly unrecoverable from (i.e. programming errors), usepanic()from@darkwrite/commoninstead, as a last resort. Result/ResultAsync._unsafeUnwrapMUST NOT be used in production code unless you are trying to interact with something that cannot handleResults._unsafeUnwrap()and_unsafeUnwrapErr()are perfectly fine in tests (an incorrect unwrap should fail the test), and should be preferred to test the expected cases directly.
- Use pre-defined Redux slices, selectors and thunks
- If a thunk is calling/delegating to another thunk, make sure it's dispatched and we are not returning a function reference/no-op.
- RTK Query has been deprecated in this codebase.
- Use
DarkwriteAPIClientfrom@/api/api-client.ts - DO NOT use
window.apidirectly - API types are defined in
@darkwrite/commonpackage, in src/contract.ts - Do not call Data Access Object (DAO) methods in IPC handler methods. Always use the corresponding service method instead.
- The main process must be treated as an interface to the database for persistence, and the operating system for integration. Business logic should stay in the renderer process as much as possible.
- SQLite is not the source of truth at runtime, it's a persistence path for Redux.
- Test files use Vitest with
@testing-library - Follow existing test patterns in each package
- Mock Electron APIs in renderer tests
.editorconfighandles basic formattingbiome.json(root) configures linting and formatting (Biome)- The
websitepackage uses Prettier (via.prettierrc) for Astro file support
nodeIntegrationwill not be enabled under any circumstances. No excuses.- Be on the look out for XSS attack vectors as this app deals with rich text.
src/features/<feature>/
├── components/ # Feature-specific React components
├── hooks/ # Custom React hooks
├── store/ # Redux slice, selectors, RTK Query APIs
└── types.ts # Feature-specific types
src/electron/
├── note/ # Note-related business logic
├── database/ # Database operations
├── workspace/ # Workspace management
├── ipc/ # IPC handlers
└── entity/ # SQLite entities
If a new dependency is required, ask the user before proceeding with installation.