# 016 — Sistema de Skills para agentes ## Objetivo Crear un sistema de skills reutilizables que los agentes puedan cargar y ejecutar. Las skills son paquetes de instrucciones, scripts y recursos que amplian las capacidades de un agente mas alla de las tools de function calling. Mientras las tools son funciones atomicas (clock, http_get, ssh_command), las skills son flujos completos de trabajo (deploy a produccion, analizar logs, generar reportes). ## Contexto - Las **tools** (`tools/`) son funciones atomicas: reciben args, ejecutan, devuelven resultado. El LLM las invoca via function calling. - Las **skills** son paquetes de instrucciones + recursos que guian al agente para completar tareas complejas multi-paso. Son como "recetas" que el agente sigue. - Ejemplo: una tool es `ssh_command`. Una skill es "deploy-service" que usa ssh_command, http_get, y logica condicional para hacer un deploy completo. ## Prerequisitos - Ninguno estricto. El sistema de tools existente sigue funcionando igual. --- ## Estructura de una skill ``` skills/// ├── SKILL.md ← obligatorio (frontmatter YAML + instrucciones markdown) ├── LICENSE.txt ← opcional ├── scripts/ ← opcional, codigo ejecutable (bash, python, etc.) ├── references/ ← opcional, docs de referencia ├── templates/ ← opcional, plantillas/assets └── assets/ ← opcional, fuentes, iconos, etc. ``` ### SKILL.md — formato ```yaml --- name: skill-name description: > Descripcion clara de que hace la skill y cuando debe activarse. Esta descripcion es el mecanismo principal de triggering. --- # Instrucciones Cuerpo markdown con las instrucciones completas. Idealmente < 500 lineas. ``` ### Carga progresiva (3 niveles) 1. **Metadata** (name + description) — siempre en contexto (~100 palabras). El agente la lee para decidir si activar la skill. 2. **Cuerpo del SKILL.md** — se carga cuando la skill se activa. Instrucciones principales. 3. **Recursos bundled** (scripts/, references/, etc.) — se cargan bajo demanda. El SKILL.md indica cuando leer cada archivo. ### Carpetas opcionales | Carpeta | Proposito | |---------|-----------| | `scripts/` | Codigo ejecutable que el agente corre (bash, python). Puede ejecutarlos sin cargarlos en contexto. | | `references/` | Documentacion extensa, leida solo cuando es relevante. Si > 300 lineas, agregar TOC al inicio. | | `templates/` | Plantillas que la skill usa como base para generar outputs. | | `assets/` | Archivos estaticos (fuentes, iconos, imagenes). | --- ## Tareas ### Fase 1: Estructura de directorios y skills iniciales - [ ] **1.1** Crear la carpeta `skills/` en la raiz del proyecto con subcategorias: ``` skills/ ├── README.md ← documentacion del sistema de skills ├── devops/ ← skills de operaciones y deploy ├── analysis/ ← skills de analisis de datos/logs ├── communication/ ← skills de comunicacion y notificaciones ├── coding/ ← skills de desarrollo y code review └── system/ ← skills de administracion del sistema ``` - [ ] **1.2** Crear skills iniciales de ejemplo: - `skills/devops/deploy-service/SKILL.md` — deploy de un servicio via SSH - `skills/analysis/log-analyzer/SKILL.md` — analisis de logs con patrones - `skills/communication/daily-report/SKILL.md` — generar y enviar reporte diario - `skills/system/health-check/SKILL.md` — verificar salud de servicios ### Fase 2: Tipos puros en `pkg/skills/` - [ ] **2.1** Crear `pkg/skills/types.go` con los tipos puros: ```go // SkillMeta es la metadata extraida del frontmatter YAML del SKILL.md. type SkillMeta struct { Name string `yaml:"name"` Description string `yaml:"description"` Category string // derivado de la ruta del directorio } // Skill es la representacion completa de una skill cargada. type Skill struct { Meta SkillMeta Instructions string // cuerpo markdown del SKILL.md BasePath string // ruta al directorio de la skill Scripts []string // rutas relativas a scripts/ References []string // rutas relativas a references/ Templates []string // rutas relativas a templates/ } // SkillMatch indica si una skill es relevante para un contexto dado. type SkillMatch struct { Skill SkillMeta Confidence float64 // 0.0 - 1.0 } ``` - [ ] **2.2** Crear `pkg/skills/match.go` — funcion pura que dado un mensaje y una lista de `SkillMeta`, retorna las skills mas relevantes: ```go func Match(query string, skills []SkillMeta) []SkillMatch ``` Implementacion inicial: keyword matching simple contra name + description. ### Fase 3: Loader en `shell/skills/` - [ ] **3.1** Crear `shell/skills/loader.go` — carga skills desde el filesystem: ```go // Loader descubre y carga skills desde un directorio base. type Loader struct { basePath string } func NewLoader(basePath string) *Loader func (l *Loader) LoadAll() ([]skills.Skill, error) // carga todas las skills func (l *Loader) LoadMeta() ([]skills.SkillMeta, error) // solo metadata (nivel 1) func (l *Loader) LoadSkill(name string) (*skills.Skill, error) // skill completa (nivel 2) func (l *Loader) ReadResource(skill, path string) (string, error) // recurso (nivel 3) ``` - [ ] **3.2** Implementar parsing del SKILL.md: - Extraer frontmatter YAML entre `---` - Extraer cuerpo markdown - Listar archivos en subcarpetas opcionales ### Fase 4: Integracion con el runtime - [ ] **4.1** Anadir `skillLoader *shellskills.Loader` al struct `Agent` en `agents/runtime.go` - [ ] **4.2** Crear una tool `skill_search` en `tools/skills/` que permita al LLM buscar skills relevantes: ```go // Def: name="skill_search", params=[{name: "query", type: "string"}] // Exec: usa el loader para buscar skills por relevancia ``` - [ ] **4.3** Crear una tool `skill_load` en `tools/skills/` que cargue el contenido completo de una skill: ```go // Def: name="skill_load", params=[{name: "skill_name", type: "string"}] // Exec: retorna las instrucciones completas del SKILL.md ``` - [ ] **4.4** Crear una tool `skill_read_resource` para cargar recursos bajo demanda: ```go // Def: name="skill_read_resource", params=[{name: "skill_name"}, {name: "path"}] // Exec: lee un archivo de scripts/, references/, templates/, o assets/ ``` - [ ] **4.5** Registrar las tools de skills en el builder de tools de `runtime.go` - [ ] **4.6** Inyectar la lista de skills disponibles (nivel 1: metadata) en el system prompt del agente, para que sepa que skills tiene a disposicion. ### Fase 5: Configuracion - [ ] **5.1** Anadir seccion `skills:` al config schema en `internal/config/schema.go`: ```go type SkillsCfg struct { Enabled bool `yaml:"enabled"` SkillsPath string `yaml:"path"` // default: "skills/" Categories []string `yaml:"categories"` // filtro opcional de categorias } ``` - [ ] **5.2** Anadir `SkillsCfg` al `AgentConfig` principal - [ ] **5.3** Respetar el filtro de categorias: si un agente solo tiene `categories: [devops, system]`, no carga skills de `analysis/` o `communication/` ### Fase 6: Ejecucion de scripts - [ ] **6.1** Evaluar como ejecutar scripts de skills de forma segura: - Los scripts viven en `skills///scripts/` - El agente necesita permisos para ejecutarlos (similar a ssh_command) - Opcion A: ejecutar via `os/exec` con sandbox basico (allowlist de interpreters) - Opcion B: ejecutar via SSH contra localhost (reutiliza infra existente) - Opcion C: solo permitir bash scripts con validacion previa - **Recomendacion**: opcion A con allowlist configurable de interpreters - [ ] **6.2** Crear `shell/skills/executor.go` para ejecutar scripts: ```go type Executor struct { allowedInterpreters []string // ["bash", "python3", "sh"] timeout time.Duration } func (e *Executor) Run(ctx context.Context, scriptPath string, args []string) (string, error) ``` - [ ] **6.3** Crear tool `skill_run_script` en `tools/skills/`: ```go // Def: name="skill_run_script", params=[{name: "skill_name"}, {name: "script"}, {name: "args"}] // Exec: ejecuta un script de la skill con el executor ``` ### Fase 7: Tests - [ ] **7.1** Unit tests para `pkg/skills/types.go` — verificar parsing de metadata - [ ] **7.2** Unit tests para `pkg/skills/match.go` — verificar matching de skills - [ ] **7.3** Unit tests para `shell/skills/loader.go` — verificar carga desde filesystem (con directorio temporal) - [ ] **7.4** Unit tests para `shell/skills/executor.go` — verificar ejecucion de scripts - [ ] **7.5** Integration test: un agente con skills habilitadas puede buscar, cargar y ejecutar una skill ### Fase 8: Documentacion - [ ] **8.1** Crear `skills/README.md` con la guia completa del sistema de skills - [ ] **8.2** Actualizar `CLAUDE.md` — anadir `skills/`, `pkg/skills/`, `shell/skills/` a la estructura - [ ] **8.3** Crear `.claude/rules/create_skill.md` — regla para crear nuevas skills - [ ] **8.4** Actualizar `docs/creating-agents.md` con la seccion de skills --- ## Orden de ejecucion recomendado 1. **Fase 1** (estructura + skills de ejemplo) — valida el formato antes de escribir codigo 2. **Fase 2** (tipos puros) — base para el loader y matching 3. **Fase 3** (loader) — carga skills desde disco 4. **Fase 5** (config) — permite habilitar/configurar skills por agente 5. **Fase 4** (integracion runtime) — conecta skills al agente via tools 6. **Fase 6** (ejecucion scripts) — opcional, solo si hay scripts 7. **Fase 7** (tests) — validar todo 8. **Fase 8** (docs) — cuando todo este estable ## Decisiones de diseno - **Skills vs Tools**: las tools son atomicas (function calling). Las skills son flujos multi-paso que el agente sigue como instrucciones. Las skills USAN tools internamente. - **Carga progresiva**: no cargar todo en contexto — solo metadata siempre, instrucciones cuando se activa, recursos bajo demanda. - **Skills como carpeta en raiz**: viven en `skills/` (no en `pkg/` ni `shell/`) porque son contenido declarativo, no codigo Go. Similar a como `agents/` tiene configs y prompts. - **Subcategorias**: organizadas por dominio (devops, analysis, etc.) como los tools por funcion (clock, http, ssh, etc.). - **Seguridad de scripts**: los scripts de skills deben tener las mismas restricciones que ssh_command — allowlist de interpreters, timeout, sin acceso a secretos directos. ## Analogia con el patron del proyecto ``` pkg/skills/ → PURE: tipos SkillMeta, Skill, SkillMatch + matching puro shell/skills/ → IMPURE: Loader (filesystem), Executor (os/exec) tools/skills/ → tools de function calling para que el LLM interactue con skills skills/ → contenido declarativo (SKILL.md + recursos) ``` ## Riesgos - Inflar el contexto del LLM si se cargan muchas skills de golpe — mitigado por carga progresiva - Ejecucion de scripts arbitrarios — mitigado por allowlist de interpreters y timeout - Complejidad innecesaria si los agentes actuales no necesitan skills — empezar con 2-3 skills simples y validar