Skip to content

Development Setup

Ankur Nair edited this page Apr 19, 2026 · 1 revision

Development Setup

Dev environment for contributors and anyone who wants to build from source.


Prerequisites

Tool Minimum Purpose
Bun 1.2.0 Package manager, test runner, scripts
Node.js 20 LTS Used by electron-vite for native-module rebuilds
Git any recent Obvious
Build toolchain OS-specific Xcode CLI on macOS, build-essential on Linux, MSVC on Windows

Install Bun

curl -fsSL https://bun.sh/install | bash

Then restart your shell. Verify: bun --version.

Install Node (if not already)

macOS (homebrew):

brew install node@20

Linux (nvm):

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
nvm install 20
nvm use 20

Clone + install

git clone https://github.com/CES-Ltd/TitanX.git
cd TitanX
bun install

bun install takes about 60 seconds first time (fetches ~1800 packages including Electron 37 and native modules like better-sqlite3 and @napi-rs/canvas).


Run in dev mode

bun run start

This launches electron-vite dev:

  • Vite dev server for renderer on http://localhost:5173 (with HMR)
  • Electron main process with --inspect on port 9229
  • CDP (Chrome DevTools Protocol) on port 9230 (you can attach DevTools MCP to this if you're using Claude Code / similar)
  • Opens the TitanX window

Edits to renderer code (src/renderer/) hot-reload in under 500ms. Edits to main-process code (src/process/) require a full restart — the app auto-reloads after Vite rebuilds.


Run tests

bun run test           # watch mode (Vitest 4)
bun run test:coverage  # one-shot with coverage report

Coverage target: ≥ 80%. CI enforces this; local runs don't block.

Test file conventions:

  • *.test.ts next to the module under test
  • __tests__/ folder for tests that span multiple modules
  • Vitest config in vitest.config.ts

See the testing skill for the full test strategy.


Build production artifacts

bun run build       # macOS arm64 + x64 (~5 min)

This wraps scripts/build-with-builder.js which:

  1. Runs electron-vite build (TypeScript → bundles in out/main/ + out/renderer/ + out/preload/)
  2. Runs electron-builder (packages each arch into a .app + .dmg + .zip)
  3. Signs the .app with an ad-hoc signature (no Apple Developer ID)
  4. Rebuilds native modules per-arch using prebuild-install

Artifacts land in out/:

  • TitanX-<version>-mac-arm64.dmg
  • TitanX-<version>-mac-x64.dmg
  • (Linux targets if you're on Linux; Windows similarly)

Code quality

Run these before opening a PR:

bunx tsc --noEmit     # type check
bun run lint:fix      # oxlint auto-fix
bun run format        # oxfmt auto-format

And to replicate the CI prek check locally (one-time install):

npm install -g @j178/prek
prek run --from-ref origin/main --to-ref HEAD

The prek check fails on:

  • Type errors
  • Lint errors (warnings OK)
  • Formatting drift (run bun run format to fix)
  • Missing newline at EOF, trailing whitespace

i18n

If you touch src/renderer/, locales/, or src/common/config/i18n, also run:

bun run i18n:types            # regenerates type definitions
node scripts/check-i18n.js    # validates all 10 locale files are in sync

Both must pass before PR. The i18n skill documents the full workflow.


Project structure at a glance

src/
├── process/           # Main process (Node + Electron APIs)
│   ├── agent/           # LLM provider adapters
│   ├── team/            # TeammateManager, Team MCP, Lead orchestration
│   ├── task/            # Conversation + agent manager (ACP + API)
│   ├── services/        # IAM, audit, fleet, dream, reasoning bank, ...
│   └── webserver/       # Fleet HTTP surface (master only)
│
├── renderer/          # Chromium sandbox (React + UnoCSS + Arco Design)
│   ├── components/      # Shared UI
│   ├── pages/           # Route-level views
│   └── hooks/           # Custom React hooks
│
├── common/            # Code shared between processes
│   ├── types/           # Shared types (team, agent, fleet, ...)
│   ├── adapter/         # IPC bridge shape
│   └── utils/           # Pure helpers
│
├── process/worker/    # Child-fork workers for CPU-heavy tasks
└── preload.ts         # The IPC boundary

Strict rule: never cross-import process boundaries. renderer/ importing from process/agent/ is a compile error. Use the IPC bridge.

Full conventions: docs/conventions/file-structure.md.


Adding a database migration

// In src/process/services/database/migrations.ts
const migration_v74: IMigration = {
  version: 74,
  name: 'Add my new column',
  up: (db) => {
    db.exec(`ALTER TABLE my_table ADD COLUMN my_new_column TEXT`);
  },
  down: (db) => {
    try {
      db.exec(`ALTER TABLE my_table DROP COLUMN my_new_column`);
    } catch { /* older SQLite — leave in place */ }
  },
};

// Register in ALL_MIGRATIONS array
// Bump CURRENT_DB_VERSION in schema.ts to 74

Rules:

  • Every up() must have a working down()
  • Default-safe columns (nullable or with defaults) — don't break older code paths
  • Never rename existing columns (add new, migrate data, drop old in a later version)
  • Run bun run test — migration tests catch most mistakes

Debugging

Renderer process

  • Open DevTools in the dev app: View → Toggle Developer Tools (or Cmd/Ctrl+Alt+I)
  • Network tab + Console tab work as expected

Main process

  • Run bun run start — the --inspect flag opens Node's inspector on localhost:9229
  • Attach VS Code / Chrome DevTools to that port
  • Or use console.log — output goes to the terminal you launched from

SQLite

The DB lives at ~/.aionui-config/aionui.db. Inspect with:

sqlite3 ~/.aionui-config/aionui.db ".tables"
sqlite3 ~/.aionui-config/aionui.db "SELECT * FROM teams LIMIT 5;"

Or use GUI tools — DB Browser for SQLite works well.


Common pitfalls

"Cannot find module 'better-sqlite3'" — the native module didn't build for your Node version. Run bun install again; if still broken, delete node_modules + re-install.

Hot reload doesn't pick up my change — some TypeScript errors cause Vite to silently fail the rebuild. Check the terminal where bun run start is running for the actual error.

App launches but hangs on splash screen — SQLite migration failed. Check the terminal output; a migration error will print before the window would have shown. Common causes: disk full, file permissions on ~/.aionui-config/, or a botched prior migration left the DB at an intermediate version.

Type errors in src/common/* — this folder is compiled for both processes. If you use anything Node-only or DOM-only, the types will fail. Keep src/common/ pure (no filesystem, no DOM).


Pull request workflow

See the oss-pr skill for the canonical flow:

  1. Branch from main (no direct commits to main)
  2. bun run test && bunx tsc --noEmit && bun run lint:fix && bun run format all green
  3. Commit with conventional format: feat(scope): subject, no AI signatures
  4. Open PR with summary + test plan
  5. Automated PR review daemon may comment — address or justify
  6. Merge squash; version bump + release happens at your branch's cadence

Related pages

Clone this wiki locally