skill-architect
The master skill for analyzing, designing, and standardizing the creation of new AI skills (Skill 72).
Installation
Suivez les instructions du dépôt pour votre agent. Consultez les fichiers et dépendances avant l’installation.
Voir la source ↗GuidesInstructions
Skill Architect
Overview
Skill Architect เป็น meta-skill สำหรับออกแบบ ประกอบ และ orchestrate skills อื่นๆ รวมถึง skill discovery, dependency resolution, skill composition patterns, และ skill orchestration เพื่อแก้ปัญหาที่ซับซ้อน
Why This Matters
- Modularity: Reuse skills ที่มีอยู่แล้วแทนสร้างใหม่
- Efficiency: Solve problems ได้เร็วขึ้นด้วยการใช้ skills ที่เหมาะสม
- Scalability: Skills สามารถขยายและ compose ได้
- Maintainability: Changes ที่ skill เดียว propagate ไปทั้งระบบ
Core Concepts
1. Skill Discovery
interface Skill {
id: string
name: string
description: string
capabilities: string[]
inputs: SkillInput[]
outputs: SkillOutput[]
dependencies: string[]
metadata: {
category: string
version: string
author: string
}
}
interface SkillInput {
name: string
type: string
required: boolean
description: string
}
interface SkillOutput {
name: string
type: string
description: string
}
class SkillRegistry {
private skills: Map<string, Skill> = new Map()
register(skill: Skill): void {
this.skills.set(skill.id, skill)
}
get(id: string): Skill | undefined {
return this.skills.get(id)
}
findByCapability(capability: string): Skill[] {
return Array.from(this.skills.values()).filter(skill =>
skill.capabilities.includes(capability)
)
}
findByCategory(category: string): Skill[] {
return Array.from(this.skills.values()).filter(skill =>
skill.metadata.category === category
)
}
search(query: string): Skill[] {
const lowerQuery = query.toLowerCase()
return Array.from(this.skills.values()).filter(skill =>
skill.name.toLowerCase().includes(lowerQuery) ||
skill.description.toLowerCase().includes(lowerQuery) ||
skill.capabilities.some(cap => cap.toLowerCase().includes(lowerQuery))
)
}
}
// Usage
const registry = new SkillRegistry()
registry.register({
id: 'skill-1',
name: 'Code Generator',
description: 'Generate code from natural language',
capabilities: ['code-generation', 'typescript', 'python'],
inputs: [
{ name: 'prompt', type: 'string', required: true, description: 'Code description' },
{ name: 'language', type: 'string', required: false, description: 'Programming language' },
],
outputs: [
{ name: 'code', type: 'string', description: 'Generated code' },
],
dependencies: [],
metadata: {
category: 'code-generation',
version: '1.0.0',
author: 'AI Team',
},
})
// Find skills by capability
const codeGenSkills = registry.findByCapability('code-generation')
// Search skills
const searchResults = registry.search('database')
2. Dependency Resolution
interface DependencyGraph {
nodes: Set<string>
edges: Map<string, string[]>
}
class DependencyResolver {
private registry: SkillRegistry
constructor(registry: SkillRegistry) {
this.registry = registry
}
resolve(skillId: string): string[] {
const visited = new Set<string>()
const result: string[] = []
this.visit(skillId, visited, result)
return result
}
private visit(skillId: string, visited: Set<string>, result: string[]): void {
if (visited.has(skillId)) {
throw new Error(`Circular dependency detected: ${skillId}`)
}
visited.add(skillId)
const skill = this.registry.get(skillId)
if (!skill) {
throw new Error(`Skill not found: ${skillId}`)
}
// Visit dependencies first
for (const dep of skill.dependencies) {
this.visit(dep, visited, result)
}
// Add this skill
result.push(skillId)
}
buildGraph(skillId: string): DependencyGraph {
const nodes = new Set<string>()
const edges = new Map<string, string[]>()
this.buildGraphRecursive(skillId, nodes, edges)
return { nodes, edges }
}
private buildGraphRecursive(
skillId: string,
nodes: Set<string>,
edges: Map<string, string[]>
): void {
if (nodes.has(skillId)) {
return
}
nodes.add(skillId)
const skill = this.registry.get(skillId)
if (!skill) {
return
}
edges.set(skillId, [...skill.dependencies])
for (const dep of skill.dependencies) {
this.buildGraphRecursive(dep, nodes, edges)
}
}
detectCircularDependencies(skillId: string): string[] {
const visited = new Set<string>()
const recursionStack = new Set<string>()
const cycles: string[] = []
this.detectCycles(skillId, visited, recursionStack, cycles)
return cycles
}
private detectCycles(
skillId: string,
visited: Set<string>,
recursionStack: Set<string>,
cycles: string[]
): void {
visited.add(skillId)
recursionStack.add(skillId)
const skill = this.registry.get(skillId)
if (!skill) {
return
}
for (const dep of skill.dependencies) {
if (!visited.has(dep)) {
this.detectCycles(dep, visited, recursionStack, cycles)
} else if (recursionStack.has(dep)) {
cycles.push(dep)
}
}
recursionStack.delete(skillId)
}
}
// Usage
const resolver = new DependencyResolver(registry)
// Resolve dependencies in order
const executionOrder = resolver.resolve('skill-1')
console.log('Execution order:', executionOrder)
// Build dependency graph
const graph = resolver.buildGraph('skill-1')
console.log('Dependency graph:', graph)
// Detect circular dependencies
const cycles = resolver.detectCircularDependencies('skill-1')
if (cycles.length > 0) {
console.error('Circular dependencies detected:', cycles)
}
3. Skill Composition
interface SkillComposition {
id: string
name: string
skills: string[]
connections: SkillConnection[]
inputs: SkillInput[]
outputs: SkillOutput[]
}
interface SkillConnection {
from: { skillId: string; output: string }
to: { skillId: string; input: string }
transform?: (value: any) => any
}
class SkillComposer {
private registry: SkillRegistry
private resolver: DependencyResolver
constructor(registry: SkillRegistry) {
this.registry = registry
this.resolver = new DependencyResolver(registry)
}
compose(composition: SkillComposition): any {
// Validate composition
this.validateComposition(composition)
// Resolve dependencies
const executionOrder = this.resolver.resolve(composition.skills[0])
// Execute skills in order
const context: Map<string, any> = new Map()
for (const skillId of executionOrder) {
const skill = this.registry.get(skillId)!
const inputs = this.prepareInputs(skill, composition, context)
const outputs = await this.executeSkill(skill, inputs)
// Store outputs in context
for (const output of skill.outputs) {
context.set(`${skillId}.${output.name}`, outputs[output.name])
}
}
// Return final outputs
return this.prepareOutputs(composition, context)
}
private validateComposition(composition: SkillComposition): void {
// Check if all skills exist
for (const skillId of composition.skills) {
if (!this.registry.get(skillId)) {
throw new Error(`Skill not found: ${skillId}`)
}
}
// Check connections
for (const conn of composition.connections) {
const fromSkill = this.registry.get(conn.from.skillId)
const toSkill = this.registry.get(conn.to.skillId)
if (!fromSkill || !toSkill) {
throw new Error('Invalid connection: skill not found')
}
const fromOutput = fromSkill.outputs.find(o => o.name === conn.from.output)
const toInput = toSkill.inputs.find(i => i.name === conn.to.input)
if (!fromOutput) {
throw new Error(`Output not found: ${conn.from.output}`)
}
if (!toInput) {
throw new Error(`Input not found: ${conn.to.input}`)
}
}
}
private prepareInputs(
skill: Skill,
composition: SkillComposition,
context: Map<string, any>
): Map<string, any> {
const inputs = new Map<string, any>()
for (const input of skill.inputs) {
// Find connection to this input
const connection = composition.connections.find(
c => c.to.skillId === skill.id && c.to.input === input.name
)
if (connection) {
// Get value from context
const value = context.get(
`${connection.from.skillId}.${connection.from.output}`
)
// Apply transform if exists
const transformed = connection.transform
? connection.transform(value)
: value
inputs.set(input.name, transformed)
}
}
return inputs
}
private async executeSkill(
skill: Skill,
inputs: Map<string, any>
): Promise<Record<string, any>> {
// Execute skill (implementation depends on skill type)
// This is a placeholder
return {}
}
private prepareOutputs(
composition: SkillComposition,
context: Map<string, any>
): any {
const outputs: any = {}
for (const output of composition.outputs) {
// Find skill that produces this output
const connection = composition.connections.find(
c => c.to.input === output.name
)
if (connection) {
outputs[output.name] = context.get(
`${connection.from.skillId}.${connection.from.output}`
)
}
}
return outputs
}
}
// Usage
const composer = new SkillComposer(registry)
const composition: SkillComposition = {
id: 'compose-1',
name: 'Data Processing Pipeline',
skills: ['skill-fetch', 'skill-transform', 'skill-save'],
connections: [
{
from: { skillId: 'skill-fetch', output: 'data' },
to: { skillId: 'skill-transform', input: 'input' },
},
{
from: { skillId: 'skill-transform', output: 'result' },
to: { skillId: 'skill-save', input: 'data' },
},
],
inputs: [
{ name: 'url', type: 'string', required: true, description: 'Data URL' },
],
outputs: [
{ name: 'saved', type: 'boolean', description: 'Save success' },
],
}
const result = await composer.compose(composition)
4. Skill Orchestration
interface OrchestrationPlan {
steps: OrchestrationStep[]
context: Record<string, any>
}
interface OrchestrationStep {
id: string
skillId: string
inputs: Record<string, any>
condition?: (context: Record<string, any>) => boolean
parallel?: boolean
retry?: {
maxAttempts: number
backoff: number
}
}
class SkillOrchestrator {
private registry: SkillRegistry
constructor(registry: SkillRegistry) {
this.registry = registry
}
async execute(plan: OrchestrationPlan): Promise<Record<string, any>> {
const context = { ...plan.context }
const results: Record<string, any> = {}
// Group steps by parallel execution
const parallelGroups = this.groupParallelSteps(plan.steps)
for (const group of parallelGroups) {
if (group.length === 1) {
// Execute single step
const step = group[0]
if (!step.condition || step.condition(context)) {
const result = await this.executeStep(step, context)
results[step.id] = result
Object.assign(context, result)
}
} else {
// Execute parallel steps
const parallelResults = await Promise.all(
group.map(async (step) => {
if (!step.condition || step.condition(context)) {
const result = await this.executeStep(step, context)
return { stepId: step.id, result }
}
return { stepId: step.id, result: null }
})
)
for (const { stepId, result } of parallelResults) {
if (result !== null) {
results[stepId] = result
Object.assign(context, result)
}
}
}
}
return results
}
private groupParallelSteps(steps: OrchestrationStep[]): OrchestrationStep[][] {
const groups: OrchestrationStep[][] = []
let currentGroup: OrchestrationStep[] = []
let inParallel = false
for (const step of steps) {
if (step.parallel) {
if (!inParallel) {
if (currentGroup.length > 0) {
groups.push(currentGroup)
currentGroup = []
}
inParallel = true
}
currentGroup.push(step)
} else {
if (inParallel) {
groups.push(currentGroup)
currentGroup = []
inParallel = false
}
currentGroup.push(step)
}
}
if (currentGroup.length > 0) {
groups.push(currentGroup)
}
return groups
}
private async executeStep(
step: OrchestrationStep,
context: Record<string, any>
): Promise<Record<string, any>> {
const skill = this.registry.get(step.skillId)
if (!skill) {
throw new Error(`Skill not found: ${step.skillId}`)
}
// Prepare inputs with context substitution
const inputs = this.substituteContext(step.inputs, context)
// Execute with retry if configured
if (step.retry) {
return await this.executeWithRetry(skill, inputs, step.retry)
}
return await this.executeSkill(skill, inputs)
}
private substituteContext(
inputs: Record<string, any>,
context: Record<string, any>
): Record<string, any> {
const substituted: Record<string, any> = {}
for (const [key, value] of Object.entries(inputs)) {
if (typeof value === 'string' && value.startsWith('$')) {
const contextKey = value.substring(1)
substituted[key] = context[contextKey]
} else {
substituted[key] = value
}
}
return substituted
}
private async executeWithRetry(
skill: Skill,
inputs: Record<string, any>,
retry: { maxAttempts: number; backoff: number }
): Promise<Record<string, any>> {
let lastError: Error | null = null
for (let attempt = 1; attempt <= retry.maxAttempts; attempt++) {
try {
return await this.executeSkill(skill, inputs)
} catch (error) {
lastError = error as Error
if (attempt < retry.maxAttempts) {
await this.sleep(retry.backoff * attempt)
}
}
}
throw lastError
}
private async executeSkill(
skill: Skill,
inputs: Record<string, any>
): Promise<Record<string, any>> {
// Execute skill (implementation depends on skill type)
return {}
}
private sleep(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms))
}
}
// Usage
const orchestrator = new SkillOrchestrator(registry)
const plan: OrchestrationPlan = {
steps: [
{
id: 'fetch-data',
skillId: 'skill-fetch',
inputs: { url: 'https://api.example.com/data' },
},
{
id: 'transform-data',
skillId: 'skill-transform',
inputs: { input: '$fetch-data.data' },
},
{
id: 'validate-data',
skillId: 'skill-validate',
inputs: { data: '$transform-data.result' },
},
{
id: 'save-data',
skillId: 'skill-save',
inputs: { data: '$transform-data.result' },
condition: (ctx) => ctx['validate-data'].valid === true,
},
],
context: {},
}
const results = await orchestrator.execute(plan)
5. Skill Templates
interface SkillTemplate {
id: string
name: string
description: string
parameters: TemplateParameter[]
skills: string[]
connections: SkillConnection[]
}
interface TemplateParameter {
name: string
type: string
default?: any
description: string
}
class SkillTemplateManager {
private templates: Map<string, SkillTemplate> = new Map()
register(template: SkillTemplate): void {
this.templates.set(template.id, template)
}
instantiate(
templateId: string,
parameters: Record<string, any>
): SkillComposition {
const template = this.templates.get(templateId)
if (!template) {
throw new Error(`Template not found: ${templateId}`)
}
// Validate parameters
this.validateParameters(template, parameters)
// Apply parameters
const skills = [...template.skills]
const connections = [...template.connections]
// Substitute parameters in connections
const substitutedConnections = connections.map(conn => ({
...conn,
transform: conn.transform
? this.substituteParameters(conn.transform, parameters)
: undefined,
}))
return {
id: `${templateId}-${Date.now()}`,
name: template.name,
skills,
connections: substitutedConnections,
inputs: [], // Derived from template
outputs: [], // Derived from template
}
}
private validateParameters(
template: SkillTemplate,
parameters: Record<string, any>
): void {
for (const param of template.parameters) {
if (param.default === undefined && !(param.name in parameters)) {
throw new Error(`Missing required parameter: ${param.name}`)
}
}
}
private substituteParameters(
fn: (value: any) => any,
parameters: Record<string, any>
): (value: any) => any {
return (value) => {
const result = fn(value)
// Substitute parameter references
return JSON.parse(
JSON.stringify(result).replace(
/\$\{(\w+)\}/g,
(_, key) => parameters[key] || `\${${key}}`
)
)
}
}
}
// Usage
const templateManager = new SkillTemplateManager()
templateManager.register({
id: 'template-pipeline',
name: 'Standard Pipeline',
description: 'Standard data processing pipeline',
parameters: [
{ name: 'transformFn', type: 'function', description: 'Transform function' },
],
skills: ['skill-fetch', 'skill-transform', 'skill-save'],
connections: [
{
from: { skillId: 'skill-fetch', output: 'data' },
to: { skillId: 'skill-transform', input: 'input' },
},
{
from: { skillId: 'skill-transform', output: 'result' },
to: { skillId: 'skill-save', input: 'data' },
transform: (value) => value, // Will be substituted with ${transformFn}
},
],
})
const composition = templateManager.instantiate('template-pipeline', {
transformFn: (data) => data.map(item => item * 2),
})
Quick Start
// 1. Create skill registry
const registry = new SkillRegistry()
// 2. Register skills
registry.register(skill1)
registry.register(skill2)
// 3. Create composer
const composer = new SkillComposer(registry)
// 4. Compose skills
const composition = {
id: 'my-composition',
skills: ['skill-1', 'skill-2'],
connections: [
{
from: { skillId: 'skill-1', output: 'result' },
to: { skillId: 'skill-2', input: 'input' },
},
],
inputs: [],
outputs: [],
}
const result = await composer.compose(composition)
Production Checklist
- Skill registry implemented
- Dependency resolution working
- Skill composition validated
- Orchestration configured
- Error handling in place
- Retry logic implemented
- Monitoring/logging enabled
- Templates defined
Anti-patterns
- Circular dependencies: Skills depend on each other
- No validation: Compose skills โดยไม่ validate inputs/outputs
- Hardcoded connections: Connections ไม่ flexible
- No error handling: Skill failures ทำให้ pipeline หยุด
- Over-composition: Compose เกินไปจนยาก maintain
Integration Points
- Skill registry
- Dependency managers
- Monitoring systems
- Logging frameworks
- API gateways
Further Reading
Exemples
Consultez les exemples du dépôt source.
Voir la source ↗Historique source
- Date d’indexation
- 2026-01-20
- Mise à jour de l’index
- 2026-01-26
- Branch
- main
Les dates concernent ce répertoire. Consultez le dépôt pour l’historique du code.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!