2026-02-08 13:34:47 +09:00
import type { AgentPromptMetadata } from "./types"
2025-12-30 23:56:09 +09:00
export interface AvailableAgent {
2026-02-08 13:34:47 +09:00
name : string
2025-12-30 23:56:09 +09:00
description : string
metadata : AgentPromptMetadata
}
export interface AvailableTool {
name : string
category : "lsp" | "ast" | "search" | "session" | "command" | "other"
}
2026-01-01 15:37:24 +09:00
export interface AvailableSkill {
name : string
description : string
location : "user" | "project" | "plugin"
}
2026-01-20 16:53:46 +09:00
export interface AvailableCategory {
name : string
description : string
2026-02-06 17:31:13 +09:00
model? : string
2026-01-20 16:53:46 +09:00
}
2025-12-30 23:56:09 +09:00
export function categorizeTools ( toolNames : string [ ] ) : AvailableTool [ ] {
return toolNames . map ( ( name ) = > {
let category : AvailableTool [ "category" ] = "other"
if ( name . startsWith ( "lsp_" ) ) {
category = "lsp"
} else if ( name . startsWith ( "ast_grep" ) ) {
category = "ast"
} else if ( name === "grep" || name === "glob" ) {
category = "search"
} else if ( name . startsWith ( "session_" ) ) {
category = "session"
2026-02-18 18:40:10 +08:00
} else if ( name === "skill" ) {
2025-12-30 23:56:09 +09:00
category = "command"
}
return { name , category }
} )
}
function formatToolsForPrompt ( tools : AvailableTool [ ] ) : string {
const lspTools = tools . filter ( ( t ) = > t . category === "lsp" )
const astTools = tools . filter ( ( t ) = > t . category === "ast" )
const searchTools = tools . filter ( ( t ) = > t . category === "search" )
const parts : string [ ] = [ ]
if ( searchTools . length > 0 ) {
parts . push ( . . . searchTools . map ( ( t ) = > ` \` ${ t . name } \` ` ) )
}
if ( lspTools . length > 0 ) {
parts . push ( "`lsp_*`" )
}
if ( astTools . length > 0 ) {
parts . push ( "`ast_grep`" )
}
return parts . join ( ", " )
}
2026-01-22 22:45:41 +09:00
export function buildKeyTriggersSection ( agents : AvailableAgent [ ] , _skills : AvailableSkill [ ] = [ ] ) : string {
2025-12-30 23:56:09 +09:00
const keyTriggers = agents
. filter ( ( a ) = > a . metadata . keyTrigger )
. map ( ( a ) = > ` - ${ a . metadata . keyTrigger } ` )
2026-01-22 22:45:41 +09:00
if ( keyTriggers . length === 0 ) return ""
2025-12-30 23:56:09 +09:00
return ` ### Key Triggers (check BEFORE classification):
2026-01-01 15:37:24 +09:00
2026-01-22 22:45:41 +09:00
${ keyTriggers . join ( "\n" ) }
2025-12-30 23:56:09 +09:00
- **"Look into" + "create PR"** → Not just research. Full implementation cycle expected. `
}
2026-01-01 15:37:24 +09:00
export function buildToolSelectionTable (
agents : AvailableAgent [ ] ,
tools : AvailableTool [ ] = [ ] ,
2026-01-22 22:45:41 +09:00
_skills : AvailableSkill [ ] = [ ]
2026-01-01 15:37:24 +09:00
) : string {
2025-12-30 23:56:09 +09:00
const rows : string [ ] = [
2026-01-22 22:45:41 +09:00
"### Tool & Agent Selection:" ,
2025-12-30 23:56:09 +09:00
"" ,
]
if ( tools . length > 0 ) {
const toolsDisplay = formatToolsForPrompt ( tools )
2026-02-17 13:26:37 +09:00
rows . push ( ` - ${ toolsDisplay } — **FREE** — Not Complex, Scope Clear, No Implicit Assumptions ` )
2025-12-30 23:56:09 +09:00
}
const costOrder = { FREE : 0 , CHEAP : 1 , EXPENSIVE : 2 }
const sortedAgents = [ . . . agents ]
. filter ( ( a ) = > a . metadata . category !== "utility" )
. sort ( ( a , b ) = > costOrder [ a . metadata . cost ] - costOrder [ b . metadata . cost ] )
for ( const agent of sortedAgents ) {
const shortDesc = agent . description . split ( "." ) [ 0 ] || agent . description
2026-02-17 13:26:37 +09:00
rows . push ( ` - \` ${ agent . name } \` agent — ** ${ agent . metadata . cost } ** — ${ shortDesc } ` )
2025-12-30 23:56:09 +09:00
}
rows . push ( "" )
2026-01-22 22:45:41 +09:00
rows . push ( "**Default flow**: explore/librarian (background) + tools → oracle (if required)" )
2025-12-30 23:56:09 +09:00
return rows . join ( "\n" )
}
export function buildExploreSection ( agents : AvailableAgent [ ] ) : string {
const exploreAgent = agents . find ( ( a ) = > a . name === "explore" )
if ( ! exploreAgent ) return ""
const useWhen = exploreAgent . metadata . useWhen || [ ]
const avoidWhen = exploreAgent . metadata . avoidWhen || [ ]
return ` ### Explore Agent = Contextual Grep
Use it as a **peer tool**, not a fallback. Fire liberally.
2026-02-17 13:26:37 +09:00
**Use Direct Tools when:**
${ avoidWhen . map ( ( w ) = > ` - ${ w } ` ) . join ( "\n" ) }
**Use Explore Agent when:**
${ useWhen . map ( ( w ) = > ` - ${ w } ` ) . join ( "\n" ) } `
2025-12-30 23:56:09 +09:00
}
export function buildLibrarianSection ( agents : AvailableAgent [ ] ) : string {
const librarianAgent = agents . find ( ( a ) = > a . name === "librarian" )
if ( ! librarianAgent ) return ""
const useWhen = librarianAgent . metadata . useWhen || [ ]
return ` ### Librarian Agent = Reference Grep
Search **external references** (docs, OSS, web). Fire proactively when unfamiliar libraries are involved.
2026-02-17 13:26:37 +09:00
**Contextual Grep (Internal)** — search OUR codebase, find patterns in THIS repo, project-specific logic.
**Reference Grep (External)** — search EXTERNAL resources, official API docs, library best practices, OSS implementation examples.
2025-12-30 23:56:09 +09:00
**Trigger phrases** (fire librarian immediately):
${ useWhen . map ( ( w ) = > ` - " ${ w } " ` ) . join ( "\n" ) } `
}
export function buildDelegationTable ( agents : AvailableAgent [ ] ) : string {
const rows : string [ ] = [
"### Delegation Table:" ,
"" ,
]
for ( const agent of agents ) {
for ( const trigger of agent . metadata . triggers ) {
2026-02-17 13:26:37 +09:00
rows . push ( ` - ** ${ trigger . domain } ** → \` ${ agent . name } \` — ${ trigger . trigger } ` )
2025-12-30 23:56:09 +09:00
}
}
return rows . join ( "\n" )
}
2026-02-04 17:47:08 +01:00
2026-01-20 16:53:46 +09:00
export function buildCategorySkillsDelegationGuide ( categories : AvailableCategory [ ] , skills : AvailableSkill [ ] ) : string {
if ( categories . length === 0 && skills . length === 0 ) return ""
const categoryRows = categories . map ( ( c ) = > {
const desc = c . description || c . name
2026-02-17 13:26:37 +09:00
return ` - \` ${ c . name } \` — ${ desc } `
2026-01-20 16:53:46 +09:00
} )
2026-02-04 17:27:32 +01:00
const builtinSkills = skills . filter ( ( s ) = > s . location === "plugin" )
const customSkills = skills . filter ( ( s ) = > s . location !== "plugin" )
2026-02-19 17:41:29 +09:00
const builtinNames = builtinSkills . map ( ( s ) = > s . name ) . join ( ", " )
const customNames = customSkills . map ( ( s ) = > {
const source = s . location === "project" ? "project" : "user"
return ` ${ s . name } ( ${ source } ) `
} ) . join ( ", " )
2026-02-04 17:27:32 +01:00
let skillsSection : string
if ( customSkills . length > 0 && builtinSkills . length > 0 ) {
2026-02-19 17:41:29 +09:00
skillsSection = ` #### Available Skills (via \` skill \` tool)
2026-02-04 17:27:32 +01:00
2026-02-19 17:41:29 +09:00
**Built-in**: ${ builtinNames }
**⚡ YOUR SKILLS (PRIORITY)**: ${ customNames }
2026-02-04 17:27:32 +01:00
2026-02-19 17:41:29 +09:00
> User-installed skills OVERRIDE built-in defaults. ALWAYS prefer YOUR SKILLS when domain matches.
> Full skill descriptions → use the \` skill \` tool to check before EVERY delegation. `
2026-02-04 17:27:32 +01:00
} else if ( customSkills . length > 0 ) {
2026-02-19 17:41:29 +09:00
skillsSection = ` #### Available Skills (via \` skill \` tool)
2026-02-04 17:27:32 +01:00
2026-02-19 17:41:29 +09:00
**⚡ YOUR SKILLS (PRIORITY)**: ${ customNames }
2026-02-04 17:27:32 +01:00
2026-02-19 17:41:29 +09:00
> User-installed skills OVERRIDE built-in defaults. ALWAYS prefer YOUR SKILLS when domain matches.
> Full skill descriptions → use the \` skill \` tool to check before EVERY delegation. `
} else if ( builtinSkills . length > 0 ) {
skillsSection = ` #### Available Skills (via \` skill \` tool)
**Built-in**: ${ builtinNames }
> Full skill descriptions → use the \` skill \` tool to check before EVERY delegation. `
} else {
skillsSection = ""
2026-02-04 17:27:32 +01:00
}
2026-01-20 16:53:46 +09:00
return ` ### Category + Skills Delegation System
2026-02-06 16:01:54 +09:00
**task() combines categories and skills for optimal task execution.**
2026-01-20 16:53:46 +09:00
#### Available Categories (Domain-Optimized Models)
2025-12-30 23:56:09 +09:00
2026-01-20 16:53:46 +09:00
Each category is configured with a model optimized for that domain. Read the description to understand when to use it.
2025-12-30 23:56:09 +09:00
2026-01-20 16:53:46 +09:00
${ categoryRows . join ( "\n" ) }
2025-12-30 23:56:09 +09:00
2026-02-04 17:27:32 +01:00
${ skillsSection }
2025-12-30 23:56:09 +09:00
2026-01-20 16:53:46 +09:00
---
### MANDATORY: Category + Skill Selection Protocol
**STEP 1: Select Category**
- Read each category's description
- Match task requirements to category domain
- Select the category whose domain BEST fits the task
2026-02-19 17:41:29 +09:00
**STEP 2: Evaluate ALL Skills**
Check the \` skill \` tool for available skills and their descriptions. For EVERY skill, ask:
2026-01-20 16:53:46 +09:00
> "Does this skill's expertise domain overlap with my task?"
2026-01-22 22:45:41 +09:00
- If YES → INCLUDE in \` load_skills=[...] \`
2026-02-19 17:41:29 +09:00
- If NO → OMIT (no justification needed)
2026-02-04 17:27:32 +01:00
${ customSkills . length > 0 ? `
2026-02-19 17:41:29 +09:00
> **User-installed skills get PRIORITY.** When in doubt, INCLUDE rather than omit. ` : "" }
2026-01-15 16:32:14 +09:00
2026-01-20 16:53:46 +09:00
---
2026-01-15 16:32:14 +09:00
2026-01-20 16:53:46 +09:00
### Delegation Pattern
2026-01-15 16:32:14 +09:00
2026-01-20 16:53:46 +09:00
\` \` \` typescript
2026-02-06 16:01:54 +09:00
task(
2026-01-20 16:53:46 +09:00
category="[selected-category]",
2026-02-04 17:27:32 +01:00
load_skills=["skill-1", "skill-2"], // Include ALL relevant skills — ESPECIALLY user-installed ones
2026-01-20 16:53:46 +09:00
prompt="..."
)
\` \` \`
2026-01-15 16:32:14 +09:00
2026-01-20 16:53:46 +09:00
**ANTI-PATTERN (will produce poor results):**
\` \` \` typescript
2026-02-06 16:01:54 +09:00
task(category="...", load_skills=[], run_in_background=false, prompt="...") // Empty load_skills without justification
2026-03-06 22:19:18 +09:00
\` \` \`
---
### Category Domain Matching (ZERO TOLERANCE)
Every delegation MUST use the category that matches the task's domain. Mismatched categories produce measurably worse output because each category runs on a model optimized for that specific domain.
**VISUAL WORK = ALWAYS \` visual-engineering \` . NO EXCEPTIONS.**
Any task involving UI, UX, CSS, styling, layout, animation, design, or frontend components MUST go to \` visual-engineering \` . Never delegate visual work to \` quick \` , \` unspecified-* \` , or any other category.
\` \` \` typescript
// CORRECT: Visual work → visual-engineering category
task(category="visual-engineering", load_skills=["frontend-ui-ux"], prompt="Redesign the sidebar layout with new spacing...")
// WRONG: Visual work in wrong category — WILL PRODUCE INFERIOR RESULTS
task(category="quick", load_skills=[], prompt="Redesign the sidebar layout with new spacing...")
\` \` \`
| Task Domain | MUST Use Category |
|---|---|
| UI, styling, animations, layout, design | \` visual-engineering \` |
| Hard logic, architecture decisions, algorithms | \` ultrabrain \` |
| Autonomous research + end-to-end implementation | \` deep \` |
| Single-file typo, trivial config change | \` quick \` |
**When in doubt about category, it is almost never \` quick \` or \` unspecified-* \` . Match the domain.** `
2025-12-30 23:56:09 +09:00
}
export function buildOracleSection ( agents : AvailableAgent [ ] ) : string {
const oracleAgent = agents . find ( ( a ) = > a . name === "oracle" )
if ( ! oracleAgent ) return ""
const useWhen = oracleAgent . metadata . useWhen || [ ]
const avoidWhen = oracleAgent . metadata . avoidWhen || [ ]
return ` <Oracle_Usage>
2026-01-09 02:24:43 +09:00
## Oracle — Read-Only High-IQ Consultant
2025-12-30 23:56:09 +09:00
2026-01-09 02:24:43 +09:00
Oracle is a read-only, expensive, high-quality reasoning model for debugging and architecture. Consultation only.
2025-12-30 23:56:09 +09:00
2026-02-17 13:26:37 +09:00
### WHEN to Consult (Oracle FIRST, then implement):
2025-12-30 23:56:09 +09:00
2026-02-17 13:26:37 +09:00
${ useWhen . map ( ( w ) = > ` - ${ w } ` ) . join ( "\n" ) }
2025-12-30 23:56:09 +09:00
### WHEN NOT to Consult:
${ avoidWhen . map ( ( w ) = > ` - ${ w } ` ) . join ( "\n" ) }
### Usage Pattern:
Briefly announce "Consulting Oracle for [reason]" before invocation.
**Exception**: This is the ONLY case where you announce before acting. For all other work, start immediately without status updates.
2026-02-17 03:53:02 +09:00
### Oracle Background Task Policy:
2026-02-17 13:26:37 +09:00
2026-02-28 12:04:18 +09:00
**Collect Oracle results before your final answer. No exceptions.**
2026-02-17 13:26:37 +09:00
2026-02-28 12:04:18 +09:00
- Oracle takes minutes. When done with your own work: **end your response** — wait for the \` <system-reminder> \` .
- Do NOT poll \` background_output \` on a running Oracle. The notification will come.
- Never cancel Oracle.
2025-12-30 23:56:09 +09:00
</Oracle_Usage> `
}
2026-01-20 16:53:46 +09:00
export function buildHardBlocksSection ( ) : string {
2025-12-30 23:56:09 +09:00
const blocks = [
2026-02-17 13:26:37 +09:00
"- Type error suppression (`as any`, `@ts-ignore`) — **Never**" ,
"- Commit without explicit request — **Never**" ,
"- Speculate about unread code — **Never**" ,
"- Leave code in broken state after failures — **Never**" ,
2026-02-28 12:04:18 +09:00
"- `background_cancel(all=true)` — **Never.** Always cancel individually by taskId." ,
"- Delivering final answer before collecting Oracle result — **Never.**" ,
2025-12-30 23:56:09 +09:00
]
return ` ## Hard Blocks (NEVER violate)
${ blocks . join ( "\n" ) } `
}
2026-01-20 16:53:46 +09:00
export function buildAntiPatternsSection ( ) : string {
2025-12-30 23:56:09 +09:00
const patterns = [
2026-02-17 13:26:37 +09:00
"- **Type Safety**: `as any`, `@ts-ignore`, `@ts-expect-error`" ,
"- **Error Handling**: Empty catch blocks `catch(e) {}`" ,
"- **Testing**: Deleting failing tests to \"pass\"" ,
"- **Search**: Firing agents for single-line typos or obvious syntax errors" ,
"- **Debugging**: Shotgun debugging, random changes" ,
2026-02-28 12:04:18 +09:00
"- **Background Tasks**: Polling `background_output` on running tasks — end response and wait for notification" ,
"- **Oracle**: Delivering answer without collecting Oracle results" ,
2025-12-30 23:56:09 +09:00
]
return ` ## Anti-Patterns (BLOCKING violations)
${ patterns . join ( "\n" ) } `
}
2026-01-03 12:45:18 +09:00
2026-02-28 12:13:10 +09:00
export function buildNonClaudePlannerSection ( model : string ) : string {
const isNonClaude = ! model . toLowerCase ( ) . includes ( 'claude' )
if ( ! isNonClaude ) return ""
return ` ### Plan Agent Dependency (Non-Claude)
Multi-step task? **ALWAYS consult Plan Agent first.** Do NOT start implementation without a plan.
- Single-file fix or trivial change → proceed directly
- Anything else (2+ steps, unclear scope, architecture) → \` task(subagent_type="plan", ...) \` FIRST
- Use \` session_id \` to resume the same Plan Agent — ask follow-up questions aggressively
- If ANY part of the task is ambiguous, ask Plan Agent before guessing
Plan Agent returns a structured work breakdown with parallel execution opportunities. Follow it. `
}
2026-03-07 00:47:55 +09:00
export function buildParallelDelegationSection ( model : string , categories : AvailableCategory [ ] ) : string {
2026-02-22 03:20:57 +09:00
const isNonClaude = ! model . toLowerCase ( ) . includes ( 'claude' )
2026-03-07 00:47:55 +09:00
const hasDelegationCategory = categories . some ( c = > c . name === 'deep' || c . name === 'unspecified-high' )
2026-02-22 03:20:57 +09:00
2026-03-07 00:47:55 +09:00
if ( ! isNonClaude || ! hasDelegationCategory ) return ""
2026-02-22 03:20:57 +09:00
2026-03-07 00:47:55 +09:00
return ` ### DECOMPOSE AND DELEGATE — YOU ARE NOT AN IMPLEMENTER
2026-02-22 03:20:57 +09:00
2026-03-07 00:47:55 +09:00
**YOUR FAILURE MODE: You attempt to do work yourself instead of decomposing and delegating.** When you implement directly, the result is measurably worse than when specialized subagents do it. Subagents have domain-specific configurations, loaded skills, and tuned prompts that you lack.
2026-02-22 03:20:57 +09:00
2026-03-07 00:47:55 +09:00
**MANDATORY — for ANY implementation task:**
1. **ALWAYS decompose** the task into independent work units. No exceptions. Even if the task "feels small", decompose it.
2. **ALWAYS delegate** EACH unit to a \` deep \` or \` unspecified-high \` agent in parallel ( \` run_in_background=true \` ).
3. **NEVER work sequentially.** If 4 independent units exist, spawn 4 agents simultaneously. Not 1 at a time. Not 2 then 2.
4. **NEVER implement directly** when delegation is possible. You write prompts, not code.
**YOUR PROMPT TO EACH AGENT MUST INCLUDE:**
- GOAL with explicit success criteria (what "done" looks like)
- File paths and constraints (where to work, what not to touch)
- Existing patterns to follow (reference specific files the agent should read)
- Clear scope boundary (what is IN scope, what is OUT of scope)
**Vague delegation = failed delegation.** If your prompt to the subagent is shorter than 5 lines, it is too vague.
| You Want To Do | You MUST Do Instead |
|---|---|
| Write code yourself | Delegate to \` deep \` or \` unspecified-high \` agent |
| Handle 3 changes sequentially | Spawn 3 agents in parallel |
| "Quickly fix this one thing" | Still delegate — your "quick fix" is slower and worse than a subagent's |
**Your value is orchestration, decomposition, and quality control. Delegating with crystal-clear prompts IS your work.** `
2026-02-22 03:20:57 +09:00
}
2026-01-20 16:53:46 +09:00
export function buildUltraworkSection (
agents : AvailableAgent [ ] ,
categories : AvailableCategory [ ] ,
skills : AvailableSkill [ ]
) : string {
2026-01-03 12:51:04 +09:00
const lines : string [ ] = [ ]
2026-01-20 16:53:46 +09:00
if ( categories . length > 0 ) {
lines . push ( "**Categories** (for implementation tasks):" )
for ( const cat of categories ) {
const shortDesc = cat . description || cat . name
lines . push ( ` - \` ${ cat . name } \` : ${ shortDesc } ` )
}
lines . push ( "" )
}
if ( skills . length > 0 ) {
2026-02-04 17:27:32 +01:00
const builtinSkills = skills . filter ( ( s ) = > s . location === "plugin" )
const customSkills = skills . filter ( ( s ) = > s . location !== "plugin" )
if ( builtinSkills . length > 0 ) {
lines . push ( "**Built-in Skills** (combine with categories):" )
for ( const skill of builtinSkills ) {
const shortDesc = skill . description . split ( "." ) [ 0 ] || skill . description
lines . push ( ` - \` ${ skill . name } \` : ${ shortDesc } ` )
}
lines . push ( "" )
}
if ( customSkills . length > 0 ) {
lines . push ( "**User-Installed Skills** (HIGH PRIORITY - user installed these for their workflow):" )
for ( const skill of customSkills ) {
const shortDesc = skill . description . split ( "." ) [ 0 ] || skill . description
lines . push ( ` - \` ${ skill . name } \` : ${ shortDesc } ` )
}
lines . push ( "" )
2026-01-20 16:53:46 +09:00
}
}
if ( agents . length > 0 ) {
const ultraworkAgentPriority = [ "explore" , "librarian" , "plan" , "oracle" ]
const sortedAgents = [ . . . agents ] . sort ( ( a , b ) = > {
const aIdx = ultraworkAgentPriority . indexOf ( a . name )
const bIdx = ultraworkAgentPriority . indexOf ( b . name )
if ( aIdx === - 1 && bIdx === - 1 ) return 0
if ( aIdx === - 1 ) return 1
if ( bIdx === - 1 ) return - 1
return aIdx - bIdx
} )
lines . push ( "**Agents** (for specialized consultation/exploration):" )
for ( const agent of sortedAgents ) {
2026-02-07 18:45:29 +09:00
const shortDesc = agent . description . length > 120 ? agent . description . slice ( 0 , 120 ) + "..." : agent . description
2026-01-20 16:53:46 +09:00
const suffix = agent . name === "explore" || agent . name === "librarian" ? " (multiple)" : ""
lines . push ( ` - \` ${ agent . name } ${ suffix } \` : ${ shortDesc } ` )
}
2026-01-03 12:45:18 +09:00
}
2026-01-03 12:51:04 +09:00
return lines . join ( "\n" )
2026-01-03 12:45:18 +09:00
}