Skip to content

Contributing

Michael Elliott edited this page Apr 5, 2026 · 2 revisions

Contributing to TITAN

Thank you for your interest in contributing to TITAN! This guide covers everything you need to submit high-quality pull requests.

PR Process

1. Fork & Branch

# Fork the repo on GitHub, then:
git clone https://github.com/YOUR_USERNAME/TITAN.git
cd TITAN
npm install
git checkout -b feat/my-feature    # or fix/, docs/, refactor/

2. Develop & Test

Make your changes, then run the full validation suite:

npm run typecheck    # TypeScript strict — must pass with 0 errors
npm run lint         # ESLint — fix any warnings
npm run test         # All 4,655+ tests must pass
npm run build        # Backend build (tsup, ESM)
npm run build:ui     # React SPA build (Vite)

Or use the combined CI command:

npm run ci           # Typecheck + full test suite

3. Commit & Push

git commit -m "feat: add my feature"    # Use conventional commit style
git push origin feat/my-feature

4. Open a Pull Request

Open a PR against the main branch. Fill out the PR template completely.

PR Template

Every PR should include:

Section What to write
What Brief description of the change
Why What problem this solves or feature it adds
How Key implementation details, non-obvious decisions
Testing Checklist: typecheck, build, tests, manual testing
Checklist No TS errors, no ESLint warnings, version bumped if release, README updated if user-facing, no secrets in diff

Coding Standards

TypeScript Strict Mode

TITAN uses TypeScript strict mode with these compiler options:

  • Target: ES2022
  • Module: ESNext (pure ESM — no CommonJS)
  • Strict: true (all strict checks enabled)
  • noImplicitReturns: true
  • noFallthroughCasesInSwitch: true
  • isolatedModules: true

ESM Only

TITAN is a pure ESM package. Never use require().

// ✅ Correct
import { something } from './module.js';
import type { MyType } from './types.js';

// ❌ Wrong
const something = require('./module');
  • Use import.meta.url instead of __dirname
  • All import paths must include the .js extension
  • "type": "module" is set in package.json

Runtime Validation with Zod

All configuration and external input uses Zod schemas for runtime validation. Config defaults are defined in src/config/schema.ts.

ESLint Rules

Key lint rules enforced:

Rule Setting
@typescript-eslint/no-explicit-any warn
@typescript-eslint/no-unused-vars warn (prefix unused args with _)
@typescript-eslint/consistent-type-imports warn
prefer-const error
no-var error

Code Style

  • Prefer named exports
  • Use the TITAN logger for all output — no bare console.log in library code
  • All async functions should handle errors
  • Tool names must be snake_case
  • Tool descriptions should be clear and concise (the LLM reads these to decide when to use tools)
  • Keep tools focused — one action per tool

Test Writing

Framework: Vitest

TITAN uses Vitest with the following configuration:

// vitest.config.ts
{
  globals: true,
  environment: 'node',
  include: ['tests/**/*.test.ts'],
  testTimeout: 30000,
  hookTimeout: 25000,
}

Current Stats

Metric Value
Total tests 4,655+
Test files 154
E2E tests 135+ (Playwright, 7 spec files)
Line coverage ~82%

Coverage Thresholds

CI enforces these minimums:

Metric Threshold
Branches 75%
Functions 60%
Lines 60%
Statements 60%

Writing Tests

// tests/skills/my_skill.test.ts
import { describe, it, expect, beforeAll } from 'vitest';

describe('my_skill', () => {
  it('should do the thing', async () => {
    const result = await myFunction();
    expect(result).toBe('expected');
  });
});

Rules:

  • All new features must have tests
  • All new skills must have a corresponding test file in tests/
  • Tests live in the tests/ directory (not alongside source)
  • Use describe/it/expect from Vitest
  • Async tests use async/await, not callbacks
  • Mock external API calls — tests should be fast
  • Use heavy vi.mock() patterns where needed (see tests/gateway-extended.test.ts for examples)
  • Don't let coverage drop below thresholds

Version Bump Protocol

TITAN uses semantic versioning (e.g., 1.1.1). When bumping the version, all 5 files must be updated together:

# File What to change
1 package.json "version" field
2 src/utils/constants.ts TITAN_VERSION constant
3 tests/core.test.ts Version assertion string
4 tests/mission-control.test.ts Version references (4 occurrences)
5 CHANGELOG.md Add new entry at top

CI runs a version consistency check that verifies all 5 locations match. PRs will fail if they're out of sync.

Note: Only the project maintainer (Tony) approves and publishes version bumps. Do not bump the version in feature PRs unless instructed.


Build Commands

Command Description
npm install Install dependencies
npm run build Production backend build (tsup → dist/)
npm run build:ui React SPA build (Vite → ui/dist/)
npm run typecheck TypeScript type checking (tsc --noEmit)
npm run lint Run ESLint
npm run lint:fix Auto-fix linting issues
npm run test Run all tests (Vitest)
npm run test:watch Run tests in watch mode
npm run test:coverage Generate coverage report
npm run ci Typecheck + full test suite
npm run dev Start CLI in dev mode (tsx)
npm run dev:gateway Start gateway in dev mode
npm start Run production build

CI Pipeline

TITAN uses GitHub Actions (.github/workflows/ci.yml). CI runs on every push to main and every pull request.

What CI Runs

Test Job (matrix: Node 22 + 24)

  1. npm ci — Clean install
  2. npm run lint — ESLint check
  3. npm run typecheck — TypeScript strict mode check
  4. npm run build — Backend build
  5. npm run build:ui — UI build
  6. npx vitest run — Full test suite
  7. Coverage report (Node 22 only)

Health Job

  1. Version consistency check — Verifies all 5 version locations match
  2. Doc accuracy check — Validates CLAUDE.md and README.md contain current version
  3. npm publish dry-run — Ensures package is publishable
  4. Docker build smoke test — Verifies Dockerfile builds correctly

Coverage Check (PRs only)

  • Downloads coverage artifact from test job
  • Fails if line coverage drops below 60%

Node.js Requirements

  • Minimum: Node.js 20 ("engines": { "node": ">=20.0.0" })
  • CI tested: Node.js 22 and 24
  • Node 18 is not supported

Adding Skills, Providers & Channels

Adding a New Skill

  1. Create the skill file at src/skills/builtin/my_skill.ts:
import { registerSkill } from '../registry.js';

export function registerMySkill(): void {
  registerSkill({
    name: 'my_tool',           // snake_case required
    description: 'Does something useful',
    parameters: {
      type: 'object',
      properties: {
        input: { type: 'string', description: 'The input' }
      },
      required: ['input']
    },
    execute: async (args: { input: string }) => {
      return `Result: ${args.input}`;
    }
  });
}
  1. Register in src/skills/registry.tsinitBuiltinSkills():
import { registerMySkill } from './builtin/my_skill.js';
registerMySkill();
  1. Add to build config in package.jsontsup.entry

  2. Write tests in tests/skills/my_skill.test.ts

Adding a New Provider

OpenAI-Compatible (most common): Add an entry to the PROVIDERS config in src/providers/openai_compat.ts:

myprovider: {
  name: 'MyProvider',
  baseUrl: 'https://api.myprovider.com/v1',
  envKey: 'MYPROVIDER_API_KEY',
  models: ['myprovider/model-large', 'myprovider/model-small']
}

Native Provider (different API):

  1. Create src/providers/my_provider.ts
  2. Extend LLMProvider from base.ts
  3. Implement: chat(), chatStream(), listModels(), healthCheck()
  4. Register in src/providers/router.ts

Adding a New Channel

  1. Create src/channels/my_channel.ts
  2. Extend ChannelAdapter from base.ts
  3. Implement: connect(), disconnect(), send(), getStatus()
  4. Register in src/gateway/server.ts

See existing adapters (discord.ts, telegram.ts, slack.ts) for the pattern.


Architecture Overview

src/
  agent/        Core agent loop, multi-agent, orchestrator, goals, Command Post
  browsing/     Shared browser pool, CAPTCHA solving
  channels/     15 channel adapters
  config/       Zod-validated config schema
  context/      ContextEngine plugin system
  gateway/      Express HTTP/WS server + Mission Control
  mcp/          Model Context Protocol server
  memory/       Episodic, learning, relationship, temporal graph
  mesh/         P2P mesh networking (mDNS, WebSocket)
  providers/    36 LLM providers (4 native + 32 OpenAI-compatible)
  skills/       100+ skills exposing ~195 tools
  utils/        Constants, logger, helpers
  voice/        LiveKit WebRTC voice
  vram/         GPU VRAM orchestrator
ui/             React 19 SPA (Vite + Tailwind CSS 4)
tests/          154 vitest test files
e2e/            Playwright E2E tests

License

By contributing, you agree that your contributions will be licensed under the MIT License.

Clone this wiki locally