- When you are about to use the wrong tool — STOP. Use the correct tool listed below. Do NOT proceed with the wrong tool even if it seems faster.
- If you already used the wrong tool — STOP and redo the step with the correct tool. Do NOT continue with the result from the wrong tool.
- NEVER use
explorefor intent-based or behavioral queries (e.g. "how does X work?", "find the orchestration flow for Y").explorecan only use grep/glob/ast_grep. For intent/behavior queries, ALWAYS usecodealive_codebase_searchdirectly ortask(category="quick"/"deep").
ALWAYS use LSP for navigating code. NEVER use grep for finding definitions, references, or implementations — LSP is semantically precise, grep matches strings blindly and gives false positives.
Default action when unsure: ALWAYS use LSP.
Tool priority order: lsp(operation=...) → grep (ONLY as a fallback when LSP returns no results).
IMPORTANT: OMO's built-in LSP tools (lsp_goto_definition, lsp_find_references, lsp_symbols, lsp_diagnostics, lsp_prepare_rename, lsp_rename) are DISABLED via disabled_tools in opencode.json because they use a separate gopls instance that conflicts with the OpenCode LSP. ALWAYS use the OpenCode lsp(operation=...) tool instead. NEVER use lsp_* prefixed tools — they will not be available.
- When you want to find where a function/type/variable is defined and you have a call site — NEVER
grepfor it. ALWAYS uselspwithoperation="goToDefinition". It jumps to the exact definition, even across packages. - When you want to find where a symbol is defined but you don't have a call site — NEVER
grepfor it. ALWAYS uselspwithoperation="workspaceSymbol". Fall back togrepONLY if LSP returns no results. - When you want to find all usages of a symbol — NEVER
grepfor the symbol name. ALWAYS uselspwithoperation="findReferences". Grep will match comments, strings, and unrelated identifiers with the same name. - When you want to understand what's in a file — NEVER scroll through it or
grepforfunc. ALWAYS uselspwithoperation="documentSymbol". It returns the complete structure: functions, types, constants, variables. - When you want to check a symbol's type or read its documentation — NEVER guess from context. ALWAYS use
lspwithoperation="hover". It returns the exact type signature and godoc. - When you want to find which types implement an interface — NEVER
grepfor type names. ALWAYS uselspwithoperation="goToImplementation". Grep cannot reliably find implicit Go interface implementations. - When you want to trace what calls a function — NEVER
grepfor the function name. ALWAYS uselsp→prepareCallHierarchy→incomingCalls. Grep will miss method calls, aliased imports, and interface dispatch. - When you want to trace what a function calls — NEVER read through the function body manually. ALWAYS use
lsp→prepareCallHierarchy→outgoingCalls. - When you want to rename a symbol — NEVER find-and-replace. ALWAYS use
ast_grep_replacefor safe AST-aware renaming. - When you want to check for errors before building — NEVER skip this step. ALWAYS run
task build:dev:allandtask lint.
ALWAYS use CodeAlive MCP (codealive_codebase_search, codealive_codebase_consultant) for semantic/intent-based code search. NEVER substitute with grep when the query is about intent or behavior — CodeAlive understands code semantics, grep only matches character sequences.
Default action when unsure: ALWAYS use codealive_codebase_search.
Tool priority order: codealive_codebase_search / codealive_codebase_consultant → ast_grep_search → grep / glob.
- ALWAYS call
codealive_get_data_sourcesbefore any CodeAlive tool. Without this, CodeAlive calls will fail. - When you want to find code by intent or behavior (e.g. "how does release planning work?", "where is the DAG built?") — NEVER
grepfor keywords. ALWAYS usecodealive_codebase_search. Grep will miss relevant code that uses different terminology, and drown you in irrelevant string matches. - When you want architectural advice or explanations (e.g. "why is the DAG built this way?", "how do these packages relate?") — NEVER guess from reading a few files. ALWAYS use
codealive_codebase_consultant. It has indexed the entire codebase and understands cross-cutting concerns. - When you want to find structural code patterns (e.g. all functions with a specific signature, all
fmt.Errorf(... %w ...)calls, all interface implementations) — NEVER usegrepwith regex hacks. ALWAYS useast_grep_search. It matches on the AST, not on text, so it won't be fooled by comments, strings, or formatting differences. - ONLY fall back to
grep/globfor simple literal matching (specific strings, config keys, error messages, annotation names). This is the ONLY valid use ofgrepin this codebase. - When delegating code search to subagents — NEVER use
explorefor CodeAlive or LSP searches. Theexploreagent can only use grep/glob/ast_grep (OMO upstream limitation). ALWAYS usetask(category="quick")ortask(category="deep")for semantic search. Thelibrarianagent has full CodeAlive/Context7 access and works correctly. - NEVER use
explorefor intent-based or behavioral queries (e.g. "how does X work?", "find the orchestration flow for Y"). These require CodeAlive, whichexplorecannot access. ALWAYS usetask(category="quick")ortask(category="deep")instead, or do thecodealive_codebase_searchyourself. ReserveexploreONLY for literal pattern matching (specific identifiers, strings, config keys).
Background subagents (explore, librarian) have known reliability issues. Tasks can silently vanish (task ID becomes unfetchable), stall (prompt received but no tool calls made), or crash without producing an error status. NEVER depend on a single background agent for critical information.
- ALWAYS fire at least 2
exploreagents when information is critical. Use different search strategies (e.g. one with grep, one with ast_grep + glob). If one fails, the other covers. - ALWAYS have a direct-tool fallback ready. After firing background agents, immediately start your own parallel search with
codealive_codebase_search,LSP, orgrep. Do NOT wait idle for agent results. - ALWAYS treat
background_outputreturning "Task not found" as a silent failure, not a timing issue. The task is gone — move on to your fallback. - When an agent's task ID vanishes or shows
status: runningwith only the initial prompt message after 30+ seconds, assume it stalled. Do NOT keep polling — use your own tools instead. - For this codebase, PREFER direct tools (
codealive_codebase_search+LSP+read) overexploreagents for targeted queries. Direct tools are 100% reliable and 3-10x faster. Reserveexploreagents ONLY for broad multi-angle discovery where 3+ different search patterns are needed simultaneously. - When delegating to
librarian, ALWAYS use maximally directive prompts that name the exact tools to call and the exact queries to run. Open-ended prompts cause the librarian to spend 40-50s "thinking" before making any tool calls. BAD: "Find the best approach for X." GOOD: "Usecontext7_resolve-library-idfor 'helm', thencontext7_query-docsfor 'hook lifecycle annotations helm.sh/hook'. Return the raw documentation."
Subagents are stateless — they do NOT read OPENCODE.md or AGENTS.md. They only know what you pass in the prompt= parameter. When delegating tasks that involve code search, navigation, or external lookups, ALWAYS include the relevant tool rules from this file in the delegation prompt. Without this, subagents will use wrong tools (e.g. grep instead of CodeAlive, guessing APIs instead of using Context7).
- When delegating code search — ALWAYS include: "Use
codealive_codebase_searchfor intent/behavioral queries. Callcodealive_get_data_sourcesfirst. Use LSPdocumentSymbolto understand file structure. NEVER use grep for finding definitions or references." - When delegating external knowledge lookup — ALWAYS include: "Use
context7_resolve-library-id+context7_query-docsfor library docs. Usegrep_app_searchGitHubfor real-world usage patterns. Usewebsearch_web_search_exafor current information. NEVER guess APIs from training data." - When delegating to
librarian— ALWAYS use directive prompts: "Search NOW for X and return results", not "Find the best approach for X". Librarian may get stuck planning instead of executing if the prompt is too open-ended.
NEVER guess at APIs — ALWAYS look them up. Using wrong API signatures wastes time on compilation errors and subtle bugs.
Default action when unsure: ALWAYS use context7_resolve-library-id + context7_query-docs.
Tool priority order: lsp with operation="goToDefinition" → Context7 → grep_app_searchGitHub → websearch_web_search_exa. If you have a URL, ALWAYS use webfetch.
- When you want to check a Go type signature or read godoc for a dependency — NEVER guess from memory or training data. ALWAYS use
lspwithoperation="goToDefinition"to navigate to the actual source. Training data may be outdated or wrong. - When you want library documentation, guides, or API examples — NEVER rely on training data. ALWAYS use
context7_resolve-library-id+context7_query-docs. Context7 has up-to-date docs; your training data may be stale. - When you want real-world usage patterns (how do other projects use this library?) — NEVER invent patterns. ALWAYS use
grep_app_searchGitHub. It searches real code from real repositories. - When you need current information, recent changes, or anything that might have changed after your training cutoff — NEVER answer from memory. ALWAYS use
websearch_web_search_exa. - When you have a specific URL to read (docs page, GitHub issue, PR) — NEVER summarize from memory. ALWAYS use
webfetchto retrieve the actual content.
Default action when unsure: Check the trdl dev environment.
- trdl-server is a Vault plugin. The local dev environment runs Vault and MinIO in Docker containers.
- Use
task server:setup:dev-environmentto set up the local dev environment (Vault + MinIO + plugin registration). - When testing trdl-server changes, restart the Vault container to reload the plugin.
ALWAYS verify after making changes, in this order. NEVER skip steps. NEVER assume "it probably compiles."
Default action when unsure: ALWAYS run the full verification pipeline.
Tool priority order: task format → task build:dev:all → task lint → task server:test:unit.
- ALWAYS run
task formatfirst — it mutates files, so other checks must run after it. - ALWAYS run
task build:dev:all— verify all modules compile. For a single module, usetask server:build,task client:build, ortask release:build. - ALWAYS run
task lint— NEVER ignore lint errors. For a single module, usetask server:lint,task client:lint,task release:lint, ortask e2e:lint. - ALWAYS run
task server:test:unit— verify tests pass. This step is MANDATORY, not optional. NEVER skip it, even if build and lint pass.
Scope verification to a single module when working in only one module. ALWAYS run full-project verification (task lint, task build:dev:all) at the end of a task.
When changes affect trdl-server (Vault plugin), ALSO verify against the local dev environment:
- Use
task server:setup:dev-environmentto ensure the dev environment is running. - Restart the Vault container to reload the updated plugin.