Files
agents_and_robots/dev/issues/0016-skills-system.md
T
egutierrez 2756557498 chore: renombrar issues a formato 4 dígitos (NNNN)
Se estandariza la numeración de todos los issues de 3 dígitos a 4 dígitos
(e.g. 005 → 0005, 010 → 0010) para mantener consistencia con la convención
definida en create_issue.md. Se actualiza el README con los nuevos nombres
y links. No hay cambios de contenido en los issues, solo renombrado.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 18:39:33 +00:00

256 lines
11 KiB
Markdown

# 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/<categoria>/<skill-name>/
├── 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/<cat>/<name>/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