docs(agents): regenerate all AGENTS.md files with comprehensive codebase analysis

- Regenerated root AGENTS.md with overview, structure, and complexity hotspots
- Regenerated all 7 subdirectory AGENTS.md files: hooks, tools, features, agents, cli, auth, shared
- Used 11 background explore agents for comprehensive feature and architecture analysis
- All files within size limits (root: 112 lines, subdirs: 57-68 lines)
- Includes where-to-look guide, conventions, anti-patterns, and agent model information

🤖 Generated with assistance of oh-my-opencode
This commit is contained in:
YeonGyu-Kim
2026-01-02 10:42:38 +09:00
parent bebe6607d4
commit a1fe0f8517
8 changed files with 283 additions and 569 deletions

138
AGENTS.md
View File

@@ -1,30 +1,29 @@
# PROJECT KNOWLEDGE BASE
**Generated:** 2026-01-02T00:10:00+09:00
**Commit:** b0c39e2
**Generated:** 2026-01-02T10:35:00+09:00
**Commit:** bebe660
**Branch:** dev
## OVERVIEW
OpenCode plugin implementing Claude Code/AmpCode features. Multi-model agent orchestration (GPT-5.2, Claude, Gemini, Grok), LSP tools (11), AST-Grep search, MCP integrations (context7, websearch_exa, grep_app). "oh-my-zsh" for OpenCode.
OpenCode plugin: multi-model agent orchestration (Claude Opus 4.5, GPT-5.2, Gemini 3, Grok), 11 LSP tools, AST-Grep, Claude Code compatibility layer. "oh-my-zsh" for OpenCode.
## STRUCTURE
```
oh-my-opencode/
├── src/
│ ├── agents/ # AI agents (7): Sisyphus, oracle, librarian, explore, frontend, document-writer, multimodal-looker
│ ├── agents/ # 7 AI agents - see src/agents/AGENTS.md
│ ├── hooks/ # 22 lifecycle hooks - see src/hooks/AGENTS.md
│ ├── tools/ # LSP, AST-Grep, Grep, Glob, etc. - see src/tools/AGENTS.md
│ ├── mcp/ # MCP servers: context7, websearch_exa, grep_app
│ ├── features/ # Claude Code compatibility + core features - see src/features/AGENTS.md
│ ├── config/ # Zod schema, TypeScript types
│ ├── tools/ # LSP, AST-Grep, session mgmt - see src/tools/AGENTS.md
│ ├── features/ # Claude Code compat layer - see src/features/AGENTS.md
│ ├── auth/ # Google Antigravity OAuth - see src/auth/AGENTS.md
│ ├── shared/ # Utilities: deep-merge, pattern-matcher, logger, etc. - see src/shared/AGENTS.md
│ ├── cli/ # CLI installer, doctor, run - see src/cli/AGENTS.md
── index.ts # Main plugin entry (OhMyOpenCodePlugin)
│ ├── shared/ # Cross-cutting utilities - see src/shared/AGENTS.md
│ ├── cli/ # CLI installer, doctor - see src/cli/AGENTS.md
── mcp/ # MCP configs: context7, websearch_exa, grep_app
│ ├── config/ # Zod schema, TypeScript types
│ └── index.ts # Main plugin entry (723 lines)
├── script/ # build-schema.ts, publish.ts, generate-changelog.ts
├── assets/ # JSON schema
└── dist/ # Build output (ESM + .d.ts)
```
@@ -32,71 +31,44 @@ oh-my-opencode/
| Task | Location | Notes |
|------|----------|-------|
| Add agent | `src/agents/` | Create .ts, add to builtinAgents in index.ts, update types.ts |
| Add hook | `src/hooks/` | Create dir with createXXXHook(), export from index.ts |
| Add tool | `src/tools/` | Dir with index/types/constants/tools.ts, add to builtinTools |
| Add MCP | `src/mcp/` | Create config, add to index.ts and types.ts |
| Add skill | `src/features/builtin-skills/` | Create skill dir with SKILL.md |
| LSP behavior | `src/tools/lsp/` | client.ts (connection), tools.ts (handlers) |
| AST-Grep | `src/tools/ast-grep/` | napi.ts for @ast-grep/napi binding |
| Google OAuth | `src/auth/antigravity/` | OAuth plugin for Google/Gemini models |
| Config schema | `src/config/schema.ts` | Zod schema, run `bun run build:schema` after changes |
| Add agent | `src/agents/` | Create .ts, add to builtinAgents, update types.ts |
| Add hook | `src/hooks/` | Dir with createXXXHook(), export from index.ts |
| Add tool | `src/tools/` | Dir with constants/types/tools.ts, add to builtinTools |
| Add MCP | `src/mcp/` | Create config, add to index.ts |
| Add skill | `src/features/builtin-skills/` | Dir with SKILL.md |
| Config schema | `src/config/schema.ts` | Run `bun run build:schema` after |
| Claude Code compat | `src/features/claude-code-*-loader/` | Command, skill, agent, mcp loaders |
| Background agents | `src/features/background-agent/` | manager.ts for task management |
| Skill MCP | `src/features/skill-mcp-manager/` | MCP servers embedded in skills |
| Interactive terminal | `src/tools/interactive-bash/` | tmux session management |
| CLI installer | `src/cli/install.ts` | Interactive TUI installation |
| Doctor checks | `src/cli/doctor/checks/` | Health checks for environment |
| Shared utilities | `src/shared/` | Cross-cutting utilities |
| Slash commands | `src/hooks/auto-slash-command/` | Auto-detect and execute `/command` patterns |
| Ralph Loop | `src/hooks/ralph-loop/` | Self-referential dev loop until completion |
## CONVENTIONS
- **Package manager**: Bun only (`bun run`, `bun build`, `bunx`)
- **Bun only**: `bun run`, `bun test`, `bunx` (NEVER npm/npx)
- **Types**: bun-types (not @types/node)
- **Build**: Dual output - `bun build` (ESM) + `tsc --emitDeclarationOnly`
- **Exports**: Barrel pattern - `export * from "./module"` in index.ts
- **Directory naming**: kebab-case (`ast-grep/`, `claude-code-hooks/`)
- **Tool structure**: index.ts, types.ts, constants.ts, tools.ts, utils.ts
- **Hook pattern**: `createXXXHook(input: PluginInput)` returning event handlers
- **Test style**: BDD comments `#given`, `#when`, `#then` (same as AAA)
- **Build**: `bun build` (ESM) + `tsc --emitDeclarationOnly`
- **Exports**: Barrel pattern in index.ts; explicit named exports for tools/hooks
- **Naming**: kebab-case directories, createXXXHook/createXXXTool factories
- **Testing**: BDD comments `#given`, `#when`, `#then` (same as AAA)
- **Temperature**: 0.1 for code agents, max 0.3
## ANTI-PATTERNS (THIS PROJECT)
## ANTI-PATTERNS
- **npm/yarn**: Use bun exclusively
- **@types/node**: Use bun-types
- **Bash file ops**: Never mkdir/touch/rm/cp/mv for file creation in code
- **Direct bun publish**: GitHub Actions workflow_dispatch only (OIDC provenance)
- **Local version bump**: Version managed by CI workflow
- **Year 2024**: NEVER use 2024 in code/prompts (use current year)
- **Rush completion**: Never mark tasks complete without verification
- **Over-exploration**: Stop searching when sufficient context found
- **High temperature**: Don't use >0.3 for code-related agents
- **Broad tool access**: Prefer explicit `include` over unrestricted access
- **Sequential agent calls**: Use `background_task` for parallel execution
- **Heavy PreToolUse logic**: Slows every tool call
- **Self-planning for complex tasks**: Spawn planning agent (Prometheus) instead
## UNIQUE STYLES
- **Platform**: Union type `"darwin" | "linux" | "win32" | "unsupported"`
- **Optional props**: Extensive `?` for optional interface properties
- **Flexible objects**: `Record<string, unknown>` for dynamic configs
- **Error handling**: Consistent try/catch with async/await
- **Agent tools**: `tools: { include: [...] }` or `tools: { exclude: [...] }`
- **Temperature**: Most agents use `0.1` for consistency
- **Hook naming**: `createXXXHook` function convention
- **Factory pattern**: Components created via `createXXX()` functions
| Category | Forbidden |
|----------|-----------|
| Type Safety | `as any`, `@ts-ignore`, `@ts-expect-error` |
| Package Manager | npm, yarn, npx |
| File Ops | Bash mkdir/touch/rm for code file creation |
| Publishing | Direct `bun publish`, local version bump |
| Agent Behavior | High temp (>0.3), broad tool access, sequential agent calls |
| Hooks | Heavy PreToolUse logic, blocking without reason |
| Year | 2024 in code/prompts (use current year) |
## AGENT MODELS
| Agent | Model | Purpose |
|-------|-------|---------|
| Sisyphus | anthropic/claude-opus-4-5 | Primary orchestrator |
| oracle | openai/gpt-5.2 | Strategic advisor, code review |
| librarian | anthropic/claude-sonnet-4-5 | Multi-repo analysis, docs |
| explore | opencode/grok-code | Fast codebase exploration |
| oracle | openai/gpt-5.2 | Strategy, code review |
| librarian | anthropic/claude-sonnet-4-5 | Docs, OSS research |
| explore | opencode/grok-code | Fast codebase grep |
| frontend-ui-ux-engineer | google/gemini-3-pro-preview | UI generation |
| document-writer | google/gemini-3-pro-preview | Technical docs |
| multimodal-looker | google/gemini-3-flash | PDF/image analysis |
@@ -107,8 +79,7 @@ oh-my-opencode/
bun run typecheck # Type check
bun run build # ESM + declarations + schema
bun run rebuild # Clean + Build
bun run build:schema # Schema only
bun test # Run tests
bun test # Run tests (380+)
```
## DEPLOYMENT
@@ -116,37 +87,26 @@ bun test # Run tests
**GitHub Actions workflow_dispatch only**
1. Never modify package.json version locally
2. Commit & push changes
3. Trigger `publish` workflow: `gh workflow run publish -f bump=patch`
2. Commit & push to dev
3. Trigger: `gh workflow run publish -f bump=patch|minor|major`
**Critical**: Never `bun publish` directly. Never bump version locally.
## CI PIPELINE
- **ci.yml**: Parallel test/typecheck, build verification, auto-commit schema on master, rolling `next` draft release
- **publish.yml**: Manual workflow_dispatch, version bump, changelog, OIDC npm publish
- **sisyphus-agent.yml**: Agent-in-CI for automated issue handling via `@sisyphus-dev-ai` mentions
CI auto-commits schema changes on master, maintains rolling `next` draft release on dev.
## COMPLEXITY HOTSPOTS
| File | Lines | Description |
|------|-------|-------------|
| `src/index.ts` | 723 | Main plugin orchestration, all hook/tool initialization |
| `src/cli/config-manager.ts` | 669 | JSONC parsing, environment detection, installation |
| `src/auth/antigravity/fetch.ts` | 621 | Token refresh, URL rewriting, endpoint fallbacks |
| `src/tools/lsp/client.ts` | 611 | LSP protocol, stdin/stdout buffering, JSON-RPC |
| `src/auth/antigravity/response.ts` | 598 | Response transformation, streaming |
| `src/auth/antigravity/thinking.ts` | 571 | Thinking block extraction/transformation |
| `src/hooks/anthropic-context-window-limit-recovery/executor.ts` | 554 | Session compaction, multi-stage recovery pipeline |
| `src/agents/sisyphus.ts` | 504 | Orchestrator prompt, delegation strategies |
| `src/index.ts` | 723 | Main plugin, all hook/tool init |
| `src/cli/config-manager.ts` | 669 | JSONC parsing, env detection |
| `src/auth/antigravity/fetch.ts` | 621 | Token refresh, URL rewriting |
| `src/tools/lsp/client.ts` | 611 | LSP protocol, JSON-RPC |
| `src/hooks/anthropic-context-window-limit-recovery/executor.ts` | 554 | Multi-stage recovery |
| `src/agents/sisyphus.ts` | 504 | Orchestrator prompt |
## NOTES
- **Testing**: Bun native test (`bun test`), BDD-style `#given/#when/#then`, 360+ tests
- **OpenCode**: Requires >= 1.0.150
- **Multi-lang docs**: README.md (EN), README.ko.md (KO), README.ja.md (JA), README.zh-cn.md (ZH-CN)
- **Config**: `~/.config/opencode/oh-my-opencode.json` (user) or `.opencode/oh-my-opencode.json` (project)
- **Trusted deps**: @ast-grep/cli, @ast-grep/napi, @code-yeongyu/comment-checker
- **JSONC support**: Config files support comments (`// comment`, `/* block */`) and trailing commas
- **Claude Code Compat**: Full compatibility layer for settings.json hooks, commands, skills, agents, MCPs
- **Config**: `~/.config/opencode/oh-my-opencode.json` or `.opencode/oh-my-opencode.json`
- **JSONC**: Config files support comments and trailing commas
- **Claude Code**: Full compat layer for settings.json hooks, commands, skills, agents, MCPs
- **Skill MCP**: Skills can embed MCP server configs in YAML frontmatter

View File

@@ -2,19 +2,20 @@
## OVERVIEW
AI agent definitions for multi-model orchestration. 7 specialized agents: Sisyphus (orchestrator), oracle (strategy), librarian (research), explore (grep), frontend-ui-ux-engineer, document-writer, multimodal-looker.
7 AI agents for multi-model orchestration. Sisyphus orchestrates, specialists handle domains.
## STRUCTURE
```
agents/
├── sisyphus.ts # Primary orchestrator (Claude Opus 4.5)
├── oracle.ts # Strategic advisor (GPT-5.2)
├── librarian.ts # Multi-repo research (Claude Sonnet 4.5)
├── explore.ts # Fast codebase grep (Grok Code)
├── frontend-ui-ux-engineer.ts # UI generation (Gemini 3 Pro)
├── document-writer.ts # Technical docs (Gemini 3 Flash)
├── multimodal-looker.ts # PDF/image analysis (Gemini 3 Flash)
├── sisyphus.ts # Primary orchestrator (504 lines)
├── oracle.ts # Strategic advisor
├── librarian.ts # Multi-repo research
├── explore.ts # Fast codebase grep
├── frontend-ui-ux-engineer.ts # UI generation
├── document-writer.ts # Technical docs
├── multimodal-looker.ts # PDF/image analysis
├── sisyphus-prompt-builder.ts # Sisyphus prompt construction
├── build-prompt.ts # Shared build agent prompt
├── plan-prompt.ts # Shared plan agent prompt
├── types.ts # AgentModelConfig interface
@@ -24,66 +25,40 @@ agents/
## AGENT MODELS
| Agent | Default Model | Fallback | Purpose |
|-------|---------------|----------|---------|
| Sisyphus | anthropic/claude-opus-4-5 | - | Primary orchestrator with extended thinking |
| oracle | openai/gpt-5.2 | - | Architecture, debugging, code review |
| librarian | anthropic/claude-sonnet-4-5 | google/gemini-3-flash | Docs, OSS research, GitHub examples |
| explore | opencode/grok-code | google/gemini-3-flash, anthropic/claude-haiku-4-5 | Fast contextual grep |
| frontend-ui-ux-engineer | google/gemini-3-pro-preview | - | UI/UX code generation |
| Agent | Model | Fallback | Purpose |
|-------|-------|----------|---------|
| Sisyphus | anthropic/claude-opus-4-5 | - | Orchestrator with extended thinking |
| oracle | openai/gpt-5.2 | - | Architecture, debugging, review |
| librarian | anthropic/claude-sonnet-4-5 | google/gemini-3-flash | Docs, GitHub research |
| explore | opencode/grok-code | gemini-3-flash, haiku-4-5 | Contextual grep |
| frontend-ui-ux-engineer | google/gemini-3-pro-preview | - | Beautiful UI code |
| document-writer | google/gemini-3-pro-preview | - | Technical writing |
| multimodal-looker | google/gemini-3-flash | - | PDF/image analysis |
| multimodal-looker | google/gemini-3-flash | - | Visual analysis |
## HOW TO ADD AN AGENT
## HOW TO ADD
1. Create `src/agents/my-agent.ts`:
```typescript
import type { AgentConfig } from "@opencode-ai/sdk"
export const myAgent: AgentConfig = {
model: "provider/model-name",
temperature: 0.1,
system: "Agent system prompt...",
tools: { include: ["tool1", "tool2"] }, // or exclude: [...]
system: "...",
tools: { include: ["tool1"] },
}
```
2. Add to `builtinAgents` in `src/agents/index.ts`
3. Update `types.ts` if adding new config options
2. Add to `builtinAgents` in index.ts
3. Update types.ts if new config options
## AGENT CONFIG OPTIONS
## MODEL FALLBACK
| Option | Type | Description |
|--------|------|-------------|
| model | string | Model identifier (provider/model-name) |
| temperature | number | 0.0-1.0, most use 0.1 for consistency |
| system | string | System prompt (can be multiline template literal) |
| tools | object | `{ include: [...] }` or `{ exclude: [...] }` |
| top_p | number | Optional nucleus sampling |
| maxTokens | number | Optional max output tokens |
`createBuiltinAgents()` handles fallback:
1. User config override
2. Installer settings (claude max20, gemini antigravity)
3. Default model
## MODEL FALLBACK LOGIC
## ANTI-PATTERNS
`createBuiltinAgents()` in utils.ts handles model fallback:
1. Check user config override (`agents.{name}.model`)
2. Check installer settings (claude max20, gemini antigravity)
3. Use default model
**Fallback order for explore**:
- If gemini antigravity enabled → `google/gemini-3-flash`
- If claude max20 enabled → `anthropic/claude-haiku-4-5`
- Default → `opencode/grok-code` (free)
## ANTI-PATTERNS (AGENTS)
- **High temperature**: Don't use >0.3 for code-related agents
- **Broad tool access**: Prefer explicit `include` over unrestricted access
- **Monolithic prompts**: Keep prompts focused; delegate to specialized agents
- **Missing fallbacks**: Consider free/cheap fallbacks for rate-limited models
## SHARED PROMPTS
- **build-prompt.ts**: Base prompt for build agents (OpenCode default + Sisyphus variants)
- **plan-prompt.ts**: Base prompt for plan agents (Planner-Sisyphus)
Used by `src/index.ts` when creating Builder-Sisyphus and Planner-Sisyphus variants.
- High temperature (>0.3) for code agents
- Broad tool access (prefer explicit `include`)
- Monolithic prompts (delegate to specialists)
- Missing fallbacks for rate-limited models

View File

@@ -2,56 +2,56 @@
## OVERVIEW
Google Antigravity OAuth implementation for Gemini models. Token management, fetch interception, thinking block extraction, and response transformation.
Google Antigravity OAuth for Gemini models. Token management, fetch interception, thinking block extraction.
## STRUCTURE
```
auth/
└── antigravity/
├── plugin.ts # Main plugin export, hooks registration
├── plugin.ts # Main export, hooks registration
├── oauth.ts # OAuth flow, token acquisition
├── token.ts # Token storage, refresh logic
├── fetch.ts # Fetch interceptor (622 lines) - URL rewriting, retry
├── response.ts # Response transformation, streaming
├── thinking.ts # Thinking block extraction/transformation
├── thought-signature-store.ts # Signature caching for thinking blocks
├── message-converter.ts # Message format conversion
├── request.ts # Request building, headers
├── fetch.ts # Fetch interceptor (621 lines)
├── response.ts # Response transformation (598 lines)
├── thinking.ts # Thinking block extraction (571 lines)
├── thought-signature-store.ts # Signature caching
├── message-converter.ts # Format conversion
├── request.ts # Request building
├── project.ts # Project ID management
├── tools.ts # Tool registration for OAuth
├── tools.ts # OAuth tool registration
├── constants.ts # API endpoints, model mappings
└── types.ts # TypeScript interfaces
└── types.ts
```
## KEY COMPONENTS
| File | Purpose |
|------|---------|
| `fetch.ts` | Core interceptor - rewrites URLs, manages tokens, handles retries |
| `thinking.ts` | Extracts `<antThinking>` blocks, transforms for OpenCode compatibility |
| `response.ts` | Handles streaming responses, SSE parsing |
| `oauth.ts` | Browser-based OAuth flow for Google accounts |
| `token.ts` | Token persistence, expiry checking, refresh |
| fetch.ts | URL rewriting, token injection, retries |
| thinking.ts | Extract `<antThinking>` blocks |
| response.ts | Streaming SSE parsing |
| oauth.ts | Browser-based OAuth flow |
| token.ts | Token persistence, expiry |
## HOW IT WORKS
1. **Intercept**: `fetch.ts` intercepts requests to Anthropic/Google endpoints
2. **Rewrite**: URLs rewritten to Antigravity proxy endpoints
3. **Auth**: Bearer token injected from stored OAuth credentials
4. **Response**: Streaming responses parsed, thinking blocks extracted
5. **Transform**: Response format normalized for OpenCode consumption
1. **Intercept**: fetch.ts intercepts Anthropic/Google requests
2. **Rewrite**: URLs Antigravity proxy endpoints
3. **Auth**: Bearer token from stored OAuth credentials
4. **Response**: Streaming parsed, thinking blocks extracted
5. **Transform**: Normalized for OpenCode
## ANTI-PATTERNS (AUTH)
## FEATURES
- **Direct API calls**: Always go through fetch interceptor
- **Storing tokens in code**: Use `token.ts` storage layer
- **Ignoring refresh**: Check token expiry before requests
- **Blocking on OAuth**: OAuth flow is async, never block main thread
- Multi-account (up to 10 Google accounts)
- Auto-fallback on rate limit
- Thinking blocks preserved
- Antigravity proxy for AI Studio access
## NOTES
## ANTI-PATTERNS
- **Multi-account**: Supports up to 10 Google accounts for load balancing
- **Fallback**: On rate limit, automatically switches to next available account
- **Thinking blocks**: Preserved and transformed for extended thinking features
- **Proxy**: Uses Antigravity proxy for Google AI Studio access
- Direct API calls (use fetch interceptor)
- Tokens in code (use token.ts storage)
- Ignoring refresh (check expiry first)
- Blocking on OAuth (always async)

View File

@@ -2,92 +2,67 @@
## OVERVIEW
Command-line interface for oh-my-opencode. Interactive installer, health diagnostics (doctor), and runtime commands. Entry point: `bunx oh-my-opencode`.
CLI for oh-my-opencode: interactive installer, health diagnostics (doctor), runtime launcher. Entry: `bunx oh-my-opencode`.
## STRUCTURE
```
cli/
├── index.ts # Commander.js entry point, subcommand routing
├── install.ts # Interactive TUI installer
├── config-manager.ts # Config detection, parsing, merging (669 lines)
├── index.ts # Commander.js entry, subcommand routing
├── install.ts # Interactive TUI installer (477 lines)
├── config-manager.ts # JSONC parsing, env detection (669 lines)
├── types.ts # CLI-specific types
├── doctor/ # Health check system
│ ├── index.ts # Doctor command entry
│ ├── constants.ts # Check categories, descriptions
│ ├── constants.ts # Check categories
│ ├── types.ts # Check result interfaces
│ └── checks/ # 17 individual health checks
├── get-local-version/ # Version detection utility
│ ├── index.ts
│ └── formatter.ts
│ └── checks/ # 17+ individual checks
├── get-local-version/ # Version detection
└── run/ # OpenCode session launcher
├── index.ts
└── completion.test.ts
```
## CLI COMMANDS
| Command | Purpose | Key File |
|---------|---------|----------|
| `install` | Interactive setup wizard | `install.ts` |
| `doctor` | Environment health checks | `doctor/index.ts` |
| `run` | Launch OpenCode session | `run/index.ts` |
| Command | Purpose |
|---------|---------|
| `install` | Interactive setup wizard |
| `doctor` | Environment health checks |
| `run` | Launch OpenCode session |
## DOCTOR CHECKS
17 checks in `doctor/checks/`:
17+ checks in `doctor/checks/`:
- version.ts (OpenCode >= 1.0.150)
- config.ts (plugin registered)
- bun.ts, node.ts, git.ts
- anthropic-auth.ts, openai-auth.ts, google-auth.ts
- lsp-*.ts, mcp-*.ts
| Check | Validates |
|-------|-----------|
| `version.ts` | OpenCode version >= 1.0.150 |
| `config.ts` | Plugin registered in opencode.json |
| `bun.ts` | Bun runtime available |
| `node.ts` | Node.js version compatibility |
| `git.ts` | Git installed |
| `anthropic-auth.ts` | Claude authentication |
| `openai-auth.ts` | OpenAI authentication |
| `google-auth.ts` | Google/Gemini authentication |
| `lsp-*.ts` | Language server availability |
| `mcp-*.ts` | MCP server connectivity |
## CONFIG-MANAGER (669 lines)
## INSTALLATION FLOW
- JSONC support (comments, trailing commas)
- Multi-source: User (~/.config/opencode/) + Project (.opencode/)
- Zod validation
- Legacy format migration
- Error aggregation for doctor
1. **Detection**: Find existing `opencode.json` / `opencode.jsonc`
2. **TUI Prompts**: Claude subscription? ChatGPT? Gemini?
3. **Config Generation**: Build `oh-my-opencode.json` based on answers
4. **Plugin Registration**: Add to `plugin` array in opencode.json
5. **Auth Guidance**: Instructions for `opencode auth login`
## CONFIG-MANAGER
The largest file (669 lines) handles:
- **JSONC support**: Parses comments and trailing commas
- **Multi-source detection**: User (~/.config/opencode/) + Project (.opencode/)
- **Schema validation**: Zod-based config validation
- **Migration**: Handles legacy config formats
- **Error collection**: Aggregates parsing errors for doctor
## HOW TO ADD A DOCTOR CHECK
## HOW TO ADD CHECK
1. Create `src/cli/doctor/checks/my-check.ts`:
```typescript
import type { DoctorCheck } from "../types"
export const myCheck: DoctorCheck = {
name: "my-check",
category: "environment",
check: async () => {
// Return { status: "pass" | "warn" | "fail", message: string }
return { status: "pass" | "warn" | "fail", message: "..." }
}
}
```
2. Add to `src/cli/doctor/checks/index.ts`
3. Update `constants.ts` if new category
## ANTI-PATTERNS (CLI)
## ANTI-PATTERNS
- **Blocking prompts in non-TTY**: Check `process.stdout.isTTY` before TUI
- **Hardcoded paths**: Use shared utilities for config paths
- **Ignoring JSONC**: User configs may have comments
- **Silent failures**: Doctor checks must return clear status/message
- Blocking prompts in non-TTY (check `process.stdout.isTTY`)
- Hardcoded paths (use shared utilities)
- JSON.parse for user files (use parseJsonc)
- Silent failures in doctor checks

View File

@@ -2,207 +2,65 @@
## OVERVIEW
Claude Code compatibility layer and core feature modules. Enables Claude Code configs/commands/skills/MCPs/hooks to work seamlessly in OpenCode.
Claude Code compatibility layer + core feature modules. Commands, skills, agents, MCPs, hooks from Claude Code work seamlessly.
## STRUCTURE
```
features/
├── background-agent/ # Background task management
│ ├── manager.ts # Task lifecycle, notifications
│ ├── manager.test.ts
│ └── types.ts
├── builtin-commands/ # Built-in slash command definitions
├── builtin-skills/ # Built-in skills (playwright, etc.)
│ └── */SKILL.md # Each skill in own directory
├── claude-code-agent-loader/ # Load agents from ~/.claude/agents/*.md
├── claude-code-command-loader/ # Load commands from ~/.claude/commands/*.md
├── claude-code-mcp-loader/ # Load MCPs from .mcp.json
├── background-agent/ # Task lifecycle, notifications (460 lines)
├── builtin-commands/ # Built-in slash commands
├── builtin-skills/ # Built-in skills (playwright)
├── claude-code-agent-loader/ # ~/.claude/agents/*.md
├── claude-code-command-loader/ # ~/.claude/commands/*.md
├── claude-code-mcp-loader/ # .mcp.json files
│ └── env-expander.ts # ${VAR} expansion
├── claude-code-plugin-loader/ # Load external plugins from installed_plugins.json
├── claude-code-plugin-loader/ # installed_plugins.json (484 lines)
├── claude-code-session-state/ # Session state persistence
├── opencode-skill-loader/ # Load skills from OpenCode and Claude paths
├── skill-mcp-manager/ # MCP servers embedded in skills
│ ├── manager.ts # Lazy-loading MCP client lifecycle
│ └── types.ts
├── opencode-skill-loader/ # Skills from OpenCode + Claude paths
├── skill-mcp-manager/ # MCP servers in skill YAML
└── hook-message-injector/ # Inject messages into conversation
```
## LOADER PRIORITY
Each loader reads from multiple directories (highest priority first):
| Loader | Priority Order |
|--------|---------------|
| Loader | Priority (highest first) |
|--------|--------------------------|
| Commands | `.opencode/command/` > `~/.config/opencode/command/` > `.claude/commands/` > `~/.claude/commands/` |
| Skills | `.opencode/skill/` > `~/.config/opencode/skill/` > `.claude/skills/` > `~/.claude/skills/` |
| Agents | `.claude/agents/` > `~/.claude/agents/` |
| MCPs | `.claude/.mcp.json` > `.mcp.json` > `~/.claude/.mcp.json` |
## HOW TO ADD A LOADER
1. Create directory: `src/features/claude-code-my-loader/`
2. Create files:
- `loader.ts`: Main loader logic with `load()` function
- `types.ts`: TypeScript interfaces
- `index.ts`: Barrel export
3. Pattern: Read from multiple dirs, merge with priority, return normalized config
## BACKGROUND AGENT SPECIFICS
- **Task lifecycle**: pending → running → completed/failed
- **Notifications**: OS notification on task complete (configurable)
- **Result retrieval**: `background_output` tool with task_id
- **Cancellation**: `background_cancel` with task_id or all=true
## CONFIG TOGGLES
Disable features in `oh-my-opencode.json`:
```json
{
"claude_code": {
"mcp": false, // Skip .mcp.json loading
"commands": false, // Skip commands/*.md loading
"skills": false, // Skip skills/*/SKILL.md loading
"agents": false, // Skip agents/*.md loading
"mcp": false, // Skip .mcp.json
"commands": false, // Skip commands/*.md
"skills": false, // Skip skills/*/SKILL.md
"agents": false, // Skip agents/*.md
"hooks": false // Skip settings.json hooks
}
}
```
## HOOK MESSAGE INJECTOR
## BACKGROUND AGENT
- **Purpose**: Inject system messages into conversation at specific points
- **Timing**: PreToolUse, PostToolUse, UserPromptSubmit, Stop
- **Format**: Returns `{ messages: [{ role: "user", content: "..." }] }`
- Lifecycle: pending → running → completed/failed
- OS notification on complete
- `background_output` to retrieve results
- `background_cancel` with task_id or all=true
## MCP LOADER (claude-code-mcp-loader)
## SKILL MCP
Loads MCP server configs from `.mcp.json` files. Full Claude Code compatibility.
- MCP servers embedded in skill YAML frontmatter
- Lazy client loading, session-scoped cleanup
- `skill_mcp` tool exposes capabilities
### File Locations (Priority Order)
## ANTI-PATTERNS
| Path | Scope | Description |
|------|-------|-------------|
| `~/.claude/.mcp.json` | user | User-global MCP servers |
| `./.mcp.json` | project | Project-specific MCP servers |
| `./.claude/.mcp.json` | local | Local overrides (git-ignored) |
### .mcp.json Format
```json
{
"mcpServers": {
"server-name": {
"type": "stdio|http|sse",
"command": "npx",
"args": ["-y", "@anthropics/mcp-server-example"],
"env": {
"API_KEY": "${MY_API_KEY}"
},
"disabled": false
}
}
}
```
### Server Types
| Type | Required Fields | Description |
|------|-----------------|-------------|
| `stdio` (default) | `command`, `args?`, `env?` | Local subprocess MCP |
| `http` | `url`, `headers?` | HTTP-based remote MCP |
| `sse` | `url`, `headers?` | SSE-based remote MCP |
### Environment Variable Expansion
Supports `${VAR}` syntax in all string fields:
```json
{
"mcpServers": {
"my-server": {
"command": "node",
"args": ["${HOME}/mcp-server/index.js"],
"env": {
"API_KEY": "${MY_API_KEY}",
"DEBUG": "${DEBUG:-false}"
}
}
}
}
```
### Examples
**stdio (Local subprocess)**:
```json
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@anthropics/mcp-server-filesystem", "/path/to/dir"]
}
}
}
```
**http (Remote)**:
```json
{
"mcpServers": {
"remote-api": {
"type": "http",
"url": "https://mcp.example.com/api",
"headers": {
"Authorization": "Bearer ${API_TOKEN}"
}
}
}
}
```
**Disable a server**:
```json
{
"mcpServers": {
"expensive-server": {
"command": "...",
"disabled": true
}
}
}
```
### Transformation
Claude Code format → OpenCode format:
| Claude Code | OpenCode |
|-------------|----------|
| `type: "stdio"` | `type: "local"` |
| `type: "http\|sse"` | `type: "remote"` |
| `command` + `args` | `command: [cmd, ...args]` |
| `env` | `environment` |
| `headers` | `headers` |
## SKILL MCP MANAGER
- **Purpose**: Manage MCP servers embedded in skill YAML frontmatter
- **Lifecycle**: Lazy client loading, session-scoped cleanup
- **Config**: `mcp` field in skill's YAML frontmatter defines server config
- **Tool**: `skill_mcp` exposes MCP capabilities (tools, resources, prompts)
## BUILTIN SKILLS
- **Location**: `src/features/builtin-skills/*/SKILL.md`
- **Available**: `playwright` (browser automation)
- **Disable**: `disabled_skills: ["playwright"]` in config
## ANTI-PATTERNS (FEATURES)
- **Blocking on load**: Loaders run at startup, keep them fast
- **No error handling**: Always try/catch, log failures, return empty on error
- **Ignoring priority**: Higher priority dirs must override lower
- **Modifying user files**: Loaders read-only, never write to ~/.claude/
- Blocking on load (loaders run at startup)
- No error handling (always try/catch)
- Ignoring priority order
- Writing to ~/.claude/ (read-only)

View File

@@ -2,85 +2,65 @@
## OVERVIEW
Lifecycle hooks that intercept/modify agent behavior. Inject context, enforce rules, recover from errors, notify on events.
22 lifecycle hooks intercepting/modifying agent behavior. Context injection, error recovery, output control, notifications.
## STRUCTURE
```
hooks/
├── agent-usage-reminder/ # Remind to use specialized agents
├── anthropic-context-window-limit-recovery/ # Auto-compact Claude at token limit
├── auto-slash-command/ # Auto-detect and execute /command patterns
├── auto-update-checker/ # Version update notifications
├── background-notification/ # OS notify on background task complete
├── claude-code-hooks/ # Claude Code settings.json integration
├── anthropic-context-window-limit-recovery/ # Auto-compact at token limit (554 lines)
├── auto-slash-command/ # Detect and execute /command patterns
├── auto-update-checker/ # Version notifications, startup toast
├── background-notification/ # OS notify on task complete
├── claude-code-hooks/ # settings.json PreToolUse/PostToolUse/etc
├── comment-checker/ # Prevent excessive AI comments
── filters/ # Filtering rules (docstring, directive, bdd, etc.)
│ └── output/ # Output formatting
├── compaction-context-injector/ # Inject context during compaction
├── directory-agents-injector/ # Auto-inject AGENTS.md files
├── directory-readme-injector/ # Auto-inject README.md files
── filters/ # docstring, directive, bdd, etc
├── compaction-context-injector/ # Preserve context during compaction
├── directory-agents-injector/ # Auto-inject AGENTS.md
├── directory-readme-injector/ # Auto-inject README.md
├── empty-message-sanitizer/ # Sanitize empty messages
├── interactive-bash-session/ # Tmux session management
├── keyword-detector/ # Detect ultrawork/search keywords
├── non-interactive-env/ # CI/headless environment handling
├── preemptive-compaction/ # Pre-emptive session compaction
├── ralph-loop/ # Self-referential dev loop until completion
├── keyword-detector/ # ultrawork/search keyword activation
├── non-interactive-env/ # CI/headless handling
├── preemptive-compaction/ # Pre-emptive at 85% usage
├── ralph-loop/ # Self-referential dev loop
├── rules-injector/ # Conditional rules from .claude/rules/
├── session-recovery/ # Recover from session errors
├── session-recovery/ # Recover from errors (430 lines)
├── think-mode/ # Auto-detect thinking triggers
├── thinking-block-validator/ # Validate thinking blocks in messages
├── context-window-monitor.ts # Monitor context usage (standalone)
├── empty-task-response-detector.ts
├── session-notification.ts # OS notify on idle (standalone)
── todo-continuation-enforcer.ts # Force TODO completion (standalone)
└── tool-output-truncator.ts # Truncate verbose outputs (standalone)
├── agent-usage-reminder/ # Remind to use specialists
├── context-window-monitor.ts # Monitor usage (standalone)
├── session-notification.ts # OS notify on idle
├── todo-continuation-enforcer.ts # Force TODO completion
── tool-output-truncator.ts # Truncate verbose outputs
```
## HOOK CATEGORIES
| Category | Hooks | Purpose |
|----------|-------|---------|
| Context Injection | directory-agents-injector, directory-readme-injector, rules-injector, compaction-context-injector | Auto-inject relevant context |
| Session Management | session-recovery, anthropic-context-window-limit-recovery, preemptive-compaction, empty-message-sanitizer | Handle session lifecycle |
| Output Control | comment-checker, tool-output-truncator | Control agent output quality |
| Notifications | session-notification, background-notification, auto-update-checker | OS/user notifications |
| Behavior Enforcement | todo-continuation-enforcer, keyword-detector, think-mode, agent-usage-reminder | Enforce agent behavior |
| Environment | non-interactive-env, interactive-bash-session, context-window-monitor | Adapt to runtime environment |
| Compatibility | claude-code-hooks | Claude Code settings.json support |
## HOW TO ADD A HOOK
1. Create directory: `src/hooks/my-hook/`
2. Create files:
- `index.ts`: Export `createMyHook(input: PluginInput)`
- `constants.ts`: Hook name constant
- `types.ts`: TypeScript interfaces (optional)
- `storage.ts`: Persistent state (optional)
3. Return event handlers: `{ PreToolUse?, PostToolUse?, UserPromptSubmit?, Stop?, onSummarize? }`
4. Export from `src/hooks/index.ts`
5. Register in main plugin
## HOOK EVENTS
| Event | Timing | Can Block | Use Case |
|-------|--------|-----------|----------|
| PreToolUse | Before tool exec | Yes | Validate, modify input |
| PostToolUse | After tool exec | No | Add context, warnings |
| UserPromptSubmit | On user prompt | Yes | Inject messages, block |
| PreToolUse | Before tool | Yes | Validate, modify input |
| PostToolUse | After tool | No | Add context, warnings |
| UserPromptSubmit | On prompt | Yes | Inject messages, block |
| Stop | Session idle | No | Inject follow-ups |
| onSummarize | During compaction | No | Preserve critical context |
| onSummarize | Compaction | No | Preserve context |
## COMMON PATTERNS
## HOW TO ADD
- **Storage**: Use `storage.ts` with JSON file for persistent state across sessions
- **Once-per-session**: Track injected paths in Set to avoid duplicate injection
- **Message injection**: Return `{ messages: [...] }` from event handlers
- **Blocking**: Return `{ blocked: true, message: "reason" }` from PreToolUse
1. Create `src/hooks/my-hook/`
2. Files: `index.ts` (createMyHook), `constants.ts`, `types.ts` (optional)
3. Return: `{ PreToolUse?, PostToolUse?, UserPromptSubmit?, Stop?, onSummarize? }`
4. Export from `src/hooks/index.ts`
## ANTI-PATTERNS (HOOKS)
## PATTERNS
- **Heavy computation** in PreToolUse: Slows every tool call
- **Blocking without clear reason**: Always provide actionable message
- **Duplicate injection**: Track what's already injected per session
- **Ignoring errors**: Always try/catch, log failures, don't crash session
- **Storage**: JSON file for persistent state across sessions
- **Once-per-session**: Track injected paths in Set
- **Message injection**: Return `{ messages: [...] }`
- **Blocking**: Return `{ blocked: true, message: "..." }` from PreToolUse
## ANTI-PATTERNS
- Heavy computation in PreToolUse (slows every tool call)
- Blocking without actionable message
- Duplicate injection (track what's injected)
- Missing try/catch (don't crash session)

View File

@@ -2,81 +2,62 @@
## OVERVIEW
Cross-cutting utility functions used across agents, hooks, tools, and features. Path resolution, config management, text processing, and Claude Code compatibility helpers.
Cross-cutting utilities: path resolution, config management, text processing, Claude Code compatibility helpers.
## STRUCTURE
```
shared/
├── index.ts # Barrel export (import { x } from "../shared")
├── claude-config-dir.ts # Resolve ~/.claude directory
├── command-executor.ts # Shell command execution with variable expansion
├── config-errors.ts # Global config error tracking
├── config-path.ts # User/project config path resolution
├── data-path.ts # XDG data directory resolution
├── deep-merge.ts # Type-safe recursive object merging
├── dynamic-truncator.ts # Token-aware output truncation
├── file-reference-resolver.ts # @filename syntax resolution
├── file-utils.ts # Symlink resolution, markdown detection
├── index.ts # Barrel export
├── claude-config-dir.ts # ~/.claude resolution
├── command-executor.ts # Shell exec with variable expansion
├── config-errors.ts # Global error tracking
├── config-path.ts # User/project config paths
├── data-path.ts # XDG data directory
├── deep-merge.ts # Type-safe recursive merge
├── dynamic-truncator.ts # Token-aware truncation
├── file-reference-resolver.ts # @filename syntax
├── file-utils.ts # Symlink, markdown detection
├── frontmatter.ts # YAML frontmatter parsing
├── hook-disabled.ts # Check if hook is disabled in config
├── jsonc-parser.ts # JSON with Comments parsing
├── logger.ts # File-based logging to OS temp
├── migration.ts # Legacy name compatibility (omo -> Sisyphus)
├── hook-disabled.ts # Check if hook disabled
├── jsonc-parser.ts # JSON with Comments
├── logger.ts # File-based logging
├── migration.ts # Legacy name compat (omo Sisyphus)
├── model-sanitizer.ts # Normalize model names
├── pattern-matcher.ts # Tool name matching with wildcards
├── snake-case.ts # Case conversion for objects
└── tool-name.ts # Normalize tool names to PascalCase
├── pattern-matcher.ts # Tool name matching
├── snake-case.ts # Case conversion
└── tool-name.ts # PascalCase normalization
```
## UTILITY CATEGORIES
## WHEN TO USE
| Category | Utilities | Used By |
|----------|-----------|---------|
| Path Resolution | `getClaudeConfigDir`, `getUserConfigPath`, `getProjectConfigPath`, `getDataDir` | Features, Hooks |
| Config Management | `deepMerge`, `parseJsonc`, `isHookDisabled`, `configErrors` | index.ts, CLI |
| Text Processing | `resolveCommandsInText`, `resolveFileReferencesInText`, `parseFrontmatter` | Commands, Rules |
| Output Control | `dynamicTruncate` | Tools (Grep, LSP) |
| Normalization | `transformToolName`, `objectToSnakeCase`, `sanitizeModelName` | Hooks, Agents |
| Compatibility | `migration.ts` | Config loading |
## WHEN TO USE WHAT
| Task | Utility | Notes |
|------|---------|-------|
| Find Claude Code configs | `getClaudeConfigDir()` | Never hardcode `~/.claude` |
| Merge settings (default → user → project) | `deepMerge(base, override)` | Arrays replaced, objects merged |
| Parse user config files | `parseJsonc()` | Supports comments and trailing commas |
| Check if hook should run | `isHookDisabled(name, disabledHooks)` | Respects `disabled_hooks` config |
| Truncate large tool output | `dynamicTruncate(text, budget, reserved)` | Token-aware, prevents overflow |
| Resolve `@file` references | `resolveFileReferencesInText()` | maxDepth=3 prevents infinite loops |
| Execute shell commands | `resolveCommandsInText()` | Supports `!`\`command\`\` syntax |
| Handle legacy agent names | `migrateLegacyAgentNames()` | `omo``Sisyphus` |
| Task | Utility |
|------|---------|
| Find ~/.claude | `getClaudeConfigDir()` |
| Merge configs | `deepMerge(base, override)` |
| Parse user files | `parseJsonc()` |
| Check hook enabled | `isHookDisabled(name, list)` |
| Truncate output | `dynamicTruncate(text, budget)` |
| Resolve @file | `resolveFileReferencesInText()` |
| Execute shell | `resolveCommandsInText()` |
| Legacy names | `migrateLegacyAgentNames()` |
## CRITICAL PATTERNS
### Dynamic Truncation
```typescript
import { dynamicTruncate } from "../shared"
// Keep 50% headroom, max 50k tokens
// Dynamic truncation
const output = dynamicTruncate(result, remainingTokens, 0.5)
```
### Deep Merge Priority
```typescript
const final = deepMerge(defaults, userConfig)
final = deepMerge(final, projectConfig) // Project wins
```
// Deep merge priority
const final = deepMerge(deepMerge(defaults, userConfig), projectConfig)
### Safe JSONC Parsing
```typescript
// Safe JSONC
const { config, error } = parseJsoncSafe(content)
if (error) return fallback
```
## ANTI-PATTERNS (SHARED)
## ANTI-PATTERNS
- **Hardcoding paths**: Use `getClaudeConfigDir()`, `getUserConfigPath()`
- **Manual JSON.parse**: Use `parseJsonc()` for user files (comments allowed)
- **Ignoring truncation**: Large outputs MUST use `dynamicTruncate`
- **Direct string concat for configs**: Use `deepMerge` for proper priority
- Hardcoding paths (use getClaudeConfigDir, getUserConfigPath)
- JSON.parse for user files (use parseJsonc)
- Ignoring truncation (large outputs MUST use dynamicTruncate)
- Direct string concat for configs (use deepMerge)

View File

@@ -2,33 +2,26 @@
## OVERVIEW
Custom tools extending agent capabilities: LSP integration (11 tools), AST-aware code search/replace, file operations with timeouts, background task management.
Custom tools: 11 LSP tools, AST-aware search/replace, file ops with timeouts, background task management, session navigation.
## STRUCTURE
```
tools/
├── ast-grep/ # AST-aware code search/replace (25 languages)
│ ├── cli.ts # @ast-grep/cli subprocess
── napi.ts # @ast-grep/napi native binding (preferred)
│ ├── constants.ts, types.ts, tools.ts, utils.ts
│ ├── napi.ts # @ast-grep/napi binding (preferred)
── cli.ts # @ast-grep/cli fallback
├── background-task/ # Async agent task management
├── call-omo-agent/ # Spawn explore/librarian agents
├── glob/ # File pattern matching (timeout-safe)
├── grep/ # Content search (timeout-safe)
├── glob/ # File pattern matching (60s timeout)
├── grep/ # Content search (60s timeout)
├── interactive-bash/ # Tmux session management
├── look-at/ # Multimodal analysis (PDF, images)
├── lsp/ # 11 LSP tools
├── lsp/ # 11 LSP tools (611 lines client.ts)
│ ├── client.ts # LSP connection lifecycle
│ ├── config.ts # Server configurations
│ ├── tools.ts # Tool implementations
│ └── types.ts
├── session-manager/ # OpenCode session file management
│ ├── constants.ts # Storage paths, descriptions
│ ├── types.ts # Session data interfaces
│ ├── storage.ts # File I/O operations
│ ├── utils.ts # Formatting, filtering
│ └── tools.ts # Tool implementations
├── session-manager/ # OpenCode session file ops
├── skill/ # Skill loading and execution
├── skill-mcp/ # Skill-embedded MCP invocation
├── slashcommand/ # Slash command execution
@@ -37,47 +30,39 @@ tools/
## TOOL CATEGORIES
| Category | Tools | Purpose |
|----------|-------|---------|
| LSP | lsp_hover, lsp_goto_definition, lsp_find_references, lsp_document_symbols, lsp_workspace_symbols, lsp_diagnostics, lsp_servers, lsp_prepare_rename, lsp_rename, lsp_code_actions, lsp_code_action_resolve | IDE-like code intelligence |
| AST | ast_grep_search, ast_grep_replace | Pattern-based code search/replace |
| File Search | grep, glob | Content and file pattern matching |
| Session | session_list, session_read, session_search, session_info | OpenCode session file management |
| Background | background_task, background_output, background_cancel | Async agent orchestration |
| Multimodal | look_at | PDF/image analysis via Gemini |
| Terminal | interactive_bash | Tmux session control |
| Commands | slashcommand | Execute slash commands |
| Skills | skill, skill_mcp | Load skills, invoke skill-embedded MCPs |
| Agents | call_omo_agent | Spawn explore/librarian |
| Category | Tools |
|----------|-------|
| LSP | lsp_hover, lsp_goto_definition, lsp_find_references, lsp_document_symbols, lsp_workspace_symbols, lsp_diagnostics, lsp_servers, lsp_prepare_rename, lsp_rename, lsp_code_actions, lsp_code_action_resolve |
| AST | ast_grep_search, ast_grep_replace |
| File Search | grep, glob |
| Session | session_list, session_read, session_search, session_info |
| Background | background_task, background_output, background_cancel |
| Multimodal | look_at |
| Terminal | interactive_bash |
| Skills | skill, skill_mcp |
| Agents | call_omo_agent |
## HOW TO ADD A TOOL
## HOW TO ADD
1. Create directory: `src/tools/my-tool/`
2. Create files:
- `constants.ts`: `TOOL_NAME`, `TOOL_DESCRIPTION`
- `types.ts`: Parameter/result interfaces
- `tools.ts`: Tool implementation (returns OpenCode tool object)
- `index.ts`: Barrel export
- `utils.ts`: Helpers (optional)
1. Create `src/tools/my-tool/`
2. Files: `constants.ts`, `types.ts`, `tools.ts`, `index.ts`
3. Add to `builtinTools` in `src/tools/index.ts`
## LSP SPECIFICS
- **Client lifecycle**: Lazy init on first use, auto-shutdown on idle
- **Config priority**: opencode.json > oh-my-opencode.json > defaults
- **Supported servers**: typescript-language-server, pylsp, gopls, rust-analyzer, etc.
- **Custom servers**: Add via `lsp` config in oh-my-opencode.json
- Lazy init on first use, auto-shutdown on idle
- Config priority: opencode.json > oh-my-opencode.json > defaults
- Servers: typescript-language-server, pylsp, gopls, rust-analyzer
## AST-GREP SPECIFICS
- **Meta-variables**: `$VAR` (single node), `$$$` (multiple nodes)
- **Languages**: 25 supported (typescript, tsx, python, rust, go, etc.)
- **Binding**: Prefers @ast-grep/napi (native), falls back to @ast-grep/cli
- **Pattern must be valid AST**: `export async function $NAME($$$) { $$$ }` not fragments
- Meta-variables: `$VAR` (single), `$$$` (multiple)
- Pattern must be valid AST node, not fragment
- Prefers napi binding for performance
## ANTI-PATTERNS (TOOLS)
## ANTI-PATTERNS
- **No timeout**: Always use timeout for file operations (default 60s)
- **Blocking main thread**: Use async/await, never sync file ops
- **Ignoring LSP errors**: Gracefully handle server not found/crashed
- **Raw subprocess for ast-grep**: Prefer napi binding for performance
- No timeout on file ops (always use, default 60s)
- Sync file operations (use async/await)
- Ignoring LSP errors (graceful handling required)
- Raw subprocess for ast-grep (prefer napi)