# AGENTS.md ## Project Overview opencode-multi-model is a Bun/TypeScript project that provides multi-model tmux session management for AI coding assistants. Works as an OpenCode plugin, standalone CLI, and project tool. Key features: - Launch multiple AI models in isolated tmux sessions - Git worktree management for each model session - Archive tag creation for session state preservation - Supports both OpenCode and Kilo binaries - Available as CLI tool, OpenCode plugin, or project-level import ## Build, Lint, and Test Commands ```bash # Install dependencies bun install # Build for production bun run build # Run tests with coverage (HTML report in ./coverage) bun run coverage # Run a specific test by name bun test --test-name-pattern "fails if session name is empty" # TypeScript type checking bun run typecheck # Lint with Biome bun run lint # Auto-fix lint issues bun run lint:fix # Format code with Biome bun run format # Full quality check bun run typecheck && bun run lint ``` ## Code Style Guidelines ### General - Use **TypeScript** with strict mode - Use **Bun** as the runtime and package manager - Use ESM modules (`"type": "module"` in package.json) - Use `node:` prefix for Node.js built-ins ### Formatting (Biome) - **Indent**: 2 spaces (not tabs) - **Quote style**: Double quotes for JS strings - **Semicolons**: Required - Run `bun run format` to format files ### TypeScript Conventions - Use `interface` for object shapes; avoid `type` aliases unless needed - Use explicit return types on exported functions - Avoid `any` when possible - Use `noUncheckedIndexedAccess: true` and `noImplicitOverride: true` in tsconfig - All types/interfaces go in `src/types.ts` ### Naming Conventions - **Files**: kebab-case (`multi-model-open.ts`) - **Functions**: camelCase (`openMultiModel`) - **Types/Interfaces**: PascalCase (`MultiModelOptions`) - **Constants**: UPPER_SNAKE_CASE (e.g., `MAX_SUGGESTIONS`) ### Imports - Use `import type` for type-only imports - Group imports: external packages, internal modules, types - Example: ```typescript import * as fs from "node:fs"; import chalk from "chalk"; import type { MultiModelOptions } from "../types"; import { runCommand } from "./utils"; ``` ### JSDoc Comments - Use JSDoc for all exported functions - Include `@example`, `@param`, and `@returns` descriptions - Add inline comments for hard-to-understand code ### Error Handling - Return result objects (e.g., `MultiModelResult`, `CommandResult`) with `success: boolean` - Include descriptive error messages prefixed with `Error:` - Provide actionable error messages (e.g., suggest valid models on failure) - Use `chalk` for colored terminal output (red for errors, dim for secondary info, bold for primary info) ### Shell Commands - Use `Bun.$` template tag for shell commands - Always use `quiet().nothrow()` to capture output - Wrap command execution in `runCommand()` utility - Never use single-character variable names ### Testing - Use `bun:test` framework - Mock `Bun.$` using the `mock()` function from `bun:test` - Use `spyOn()` for fs/os module mocking - Group tests with `describe()` blocks - Test file naming: `*.test.ts` in `tests/` directory ### Project Structure ``` src/ ├── index.ts # Plugin entry point (default export) ├── cli.ts # CLI entry point ├── types.ts # All TypeScript interfaces/types ├── core/ │ ├── index.ts # Core exports │ ├── open.ts # Session launch logic │ ├── close.ts # Session close logic │ ├── cleanup.ts # Archive tag cleanup logic │ └── utils.ts # Shared utilities └── tools/ ├── open.ts # OpenCode tool definition ├── close.ts # CloseCode tool definition └── cleanup.ts # Cleanup tool definition tests/ ├── open.test.ts ├── close.test.ts ├── cleanup.test.ts ├── open_error.test.ts ├── close_error.test.ts └── utils.test.ts ``` ### Git Branch and Tag Naming - Session branches: `opencode//` - Archive tags: `archive/-` (created by close command) - Worktrees: `~/.local/share/opencode/multi-model///` ### Common Pitfalls - Tmux session names use raw input; git branches/paths use sanitized names - Window names must be unique; collisions get numeric suffixes (e.g., `gpt-5-2`, `gpt-5-2-2`) - Window names are truncated to 24 characters to fit tmux limits - Worktree paths are checked for existence before creation to avoid conflicts