chore: eliminar issues completados del directorio pendiente
Los issues 0027, 0028 y 0031 fueron reintroducidos por el merge de quick/claude-skills (basada en master pre-limpieza). Se eliminan definitivamente — las copias en completed/ son la version final. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,112 +0,0 @@
|
||||
# 0027 — Limpiar config schema: eliminar codigo muerto
|
||||
|
||||
## Objetivo
|
||||
|
||||
Eliminar las secciones del config schema (`internal/config/schema.go`) que no estan implementadas ni referenciadas en el codebase. Reducir de 560 lineas / 61 structs a solo lo que realmente se usa.
|
||||
|
||||
## Contexto
|
||||
|
||||
- `internal/config/schema.go` tiene 560 lineas y 61 tipos struct
|
||||
- Secciones **nunca referenciadas** en ningun archivo `.go`:
|
||||
- `ObservabilityCfg` (metrics, tracing, health) — 0 usos
|
||||
- `ResilienceCfg` (circuit breaker, retry, queue) — 0 usos
|
||||
- `AgentsCfg` (peers, delegation, protocol) — 0 usos
|
||||
- `PersonalityCfg.Communication` (18 campos: humor, quirks, catchphrases) — 0 usos
|
||||
- El template `_template/config.yaml` tiene 414 lineas cuando un agente real necesita ~40
|
||||
- Esto complica el onboarding y crea confusion sobre que es funcional vs especulativo
|
||||
|
||||
## Arquitectura
|
||||
|
||||
```
|
||||
internal/config/schema.go → eliminar structs muertos (~180 lineas)
|
||||
agents/_template/config.yaml → reducir a lo esencial (~60 lineas)
|
||||
```
|
||||
|
||||
### Patron pure core / impure shell
|
||||
|
||||
- `pkg/` — sin cambios
|
||||
- `shell/` — sin cambios
|
||||
- `agents/` — template simplificado
|
||||
- `internal/config/` — poda de tipos
|
||||
|
||||
## Tareas
|
||||
|
||||
### Fase 1: Auditar uso real
|
||||
|
||||
- [ ] **1.1** Grep cada struct/campo del schema contra todo el codebase para confirmar cuales tienen 0 referencias
|
||||
- [ ] **1.2** Documentar en este issue la lista final de tipos a eliminar
|
||||
|
||||
### Fase 2: Podar schema.go
|
||||
|
||||
- [ ] **2.1** Eliminar `ObservabilityCfg` y todos sus sub-structs (LoggingCfg, MetricsCfg, HealthCfg, TracingCfg)
|
||||
- [ ] **2.2** Eliminar `ResilienceCfg` y sub-structs (CircuitBreakerCfg, RetryCfg, ShutdownCfg, QueueCfg)
|
||||
- [ ] **2.3** Eliminar `AgentsCfg` y sub-structs (PeerCfg, DelegationCfg)
|
||||
- [ ] **2.4** Eliminar campos no usados de `PersonalityCfg` (Communication, Humor, Quirks, etc.)
|
||||
- [ ] **2.5** Verificar que los campos eliminados no rompen el parsing YAML (yaml.v3 ignora campos extra por defecto)
|
||||
|
||||
### Fase 3: Simplificar template
|
||||
|
||||
- [ ] **3.1** Reescribir `agents/_template/config.yaml` con solo los campos funcionales (~60 lineas)
|
||||
- [ ] **3.2** Añadir comentarios explicativos en el template para cada seccion
|
||||
|
||||
### Fase 4: Tests
|
||||
|
||||
- [ ] **4.1** Verificar que los configs existentes (`assistant-bot`, `asistente-2`, `meteorologo`) siguen parseando correctamente
|
||||
- [ ] **4.2** `go build -tags goolm ./...` compila
|
||||
- [ ] **4.3** `go test -tags goolm ./...` pasa
|
||||
|
||||
### Fase 5: Cleanup
|
||||
|
||||
- [ ] **5.1** Actualizar `CLAUDE.md` si se mencionan secciones eliminadas
|
||||
- [ ] **5.2** Si algun config YAML existente usa campos eliminados, limpiar esas lineas
|
||||
|
||||
---
|
||||
|
||||
## Ejemplo de uso
|
||||
|
||||
Antes (template 414 lineas):
|
||||
```yaml
|
||||
personality:
|
||||
tone: friendly
|
||||
communication:
|
||||
formality: informal # nunca se usa
|
||||
humor: light # nunca se usa
|
||||
quirks: ["dice 'vale'"] # nunca se usa
|
||||
observability: # nunca se usa
|
||||
logging: ...
|
||||
metrics: ...
|
||||
resilience: # nunca se usa
|
||||
circuit_breaker: ...
|
||||
```
|
||||
|
||||
Despues (template ~60 lineas):
|
||||
```yaml
|
||||
agent:
|
||||
id: mi-agente
|
||||
description: "Descripcion"
|
||||
personality:
|
||||
tone: friendly
|
||||
language: es
|
||||
llm:
|
||||
primary:
|
||||
provider: openai
|
||||
model: gpt-4o
|
||||
matrix:
|
||||
threads:
|
||||
enabled: true
|
||||
```
|
||||
|
||||
## Decisiones de diseno
|
||||
|
||||
- **Eliminar, no comentar**: codigo muerto se borra, no se comenta con "// TODO: implement"
|
||||
- **Si se necesita en el futuro, se re-añade**: Git tiene historial. No mantener especulacion.
|
||||
- **yaml.v3 es tolerante**: campos extra en YAML no causan error, asi que eliminar structs no rompe configs existentes que tengan esos campos
|
||||
|
||||
## Prerequisitos
|
||||
|
||||
- Ninguno
|
||||
|
||||
## Riesgos
|
||||
|
||||
- **Falso negativo en grep**: algun campo podria usarse via reflection o string matching. Mitigacion: buscar tambien por nombre de campo en strings
|
||||
- **Configs de usuarios existentes**: si alguien tiene un config con `observability:`, no rompera (yaml.v3 ignora), pero el campo sera silenciosamente ignorado. Esto ya era el caso.
|
||||
@@ -1,109 +0,0 @@
|
||||
# 0028 — Desacoplar launcher del registro estatico de agentes
|
||||
|
||||
## Objetivo
|
||||
|
||||
Eliminar la necesidad de editar `cmd/launcher/main.go` cada vez que se añade un agente. Reemplazar el `rulesRegistry` hard-coded con auto-discovery basado en la convencion de directorios.
|
||||
|
||||
## Contexto
|
||||
|
||||
- Actualmente `cmd/launcher/main.go` importa cada paquete de agente explicitamente:
|
||||
```go
|
||||
import (
|
||||
assistantagent "github.com/enmanuel/agents/agents/assistant-bot"
|
||||
asistente2agent "github.com/enmanuel/agents/agents/asistente-2"
|
||||
)
|
||||
var rulesRegistry = map[string]func() []decision.Rule{...}
|
||||
```
|
||||
- Cada agente nuevo requiere: añadir import + añadir entrada al map + recompilar
|
||||
- El script `dev-scripts/agent/new-agent.sh` ya modifica el launcher automaticamente, pero es fragil (sed sobre codigo Go)
|
||||
- Contradiccion: el launcher hace glob de `agents/*/config.yaml` para descubrir configs, pero luego necesita imports estaticos para las reglas
|
||||
|
||||
## Arquitectura
|
||||
|
||||
```
|
||||
agents/registry.go NEW → registro global de reglas (init-based)
|
||||
agents/<id>/agent.go → cada agente se auto-registra via init()
|
||||
cmd/launcher/main.go → eliminar rulesRegistry, usar agents.GetRules(id)
|
||||
```
|
||||
|
||||
### Patron pure core / impure shell
|
||||
|
||||
- `pkg/` — sin cambios
|
||||
- `shell/` — sin cambios
|
||||
- `agents/` — nuevo registry global + init() en cada agente
|
||||
- `cmd/launcher/` — simplificacion
|
||||
|
||||
## Tareas
|
||||
|
||||
### Fase 1: Crear registry de reglas
|
||||
|
||||
- [ ] **1.1** Crear `agents/registry.go` con `Register(id, rulesFn)` y `GetRules(id)`
|
||||
- [ ] **1.2** Usar sync.Mutex o sync.Map para seguridad en init()
|
||||
|
||||
### Fase 2: Migrar agentes a auto-registro
|
||||
|
||||
- [ ] **2.1** En `agents/assistant-bot/agent.go` añadir `func init() { agents.Register("assistant-bot", Rules) }`
|
||||
- [ ] **2.2** Repetir para `asistente-2` y `meteorologo`
|
||||
- [ ] **2.3** Actualizar `agents/_template/agent.go` con el patron init()
|
||||
|
||||
### Fase 3: Simplificar launcher
|
||||
|
||||
- [ ] **3.1** Eliminar imports explicitos de agentes en `cmd/launcher/main.go`
|
||||
- [ ] **3.2** Añadir blank import: `_ "github.com/enmanuel/agents/agents/assistant-bot"` (etc.)
|
||||
- [ ] **3.3** Reemplazar `rulesRegistry[id]` con `agents.GetRules(id)`
|
||||
- [ ] **3.4** Si no hay reglas registradas para un agent id, log warning y usar reglas vacias (command-only bot)
|
||||
|
||||
### Fase 4: Actualizar scripts
|
||||
|
||||
- [ ] **4.1** Simplificar `dev-scripts/agent/new-agent.sh` — ya no necesita editar el map, solo añadir blank import
|
||||
- [ ] **4.2** Actualizar `.claude/rules/create_agent.md` con el nuevo patron
|
||||
|
||||
### Fase 5: Tests
|
||||
|
||||
- [ ] **5.1** Test para `agents/registry.go` (register, get, get-missing)
|
||||
- [ ] **5.2** `go build -tags goolm ./...` compila
|
||||
- [ ] **5.3** `go test -tags goolm ./...` pasa
|
||||
|
||||
### Fase 6: Cleanup
|
||||
|
||||
- [ ] **6.1** Actualizar `CLAUDE.md` seccion sobre registro en launcher
|
||||
- [ ] **6.2** Eliminar codigo muerto del launcher
|
||||
|
||||
---
|
||||
|
||||
## Ejemplo de uso
|
||||
|
||||
Antes (crear agente):
|
||||
```go
|
||||
// cmd/launcher/main.go — editar manualmente
|
||||
import newagent "github.com/enmanuel/agents/agents/new-bot"
|
||||
var rulesRegistry = map[string]func() []decision.Rule{
|
||||
"new-bot": newagent.Rules, // añadir esta linea
|
||||
}
|
||||
```
|
||||
|
||||
Despues:
|
||||
```go
|
||||
// agents/new-bot/agent.go — auto-registro
|
||||
func init() {
|
||||
agents.Register("new-bot", Rules)
|
||||
}
|
||||
|
||||
// cmd/launcher/main.go — solo blank import
|
||||
import _ "github.com/enmanuel/agents/agents/new-bot"
|
||||
```
|
||||
|
||||
## Decisiones de diseno
|
||||
|
||||
- **init() + blank import**: patron estandar en Go (database/sql drivers, image codecs). Simple y familiar
|
||||
- **Blank imports en launcher**: siguen siendo estaticos en el codigo, pero son una linea trivial sin logica. El script de scaffolding puede añadirla sin riesgo de romper sintaxis Go
|
||||
- **No plugin system dinamico**: Go no tiene plugins portables. init() es el mecanismo idomatic
|
||||
|
||||
## Prerequisitos
|
||||
|
||||
- Ninguno (puede hacerse independiente de otros issues)
|
||||
|
||||
## Riesgos
|
||||
|
||||
- **Orden de init()**: Go garantiza init() dentro de un paquete, pero no entre paquetes. Mitigacion: el registro es un map simple, el orden no importa
|
||||
- **Olvidar blank import**: si no se añade el blank import, el agente no se registra y el launcher lo trata como command-only. Mitigacion: el script de scaffolding lo añade automaticamente
|
||||
@@ -1,179 +0,0 @@
|
||||
# 0031 — Expandir tools/file/ con write, list, append, delete
|
||||
|
||||
## Objetivo
|
||||
|
||||
Ampliar el paquete `tools/file/` con operaciones de escritura, listado, append y borrado. Mantener el patron deny-by-default, validacion de symlinks, y respetar el flag `read_only` del config.
|
||||
|
||||
## Contexto
|
||||
|
||||
- `tools/file/file.go` actualmente solo tiene `read_file` (107 lineas)
|
||||
- Seguridad existente: deny-by-default, symlink resolution via `EvalSymlinks`, output truncation a 64KB
|
||||
- Helpers existentes: `validatePath()` y `resolveReal()` ya estan listos para reutilizarse
|
||||
- Config `FileOpsCfg` tiene campos `AllowedPaths []string` y `ReadOnly bool` — ReadOnly ya existe pero no se usa porque no hay operaciones de escritura
|
||||
- Los agentes necesitan interactuar con carpetas de trabajo (workspaces, proyectos, outputs)
|
||||
|
||||
## Arquitectura
|
||||
|
||||
```
|
||||
tools/file/file.go → mantener read_file + validatePath (existente)
|
||||
tools/file/write.go NEW → write_file tool
|
||||
tools/file/list.go NEW → list_directory tool
|
||||
tools/file/append.go NEW → append_file tool
|
||||
tools/file/delete.go NEW → delete_file tool
|
||||
tools/file/file_test.go → ampliar tests existentes
|
||||
tools/file/write_test.go NEW → tests de escritura
|
||||
tools/file/list_test.go NEW → tests de listado
|
||||
tools/file/delete_test.go NEW → tests de borrado
|
||||
agents/runtime.go → registrar nuevas tools en buildToolRegistry()
|
||||
```
|
||||
|
||||
### Patron pure core / impure shell
|
||||
|
||||
- `pkg/` — sin cambios
|
||||
- `tools/file/` — cada tool sigue el patron Def (puro) + Exec (impuro)
|
||||
- `agents/` — solo cambio en registro de tools
|
||||
|
||||
## Tareas
|
||||
|
||||
### Fase 1: Refactor de validacion compartida
|
||||
|
||||
- [ ] **1.1** Extraer `validatePath()` y `resolveReal()` a `tools/file/validate.go` (ya son funciones internas, solo moverlas para reutilizarlas)
|
||||
- [ ] **1.2** Crear helper `validateWritePath(absPath, cfg)` que ademas verifica `ReadOnly == false`
|
||||
|
||||
### Fase 2: write_file
|
||||
|
||||
- [ ] **2.1** Crear `tools/file/write.go` con `NewWriteFile(cfg) tools.Tool`
|
||||
- [ ] **2.2** Parametros: `path` (string, required), `content` (string, required)
|
||||
- [ ] **2.3** Validaciones:
|
||||
- Rechazar si `cfg.ReadOnly == true`
|
||||
- `validatePath()` contra AllowedPaths
|
||||
- Crear directorios padre si no existen (`os.MkdirAll`)
|
||||
- Limite de contenido: max 1MB de input
|
||||
- [ ] **2.4** Devolver confirmacion con bytes escritos y path
|
||||
|
||||
### Fase 3: list_directory
|
||||
|
||||
- [ ] **3.1** Crear `tools/file/list.go` con `NewListDirectory(cfg) tools.Tool`
|
||||
- [ ] **3.2** Parametros: `path` (string, required), `recursive` (boolean, optional, default false)
|
||||
- [ ] **3.3** Validaciones:
|
||||
- `validatePath()` contra AllowedPaths
|
||||
- Limite de entries: max 500 archivos en el output
|
||||
- No seguir symlinks fuera de AllowedPaths
|
||||
- [ ] **3.4** Output: lista con nombre, tamaño, tipo (file/dir), fecha modificacion
|
||||
|
||||
### Fase 4: append_file
|
||||
|
||||
- [ ] **4.1** Crear `tools/file/append.go` con `NewAppendFile(cfg) tools.Tool`
|
||||
- [ ] **4.2** Parametros: `path` (string, required), `content` (string, required)
|
||||
- [ ] **4.3** Validaciones:
|
||||
- Rechazar si `cfg.ReadOnly == true`
|
||||
- `validatePath()` contra AllowedPaths
|
||||
- Si el archivo no existe, crearlo (igual que write)
|
||||
- Limite de tamaño: verificar que archivo existente + contenido nuevo < 10MB
|
||||
- [ ] **4.4** Devolver confirmacion con bytes añadidos y tamaño total
|
||||
|
||||
### Fase 5: delete_file
|
||||
|
||||
- [ ] **5.1** Crear `tools/file/delete.go` con `NewDeleteFile(cfg) tools.Tool`
|
||||
- [ ] **5.2** Parametros: `path` (string, required)
|
||||
- [ ] **5.3** Validaciones:
|
||||
- Rechazar si `cfg.ReadOnly == true`
|
||||
- `validatePath()` contra AllowedPaths
|
||||
- **Solo archivos**: no permitir borrar directorios (prevencion de `rm -rf` accidental)
|
||||
- Resolver symlinks antes de borrar (no borrar el symlink si apunta fuera de AllowedPaths)
|
||||
- [ ] **5.4** Devolver confirmacion con path eliminado
|
||||
|
||||
### Fase 6: Registro en runtime
|
||||
|
||||
- [ ] **6.1** En `agents/runtime.go` → `buildToolRegistry()`, registrar las 4 tools nuevas condicionalmente:
|
||||
```go
|
||||
if cfg.Tools.FileOps.Enabled {
|
||||
reg.Register(file.NewReadFile(cfg.Tools.FileOps))
|
||||
if !cfg.Tools.FileOps.ReadOnly {
|
||||
reg.Register(file.NewWriteFile(cfg.Tools.FileOps))
|
||||
reg.Register(file.NewAppendFile(cfg.Tools.FileOps))
|
||||
reg.Register(file.NewDeleteFile(cfg.Tools.FileOps))
|
||||
}
|
||||
reg.Register(file.NewListDirectory(cfg.Tools.FileOps))
|
||||
}
|
||||
```
|
||||
- [ ] **6.2** `list_directory` se registra siempre (no requiere escritura)
|
||||
|
||||
### Fase 7: Tests
|
||||
|
||||
- [ ] **7.1** Test: `write_file` crea archivo nuevo en AllowedPaths
|
||||
- [ ] **7.2** Test: `write_file` rechaza si ReadOnly es true
|
||||
- [ ] **7.3** Test: `write_file` rechaza paths fuera de AllowedPaths
|
||||
- [ ] **7.4** Test: `write_file` rechaza contenido > 1MB
|
||||
- [ ] **7.5** Test: `list_directory` lista correctamente archivos y subdirectorios
|
||||
- [ ] **7.6** Test: `list_directory` respeta limite de 500 entries
|
||||
- [ ] **7.7** Test: `list_directory` no sigue symlinks fuera de AllowedPaths
|
||||
- [ ] **7.8** Test: `append_file` añade contenido al final
|
||||
- [ ] **7.9** Test: `append_file` crea archivo si no existe
|
||||
- [ ] **7.10** Test: `delete_file` borra archivo existente
|
||||
- [ ] **7.11** Test: `delete_file` rechaza borrar directorios
|
||||
- [ ] **7.12** Test: `delete_file` rechaza si ReadOnly es true
|
||||
- [ ] **7.13** Test: symlink que apunta fuera de AllowedPaths es rechazado en todas las tools
|
||||
- [ ] **7.14** Test: path traversal (`../`) es rechazado en todas las tools
|
||||
|
||||
### Fase 8: Cleanup
|
||||
|
||||
- [ ] **8.1** Actualizar `CLAUDE.md` seccion de tools con las nuevas herramientas
|
||||
- [ ] **8.2** Actualizar `.claude/rules/create_tool.md` si hay nuevos patrones
|
||||
- [ ] **8.3** `go build -tags goolm ./...` y `go test -tags goolm ./...`
|
||||
|
||||
---
|
||||
|
||||
## Ejemplo de uso
|
||||
|
||||
Config del agente:
|
||||
```yaml
|
||||
tools:
|
||||
file:
|
||||
enabled: true
|
||||
allowed_paths:
|
||||
- "/home/ubuntu/workspace/proyecto-x"
|
||||
read_only: false
|
||||
```
|
||||
|
||||
Interaccion en Element:
|
||||
```
|
||||
Usuario: Lista los archivos en /home/ubuntu/workspace/proyecto-x/src
|
||||
Bot: [usa list_directory] Encontre 12 archivos:
|
||||
- main.go (2.3 KB, 2026-04-01)
|
||||
- handler.go (1.1 KB, 2026-04-02)
|
||||
- ...
|
||||
|
||||
Usuario: Escribe un archivo test.txt con "hola mundo"
|
||||
Bot: [usa write_file] Archivo creado: /home/ubuntu/workspace/proyecto-x/test.txt (10 bytes)
|
||||
|
||||
Usuario: Añade una linea mas al test.txt
|
||||
Bot: [usa append_file] Contenido añadido: 15 bytes (total: 25 bytes)
|
||||
|
||||
Usuario: Borra el test.txt
|
||||
Bot: [usa delete_file] Archivo eliminado: /home/ubuntu/workspace/proyecto-x/test.txt
|
||||
```
|
||||
|
||||
Intento fuera de AllowedPaths:
|
||||
```
|
||||
Usuario: Lee /etc/passwd
|
||||
Bot: Error: path "/etc/passwd" not under any allowed path
|
||||
```
|
||||
|
||||
## Decisiones de diseno
|
||||
|
||||
- **ReadOnly como gate**: `write_file`, `append_file`, `delete_file` solo se registran si `ReadOnly == false`. `read_file` y `list_directory` siempre se registran si file tools esta habilitado
|
||||
- **Solo archivos en delete**: borrar directorios es demasiado peligroso para un agente autonomo. Si necesita borrar un directorio, puede borrar archivos uno por uno
|
||||
- **Limites de tamaño**: 1MB para write (evita saturar disco), 64KB para read output (evita saturar contexto LLM), 500 entries para list (evita listados enormes)
|
||||
- **Crear padres automaticamente**: `write_file` hace `MkdirAll` para crear la estructura de directorios. Simplifica el uso sin riesgo de seguridad (los paths padre tambien estan bajo AllowedPaths)
|
||||
- **Reutilizar validatePath()**: misma logica de seguridad para todas las operaciones. Un solo punto de validacion
|
||||
|
||||
## Prerequisitos
|
||||
|
||||
- Ninguno
|
||||
|
||||
## Riesgos
|
||||
|
||||
- **Escritura accidental**: un agente con LLM podria decidir escribir archivos incorrectos. Mitigacion: AllowedPaths restringe donde puede escribir, y el system prompt debe instruir al agente sobre cuando escribir
|
||||
- **Race conditions**: dos agentes escribiendo el mismo archivo. Mitigacion: file locking no es necesario en la primera version; los agentes tipicamente tienen workspaces separados
|
||||
- **Disk exhaustion**: un agente escribiendo en loop. Mitigacion: rate limiting del tool registry + limite de 1MB por write
|
||||
Reference in New Issue
Block a user