e6c1671177
Mover issue 0016 a completed/ y actualizar README: El issue 0016-skills-system ha sido completado con todas las fases: - Estructura de directorios y skills de ejemplo - Tipos puros (pkg/skills/) - Loader y executor (shell/skills/) - Configuracion en schema - Tools de function calling - Integracion con runtime - Tests unitarios completos - Documentacion completa Estado en dev/issues/README.md: pendiente → completado Sistema de skills operativo y listo para usar.
256 lines
11 KiB
Markdown
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
|