docs: Add comprehensive documentation for production deployment and contribution
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.
This commit is contained in:
+491
@@ -0,0 +1,491 @@
|
||||
# Contributing to Flynn
|
||||
|
||||
Thank you for your interest in contributing to Flynn! This guide will help you get started.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Quick Start](#quick-start)
|
||||
- [Development Setup](#development-setup)
|
||||
- [Development Workflow](#development-workflow)
|
||||
- [Code Style](#code-style)
|
||||
- [Testing](#testing)
|
||||
- [Adding Features](#adding-features)
|
||||
- [Commit Guidelines](#commit-guidelines)
|
||||
- [Submitting Changes](#submitting-changes)
|
||||
- [Getting Help](#getting-help)
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
pnpm test:run src/path/to/file.test.ts
|
||||
```
|
||||
|
||||
### Configuration for Development
|
||||
|
||||
Create a development config:
|
||||
|
||||
```bash
|
||||
cp config/default.yaml ~/.config/flynn/config.yaml
|
||||
# Edit config with your API keys and settings
|
||||
```
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Branching Strategy
|
||||
|
||||
1. **Main branch**: `main` - stable production code
|
||||
2. **Feature branches**: `feature/description` - new features
|
||||
3. **Bugfix branches**: `bugfix/description` - bug fixes
|
||||
4. **Refactor branches**: `refactor/description` - code improvements
|
||||
|
||||
### Feature Development
|
||||
|
||||
1. Create a feature branch from `main`
|
||||
```bash
|
||||
git checkout -b feature/my-new-feature
|
||||
```
|
||||
|
||||
2. Make your changes
|
||||
|
||||
3. Build and test
|
||||
```bash
|
||||
pnpm build
|
||||
pnpm test
|
||||
pnpm lint
|
||||
pnpm typecheck
|
||||
```
|
||||
|
||||
4. Commit your changes (see [Commit Guidelines](#commit-guidelines))
|
||||
|
||||
5. 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`
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "feat: add my new feature"
|
||||
```
|
||||
|
||||
## Code Style
|
||||
|
||||
Flynn follows specific conventions documented in [`.planning/codebase/CONVENTIONS.md`](.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.ts` beside `file.ts`
|
||||
|
||||
### Import Organization
|
||||
|
||||
```typescript
|
||||
// 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
|
||||
|
||||
```typescript
|
||||
// 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
|
||||
|
||||
```typescript
|
||||
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 `afterEach` or `it` blocks
|
||||
- Mock external dependencies (APIs, databases, filesystem)
|
||||
- Use `describe`/`it` pattern for organization
|
||||
- Keep tests focused and independent
|
||||
|
||||
### Running Tests
|
||||
|
||||
```bash
|
||||
# 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)
|
||||
|
||||
```typescript
|
||||
// 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)
|
||||
|
||||
```typescript
|
||||
// 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)
|
||||
|
||||
```typescript
|
||||
// src/tools/builtin/index.ts
|
||||
export function createMemoryTools(store: MemoryStore, hybridSearch?: HybridSearch): Tool[] {
|
||||
return [
|
||||
createMemoryReadTool(store),
|
||||
createMemoryWriteTool(store),
|
||||
createMemorySearchTool(store, hybridSearch),
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
**Registration Steps:**
|
||||
|
||||
1. Add export to `src/tools/builtin/index.ts`
|
||||
2. Add export to `src/tools/index.ts`
|
||||
3. Register in `src/daemon/index.ts` (call factory + register)
|
||||
4. Add to tool profiles in `src/tools/policy.ts` if needed
|
||||
5. Write tests in `src/tools/builtin/my-tool.test.ts`
|
||||
|
||||
### Adding a New Channel Adapter
|
||||
|
||||
1. Create directory: `src/channels/<platform>/`
|
||||
2. Create `adapter.ts` implementing `ChannelAdapter` interface
|
||||
3. Create `index.ts` re-exporting the adapter
|
||||
4. Add test: `adapter.test.ts`
|
||||
5. Register in `src/channels/index.ts`
|
||||
6. Register in `src/daemon/index.ts`
|
||||
7. Add config schema in `src/config/schema.ts`
|
||||
|
||||
### Adding a New Model Provider
|
||||
|
||||
1. Create `src/models/<provider>.ts` implementing `ModelClient` interface
|
||||
2. Add export to `src/models/index.ts`
|
||||
3. Add case in `src/daemon/index.ts` → `createClientFromConfig()`
|
||||
4. Add to `src/config/schema.ts` → `modelConfigBaseSchema.provider` enum
|
||||
5. Write tests in `src/models/<provider>.test.ts`
|
||||
|
||||
### Adding a New CLI Command
|
||||
|
||||
```typescript
|
||||
// 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`:
|
||||
```typescript
|
||||
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 feature
|
||||
- `fix`: Bug fix
|
||||
- `refactor`: Code refactoring (no functional change)
|
||||
- `docs`: Documentation changes
|
||||
- `test`: Test additions/modifications
|
||||
- `chore`: Build process, dependencies, tooling
|
||||
- `style`: 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
|
||||
|
||||
1. Ensure your branch is up to date with `main`
|
||||
```bash
|
||||
git fetch origin
|
||||
git rebase origin/main
|
||||
```
|
||||
|
||||
2. Push your branch
|
||||
```bash
|
||||
git push -u origin feature/my-new-feature
|
||||
```
|
||||
|
||||
3. 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`](.planning/codebase/ARCHITECTURE.md)
|
||||
- **Structure**: [`.planning/codebase/STRUCTURE.md`](.planning/codebase/STRUCTURE.md)
|
||||
- **Conventions**: [`.planning/codebase/CONVENTIONS.md`](.planning/codebase/CONVENTIONS.md)
|
||||
- **Developer Guide**: [`AGENTS.md`](AGENTS.md)
|
||||
- **User Documentation**: [`README.md`](README.md)
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
See [`TROUBLESHOOTING.md`](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!
|
||||
Reference in New Issue
Block a user