From 948e23156a6399aca944ffc317ad29db6686c7e9 Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Wed, 4 Mar 2026 22:07:24 +0100 Subject: [PATCH] refine skills prompt --- SKILLS_PROMPT.md | 32 ++++++++++++++++++++++++++++++++ claude/agent/anvillm-agent.md | 32 ++++++++++++++++++++++++++++++++ internal/p9/roles.go | 11 +++++++++-- internal/p9/skills.go | 11 +++++++++++ 4 files changed, 84 insertions(+), 2 deletions(-) diff --git a/SKILLS_PROMPT.md b/SKILLS_PROMPT.md index d1d3a7d..91c5920 100644 --- a/SKILLS_PROMPT.md +++ b/SKILLS_PROMPT.md @@ -34,6 +34,38 @@ Code: - Documentation → `documentation`, `notes` - Knowledge management → `knowledge`, `learning` +## Proactive Role Discovery + +**When user assigns you a specialized identity or requests specialized expertise**, discover and load relevant roles: + +Examples: +- "You are an API tester" → search for "API testing" role +- "I need help testing an API" → search for "API testing" role +- "Help me design a database schema" → search for "database" or "backend architect" role +- "Review this code for security issues" → search for "security" role + +1. Search for roles by **specific task keywords**: +``` +Tool: execute_code +Language: bash +Code: +bash <(9p read agent/tools/mcp/discover_role.sh) +``` + +2. Load role content: +``` +Tool: execute_code +Language: bash +Code: +9p read agent/roles//.md +``` + +3. Adopt the role's persona and expertise for your response + +**Use specific keywords, not broad categories:** +- ✓ "API testing", "backend architect", "security audit" (specific) +- ✗ "testing", "engineering", "QA" (too broad) + ## Tool Discovery For ANY AnviLLM task (sessions, messages, beads, agents, etc.): diff --git a/claude/agent/anvillm-agent.md b/claude/agent/anvillm-agent.md index d80d2c9..98ad47d 100644 --- a/claude/agent/anvillm-agent.md +++ b/claude/agent/anvillm-agent.md @@ -66,6 +66,38 @@ Code: - Documentation → `documentation`, `notes` - Knowledge management → `knowledge`, `learning` +## Proactive Role Discovery + +**When user assigns you a specialized identity or requests specialized expertise**, discover and load relevant roles: + +Examples: +- "You are an API tester" → search for "API testing" role +- "I need help testing an API" → search for "API testing" role +- "Help me design a database schema" → search for "database" or "backend architect" role +- "Review this code for security issues" → search for "security" role + +1. Search for roles by **specific task keywords**: +``` +Tool: execute_code +Language: bash +Code: +bash <(9p read agent/tools/mcp/discover_role.sh) +``` + +2. Load role content: +``` +Tool: execute_code +Language: bash +Code: +9p read agent/roles//.md +``` + +3. Adopt the role's persona and expertise for your response + +**Use specific keywords, not broad categories:** +- ✓ "API testing", "backend architect", "security audit" (specific) +- ✗ "testing", "engineering", "QA" (too broad) + ## Tool Discovery For ANY AnviLLM task (sessions, messages, beads, agents, etc.): diff --git a/internal/p9/roles.go b/internal/p9/roles.go index ae2ccd1..a2f8ea8 100644 --- a/internal/p9/roles.go +++ b/internal/p9/roles.go @@ -68,6 +68,7 @@ func parseRoleFrontMatter(rolePath string, derivedFocusAreas []string) (*RoleMet scanner := bufio.NewScanner(f) inFrontMatter := false hasFrontMatterFocusAreas := false + hasDescription := false for scanner.Scan() { line := scanner.Text() @@ -95,11 +96,17 @@ func parseRoleFrontMatter(rolePath string, derivedFocusAreas []string) (*RoleMet } } else if desc, ok := strings.CutPrefix(line, "description:"); ok { meta.Description = strings.TrimSpace(desc) + hasDescription = true } else if name, ok := strings.CutPrefix(line, "name:"); ok { meta.DisplayName = strings.TrimSpace(name) } } + // If missing description, exclude from list + if !hasDescription { + return nil, fmt.Errorf("missing description") + } + // If no frontmatter focus-areas and no derived, add "uncategorized" if !hasFrontMatterFocusAreas && len(derivedFocusAreas) == 0 { meta.FocusAreas = []string{"uncategorized"} @@ -210,7 +217,7 @@ func (r *RolesFS) listRolesInFocusArea(focusArea string) ([]*RoleMeta, error) { return result, nil } -// generateHelp creates aggregated index: focus-area/role-name\tdescription +// generateHelp creates aggregated index: focus-area/role-filename.md\tDisplayName\tDescription func (r *RolesFS) generateHelp() (string, error) { roles, err := r.listAllRoles() if err != nil { @@ -224,7 +231,7 @@ func (r *RolesFS) generateHelp() (string, error) { displayName = role.Name } for _, fa := range role.FocusAreas { - line := fmt.Sprintf("%s/%s\t%s", fa, displayName, role.Description) + line := fmt.Sprintf("%s/%s.md\t%s\t%s", fa, role.Name, displayName, role.Description) lines = append(lines, line) } } diff --git a/internal/p9/skills.go b/internal/p9/skills.go index 6c030ff..dbcf7b4 100644 --- a/internal/p9/skills.go +++ b/internal/p9/skills.go @@ -67,6 +67,8 @@ func parseSkillFrontMatter(skillDir string) (*SkillMeta, error) { scanner := bufio.NewScanner(f) inFrontMatter := false + hasName := false + hasDescription := false for scanner.Scan() { line := scanner.Text() @@ -91,11 +93,20 @@ func parseSkillFrontMatter(skillDir string) (*SkillMeta, error) { meta.Intents = append(meta.Intents, i) } } + } else if name, ok := strings.CutPrefix(line, "name:"); ok { + meta.Name = strings.TrimSpace(name) + hasName = true } else if desc, ok := strings.CutPrefix(line, "description:"); ok { meta.Description = strings.TrimSpace(desc) + hasDescription = true } } + // If missing name or description, return nil to exclude from list + if !hasName || !hasDescription { + return nil, fmt.Errorf("missing name or description") + } + return meta, nil }