# 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
