feat: make agent capabilities data-driven via agent YAML metadata
Replace the hardcoded getAgentCapabilities() map with a data-driven pipeline. Capabilities are now defined in each .agent.yaml source file, compiled into the XML output, extracted into agent-manifest.csv by the manifest generator, and read by the GitHub Copilot handler at install time. New agents automatically get their capabilities without code changes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
eb0e1fb1a5
commit
cb1a7cccc8
|
|
@ -5,6 +5,7 @@ agent:
|
||||||
title: Business Analyst
|
title: Business Analyst
|
||||||
icon: 📊
|
icon: 📊
|
||||||
module: bmm
|
module: bmm
|
||||||
|
capabilities: "market research, competitive analysis, requirements elicitation, domain expertise"
|
||||||
hasSidecar: false
|
hasSidecar: false
|
||||||
|
|
||||||
persona:
|
persona:
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ agent:
|
||||||
title: Architect
|
title: Architect
|
||||||
icon: 🏗️
|
icon: 🏗️
|
||||||
module: bmm
|
module: bmm
|
||||||
|
capabilities: "distributed systems, cloud infrastructure, API design, scalable patterns"
|
||||||
hasSidecar: false
|
hasSidecar: false
|
||||||
|
|
||||||
persona:
|
persona:
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ agent:
|
||||||
title: Developer Agent
|
title: Developer Agent
|
||||||
icon: 💻
|
icon: 💻
|
||||||
module: bmm
|
module: bmm
|
||||||
|
capabilities: "story execution, test-driven development, code implementation"
|
||||||
hasSidecar: false
|
hasSidecar: false
|
||||||
|
|
||||||
persona:
|
persona:
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ agent:
|
||||||
title: Product Manager
|
title: Product Manager
|
||||||
icon: 📋
|
icon: 📋
|
||||||
module: bmm
|
module: bmm
|
||||||
|
capabilities: "PRD creation, requirements discovery, stakeholder alignment, user interviews"
|
||||||
hasSidecar: false
|
hasSidecar: false
|
||||||
|
|
||||||
persona:
|
persona:
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ agent:
|
||||||
title: QA Engineer
|
title: QA Engineer
|
||||||
icon: 🧪
|
icon: 🧪
|
||||||
module: bmm
|
module: bmm
|
||||||
|
capabilities: "test automation, API testing, E2E testing, coverage analysis"
|
||||||
hasSidecar: false
|
hasSidecar: false
|
||||||
|
|
||||||
persona:
|
persona:
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ agent:
|
||||||
title: Quick Flow Solo Dev
|
title: Quick Flow Solo Dev
|
||||||
icon: 🚀
|
icon: 🚀
|
||||||
module: bmm
|
module: bmm
|
||||||
|
capabilities: "rapid spec creation, lean implementation, minimum ceremony"
|
||||||
hasSidecar: false
|
hasSidecar: false
|
||||||
|
|
||||||
persona:
|
persona:
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ agent:
|
||||||
title: Scrum Master
|
title: Scrum Master
|
||||||
icon: 🏃
|
icon: 🏃
|
||||||
module: bmm
|
module: bmm
|
||||||
|
capabilities: "sprint planning, story preparation, agile ceremonies, backlog management"
|
||||||
hasSidecar: false
|
hasSidecar: false
|
||||||
|
|
||||||
persona:
|
persona:
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ agent:
|
||||||
title: Technical Writer
|
title: Technical Writer
|
||||||
icon: 📚
|
icon: 📚
|
||||||
module: bmm
|
module: bmm
|
||||||
|
capabilities: "documentation, Mermaid diagrams, standards compliance, concept explanation"
|
||||||
hasSidecar: true
|
hasSidecar: true
|
||||||
|
|
||||||
persona:
|
persona:
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ agent:
|
||||||
title: UX Designer
|
title: UX Designer
|
||||||
icon: 🎨
|
icon: 🎨
|
||||||
module: bmm
|
module: bmm
|
||||||
|
capabilities: "user research, interaction design, UI patterns, experience strategy"
|
||||||
hasSidecar: false
|
hasSidecar: false
|
||||||
|
|
||||||
persona:
|
persona:
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ agent:
|
||||||
name: "BMad Master"
|
name: "BMad Master"
|
||||||
title: "BMad Master Executor, Knowledge Custodian, and Workflow Orchestrator"
|
title: "BMad Master Executor, Knowledge Custodian, and Workflow Orchestrator"
|
||||||
icon: "🧙"
|
icon: "🧙"
|
||||||
|
capabilities: "runtime resource management, workflow orchestration, task execution, knowledge custodian"
|
||||||
hasSidecar: false
|
hasSidecar: false
|
||||||
|
|
||||||
persona:
|
persona:
|
||||||
|
|
|
||||||
|
|
@ -321,6 +321,7 @@ class ManifestGenerator {
|
||||||
const nameMatch = content.match(/name="([^"]+)"/);
|
const nameMatch = content.match(/name="([^"]+)"/);
|
||||||
const titleMatch = content.match(/title="([^"]+)"/);
|
const titleMatch = content.match(/title="([^"]+)"/);
|
||||||
const iconMatch = content.match(/icon="([^"]+)"/);
|
const iconMatch = content.match(/icon="([^"]+)"/);
|
||||||
|
const capabilitiesMatch = content.match(/capabilities="([^"]+)"/);
|
||||||
|
|
||||||
// Extract persona fields
|
// Extract persona fields
|
||||||
const roleMatch = content.match(/<role>([^<]+)<\/role>/);
|
const roleMatch = content.match(/<role>([^<]+)<\/role>/);
|
||||||
|
|
@ -342,6 +343,7 @@ class ManifestGenerator {
|
||||||
displayName: nameMatch ? nameMatch[1] : agentName,
|
displayName: nameMatch ? nameMatch[1] : agentName,
|
||||||
title: titleMatch ? titleMatch[1] : '',
|
title: titleMatch ? titleMatch[1] : '',
|
||||||
icon: iconMatch ? iconMatch[1] : '',
|
icon: iconMatch ? iconMatch[1] : '',
|
||||||
|
capabilities: capabilitiesMatch ? this.cleanForCSV(capabilitiesMatch[1]) : '',
|
||||||
role: roleMatch ? this.cleanForCSV(roleMatch[1]) : '',
|
role: roleMatch ? this.cleanForCSV(roleMatch[1]) : '',
|
||||||
identity: identityMatch ? this.cleanForCSV(identityMatch[1]) : '',
|
identity: identityMatch ? this.cleanForCSV(identityMatch[1]) : '',
|
||||||
communicationStyle: styleMatch ? this.cleanForCSV(styleMatch[1]) : '',
|
communicationStyle: styleMatch ? this.cleanForCSV(styleMatch[1]) : '',
|
||||||
|
|
@ -784,7 +786,7 @@ class ManifestGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create CSV header with persona fields
|
// Create CSV header with persona fields
|
||||||
let csvContent = 'name,displayName,title,icon,role,identity,communicationStyle,principles,module,path\n';
|
let csvContent = 'name,displayName,title,icon,capabilities,role,identity,communicationStyle,principles,module,path\n';
|
||||||
|
|
||||||
// Combine existing and new agents, preferring new data for duplicates
|
// Combine existing and new agents, preferring new data for duplicates
|
||||||
const allAgents = new Map();
|
const allAgents = new Map();
|
||||||
|
|
@ -802,6 +804,7 @@ class ManifestGenerator {
|
||||||
displayName: agent.displayName,
|
displayName: agent.displayName,
|
||||||
title: agent.title,
|
title: agent.title,
|
||||||
icon: agent.icon,
|
icon: agent.icon,
|
||||||
|
capabilities: agent.capabilities,
|
||||||
role: agent.role,
|
role: agent.role,
|
||||||
identity: agent.identity,
|
identity: agent.identity,
|
||||||
communicationStyle: agent.communicationStyle,
|
communicationStyle: agent.communicationStyle,
|
||||||
|
|
@ -818,6 +821,7 @@ class ManifestGenerator {
|
||||||
escapeCsv(record.displayName),
|
escapeCsv(record.displayName),
|
||||||
escapeCsv(record.title),
|
escapeCsv(record.title),
|
||||||
escapeCsv(record.icon),
|
escapeCsv(record.icon),
|
||||||
|
escapeCsv(record.capabilities),
|
||||||
escapeCsv(record.role),
|
escapeCsv(record.role),
|
||||||
escapeCsv(record.identity),
|
escapeCsv(record.identity),
|
||||||
escapeCsv(record.communicationStyle),
|
escapeCsv(record.communicationStyle),
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,7 @@ class GitHubCopilotSetup extends BaseIdeSetup {
|
||||||
if (manifestEntry) {
|
if (manifestEntry) {
|
||||||
const persona = manifestEntry.displayName || artifact.name;
|
const persona = manifestEntry.displayName || artifact.name;
|
||||||
const title = manifestEntry.title || this.formatTitle(artifact.name);
|
const title = manifestEntry.title || this.formatTitle(artifact.name);
|
||||||
const capabilities = this.getAgentCapabilities(artifact.name);
|
const capabilities = manifestEntry.capabilities || 'agent capabilities';
|
||||||
description = `${persona} — ${title}: ${capabilities}`;
|
description = `${persona} — ${title}: ${capabilities}`;
|
||||||
} else {
|
} else {
|
||||||
description = `Activates the ${this.formatTitle(artifact.name)} agent persona.`;
|
description = `Activates the ${this.formatTitle(artifact.name)} agent persona.`;
|
||||||
|
|
@ -188,28 +188,6 @@ You must fully embody this agent's persona and follow all activation instruction
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get capabilities string for an agent
|
|
||||||
* @param {string} agentName - Agent name
|
|
||||||
* @returns {string} Comma-separated capabilities
|
|
||||||
*/
|
|
||||||
getAgentCapabilities(agentName) {
|
|
||||||
const capabilitiesMap = {
|
|
||||||
'bmad-master': 'runtime resource management, workflow orchestration, task execution, knowledge custodian',
|
|
||||||
analyst: 'market research, competitive analysis, requirements elicitation, domain expertise',
|
|
||||||
architect: 'distributed systems, cloud infrastructure, API design, scalable patterns',
|
|
||||||
dev: 'story execution, test-driven development, code implementation',
|
|
||||||
pm: 'PRD creation, requirements discovery, stakeholder alignment, user interviews',
|
|
||||||
qa: 'test automation, API testing, E2E testing, coverage analysis',
|
|
||||||
'quick-flow-solo-dev': 'rapid spec creation, lean implementation, minimum ceremony',
|
|
||||||
sm: 'sprint planning, story preparation, agile ceremonies, backlog management',
|
|
||||||
'tech-writer': 'documentation, Mermaid diagrams, standards compliance, concept explanation',
|
|
||||||
'ux-designer': 'user research, interaction design, UI patterns, experience strategy',
|
|
||||||
};
|
|
||||||
|
|
||||||
return capabilitiesMap[agentName] || 'agent capabilities';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate .prompt.md files for workflows, tasks, tech-writer commands, and agent activators
|
* Generate .prompt.md files for workflows, tasks, tech-writer commands, and agent activators
|
||||||
* @param {string} projectDir - Project directory
|
* @param {string} projectDir - Project directory
|
||||||
|
|
@ -449,7 +427,7 @@ tools: ${toolsStr}
|
||||||
for (const agentName of agentOrder) {
|
for (const agentName of agentOrder) {
|
||||||
const meta = agentManifest.get(agentName);
|
const meta = agentManifest.get(agentName);
|
||||||
if (meta) {
|
if (meta) {
|
||||||
const capabilities = this.getAgentCapabilities(agentName);
|
const capabilities = meta.capabilities || 'agent capabilities';
|
||||||
const cleanTitle = (meta.title || '').replaceAll('""', '"');
|
const cleanTitle = (meta.title || '').replaceAll('""', '"');
|
||||||
agentsTable += `| ${agentName} | ${meta.displayName} | ${cleanTitle} | ${capabilities} |\n`;
|
agentsTable += `| ${agentName} | ${meta.displayName} | ${cleanTitle} | ${capabilities} |\n`;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -279,6 +279,9 @@ async function compileToXml(agentYaml, agentName = '', targetPath = '') {
|
||||||
`title="${meta.title || ''}"`,
|
`title="${meta.title || ''}"`,
|
||||||
`icon="${meta.icon || '🤖'}"`,
|
`icon="${meta.icon || '🤖'}"`,
|
||||||
];
|
];
|
||||||
|
if (meta.capabilities) {
|
||||||
|
agentAttrs.push(`capabilities="${escapeXml(meta.capabilities)}"`);
|
||||||
|
}
|
||||||
|
|
||||||
xml += `<agent ${agentAttrs.join(' ')}>\n`;
|
xml += `<agent ${agentAttrs.join(' ')}>\n`;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -228,6 +228,7 @@ function buildMetadataSchema(expectedModule) {
|
||||||
title: createNonEmptyString('agent.metadata.title'),
|
title: createNonEmptyString('agent.metadata.title'),
|
||||||
icon: createNonEmptyString('agent.metadata.icon'),
|
icon: createNonEmptyString('agent.metadata.icon'),
|
||||||
module: createNonEmptyString('agent.metadata.module').optional(),
|
module: createNonEmptyString('agent.metadata.module').optional(),
|
||||||
|
capabilities: createNonEmptyString('agent.metadata.capabilities').optional(),
|
||||||
hasSidecar: z.boolean(),
|
hasSidecar: z.boolean(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue