This commit adds 6 new documentation files to fill critical gaps: - CONTRIBUTING.md: Developer onboarding guide with setup, workflow, code style, testing, and adding features - TROUBLESHOOTING.md: Common issues and solutions for errors, model issues, tool issues, channel issues, gateway issues, configuration issues, and memory/database issues - docs/api/PROTOCOL.md: Gateway JSON-RPC protocol documentation with connection, authentication, message format, methods, events, error codes, and example client implementation - docs/api/TOOLS.md: Tools API documentation covering tool interface, input schema format, result format, tool patterns, tool registration, tool policy, execution flow, and builtin tools reference - docs/deployment/PRODUCTION.md: Production deployment guide covering Docker deployment, systemd service, security, configuration, monitoring, backup & recovery, and performance tuning - docs/performance/TUNING.md: Performance optimization guide covering context management, model routing, tool execution, memory & embeddings, session management, database performance, gateway performance, and resource usage These files complement the existing excellent documentation (README.md, AGENTS.md, ARCHITECTURE.md, STRUCTURE.md, CONVENTIONS.md) to provide complete coverage for users, developers, and operators.
11 KiB
Contributing to Flynn
Thank you for your interest in contributing to Flynn! This guide will help you get started.
Table of Contents
- Quick Start
- Development Setup
- Development Workflow
- Code Style
- Testing
- Adding Features
- Commit Guidelines
- Submitting Changes
- Getting Help
Quick Start
# Clone the repository
git clone <repo-url>
cd flynn
# Install dependencies
pnpm install
# Build the project
pnpm build
# Run the daemon
pnpm start
Development Setup
Prerequisites
- Node.js >= 22.0.0
- pnpm (package manager)
- Docker (optional, for sandbox features)
Installation
# Install dependencies
pnpm install
# Verify TypeScript compiles
pnpm typecheck
# Run linter
pnpm lint
# Run tests
pnpm test
Development Commands
| Command | Description |
|---|---|
pnpm build |
Compile TypeScript to dist/ |
pnpm dev |
Run daemon with watch mode (tsx watch) |
pnpm start |
Start production build |
pnpm tui |
Minimal TUI (readline) |
pnpm tui:fs |
Fullscreen TUI (React/Ink) |
pnpm test |
Run vitest in watch mode |
pnpm test:run |
Run tests once (CI) |
pnpm lint |
Run ESLint |
pnpm typecheck |
TypeScript check (no emit) |
Running a Single Test File
pnpm test:run src/path/to/file.test.ts
Configuration for Development
Create a development config:
cp config/default.yaml ~/.config/flynn/config.yaml
# Edit config with your API keys and settings
Development Workflow
Branching Strategy
- Main branch:
main- stable production code - Feature branches:
feature/description- new features - Bugfix branches:
bugfix/description- bug fixes - Refactor branches:
refactor/description- code improvements
Feature Development
-
Create a feature branch from
maingit checkout -b feature/my-new-feature -
Make your changes
-
Build and test
pnpm build pnpm test pnpm lint pnpm typecheck -
Commit your changes (see Commit Guidelines)
-
Push and create a pull request
Committing Changes
Before committing, ensure:
- All tests pass:
pnpm test:run - Linting passes:
pnpm lint - Type checking passes:
pnpm typecheck - Build succeeds:
pnpm build
git add .
git commit -m "feat: add my new feature"
Code Style
Flynn follows specific conventions documented in .planning/codebase/CONVENTIONS.md.
Key Guidelines
- 2-space indentation (no tabs)
- Single quotes for strings
- Trailing commas in multiline structures
- Semicolons always used
- camelCase for functions/variables
- PascalCase for classes/interfaces
- kebab-case for source files (
my-feature.ts) - PascalCase for React components (
MyComponent.tsx) - Test files co-located with source:
file.test.tsbesidefile.ts
Import Organization
// 1. Node.js stdlib
import { readFileSync } from 'fs';
import { execFile } from 'child_process';
// 2. Third-party packages
import Anthropic from '@anthropic-ai/sdk';
import { z } from 'zod';
// 3. Local imports (always use .js extension)
import { NativeAgent } from './agent.js';
import type { Config } from '../config/schema.js';
Error Handling
// Pattern 1: Return ToolResult with error (tools)
try {
const result = await someOperation();
return { success: true, output: result };
} catch (error) {
return {
success: false,
output: '',
error: error instanceof Error ? error.message : String(error),
};
}
// Pattern 2: Throw with descriptive message (config/setup)
if (envValue === undefined) {
throw new Error(`Environment variable ${envVar} is not set`);
}
Testing
Test Framework
Flynn uses Vitest for testing. Test files are co-located with source files:
src/
├── agent.ts
├── agent.test.ts
├── models/
│ ├── anthropic.ts
│ └── anthropic.test.ts
Writing Tests
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { MyComponent } from './my-component.js';
describe('MyComponent', () => {
beforeEach(() => {
// Setup before each test
});
afterEach(() => {
// Cleanup after each test
});
it('should do something correctly', () => {
const result = MyComponent.doSomething();
expect(result).toBe('expected-value');
});
it('should handle errors gracefully', () => {
expect(() => MyComponent.doSomethingInvalid()).toThrow();
});
});
Testing Guidelines
- Test both success and failure cases
- Clean up resources (files, directories) in
afterEachoritblocks - Mock external dependencies (APIs, databases, filesystem)
- Use
describe/itpattern for organization - Keep tests focused and independent
Running Tests
# Watch mode (during development)
pnpm test
# Run once (CI/pre-commit)
pnpm test:run
# Run specific test file
pnpm test:run src/models/anthropic.test.ts
# Run tests matching pattern
pnpm test -- --grep "anthropic"
Adding Features
Adding a New Tool
Flynn tools follow three patterns:
Pattern 1: Static Tool (no dependencies)
// src/tools/builtin/my-tool.ts
import type { Tool, ToolResult } from '../types.js';
interface MyToolArgs {
input: string;
}
export const myTool: Tool = {
name: 'my.tool',
description: 'Description of what this tool does',
inputSchema: {
type: 'object',
properties: {
input: { type: 'string', description: 'Input parameter' },
},
required: ['input'],
},
execute: async (rawArgs: unknown): Promise<ToolResult> => {
const args = rawArgs as MyToolArgs;
// Implementation
return { success: true, output: 'result' };
},
};
Pattern 2: Factory Tool (needs dependency injection)
// src/tools/builtin/memory-read.ts
import type { Tool, ToolResult } from '../types.js';
import type { MemoryStore } from '../../memory/store.js';
export function createMemoryReadTool(store: MemoryStore): Tool {
return {
name: 'memory.read',
description: 'Read from memory store',
inputSchema: {
type: 'object',
properties: {
namespace: { type: 'string', description: 'Memory namespace' },
},
required: ['namespace'],
},
execute: async (rawArgs: unknown): Promise<ToolResult> => {
const args = rawArgs as { namespace: string };
try {
const content = store.read(args.namespace);
return { success: true, output: content };
} catch (error) {
return {
success: false,
output: '',
error: error instanceof Error ? error.message : String(error),
};
}
},
};
}
Pattern 3: Multi-Factory (related tool set)
// src/tools/builtin/index.ts
export function createMemoryTools(store: MemoryStore, hybridSearch?: HybridSearch): Tool[] {
return [
createMemoryReadTool(store),
createMemoryWriteTool(store),
createMemorySearchTool(store, hybridSearch),
];
}
Registration Steps:
- Add export to
src/tools/builtin/index.ts - Add export to
src/tools/index.ts - Register in
src/daemon/index.ts(call factory + register) - Add to tool profiles in
src/tools/policy.tsif needed - Write tests in
src/tools/builtin/my-tool.test.ts
Adding a New Channel Adapter
- Create directory:
src/channels/<platform>/ - Create
adapter.tsimplementingChannelAdapterinterface - Create
index.tsre-exporting the adapter - Add test:
adapter.test.ts - Register in
src/channels/index.ts - Register in
src/daemon/index.ts - Add config schema in
src/config/schema.ts
Adding a New Model Provider
- Create
src/models/<provider>.tsimplementingModelClientinterface - Add export to
src/models/index.ts - Add case in
src/daemon/index.ts→createClientFromConfig() - Add to
src/config/schema.ts→modelConfigBaseSchema.providerenum - Write tests in
src/models/<provider>.test.ts
Adding a New CLI Command
// src/cli/my-cmd.ts
import { Command } from 'commander';
import { loadConfigSafe } from './shared.js';
export function registerMyCommand(program: Command) {
program
.command('my-cmd')
.description('Description of my command')
.option('-c, --config <path>', 'Config file path')
.action(async (options) => {
const configResult = await loadConfigSafe(options.config);
if (configResult.error) {
console.error(configResult.error);
process.exit(1);
}
// Implementation
});
}
Register in src/cli/index.ts:
import { registerMyCommand } from './my-cmd.js';
// In registerCommands()
registerMyCommand(program);
Commit Guidelines
Commit Message Format
Follow conventional commits:
<type>(<scope>): <description>
[optional body]
[optional footer]
Types
feat: New featurefix: Bug fixrefactor: Code refactoring (no functional change)docs: Documentation changestest: Test additions/modificationschore: Build process, dependencies, toolingstyle: Code style changes (formatting, semicolons, etc.)
Examples
feat(tools): add image analysis tool
Implements image analysis using OpenAI Vision API.
Closes #123
fix(gateway): handle WebSocket disconnection gracefully
Prevents infinite loop when connection drops during event emission.
docs(readme): update quick start instructions
Clarify configuration steps for new users.
test(models): add Anthropic client retry tests
Verify exponential backoff and fallback behavior.
Submitting Changes
Pull Request Process
-
Ensure your branch is up to date with
maingit fetch origin git rebase origin/main -
Push your branch
git push -u origin feature/my-new-feature -
Create a pull request with:
- Clear description of changes
- Reference related issues
- Screenshots if UI changes
- Test results
- Breaking changes noted
Code Review Checklist
Before submitting, verify:
- All tests pass (
pnpm test:run) - Linting passes (
pnpm lint) - Type checking passes (
pnpm typecheck) - Build succeeds (
pnpm build) - New features have tests
- Documentation updated (README, AGENTS.md, code comments)
- No console.log or debugger statements
- Sensitive data not committed (API keys, tokens)
- Commit messages follow format
Getting Help
Documentation
- Architecture:
.planning/codebase/ARCHITECTURE.md - Structure:
.planning/codebase/STRUCTURE.md - Conventions:
.planning/codebase/CONVENTIONS.md - Developer Guide:
AGENTS.md - User Documentation:
README.md
Troubleshooting
See TROUBLESHOOTING.md for common issues and solutions.
Questions?
- Open an issue for bugs or feature requests
- Start a discussion for questions
- Check existing issues and discussions first
Thank you for contributing to Flynn!