From bcbbd974e34e68d8025e69ce2bc05493e7ff688a Mon Sep 17 00:00:00 2001 From: Enmanuel Date: Wed, 4 Mar 2026 21:39:11 +0000 Subject: [PATCH] docs: add agent creation guide and LLM policies index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Documentación y políticas para la creación de agentes: - docs/creating-agents.md: guía completa paso a paso para humanos (scaffold, config, registro Matrix, avatar, verificación E2EE, arranque, troubleshooting) - .claude/policies/create_agent.md: policy para LLMs con estructura de archivos, convenciones y reglas a seguir al crear agentes - .claude/policies/index.md: índice de todas las policies disponibles - .claude/policies/create_tool.md: movido desde .claude/rules/ (misma policy) - CLAUDE.md: añadida sección de políticas, actualizada tabla de agentes con asistente-2, y actualizado el flujo de "Cómo añadir un nuevo bot" con pasos de avatar y verificación E2EE Co-Authored-By: Claude Opus 4.6 --- .claude/CLAUDE.md | 28 +- .claude/policies/create_agent.md | 144 +++++++++ .claude/{rules => policies}/create_tool.md | 0 .claude/policies/index.md | 23 ++ .gitignore | 3 +- docs/creating-agents.md | 322 +++++++++++++++++++++ 6 files changed, 513 insertions(+), 7 deletions(-) create mode 100644 .claude/policies/create_agent.md rename .claude/{rules => policies}/create_tool.md (100%) create mode 100644 .claude/policies/index.md create mode 100644 docs/creating-agents.md diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index e4f0e97..e50af07 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -58,11 +58,24 @@ cmd/register/main.go → registra bots en Synapse via admin API dev-scripts/ → scripts bash para operaciones del día a día ``` +## Políticas para LLMs + +Las políticas guían cómo ejecutar tareas específicas respetando la arquitectura del proyecto. +Ver índice completo en `.claude/policies/index.md`. + +| Política | Cuándo aplicarla | +|----------|------------------| +| `.claude/policies/create_agent.md` | Al crear un nuevo bot/agente Matrix | +| `.claude/policies/create_tool.md` | Al añadir una nueva tool para function calling | + +Documentación detallada para humanos en `docs/creating-agents.md`. + ## Agentes existentes | ID | Estado | LLM | Descripción | |----------------|-----------|---------|------------------------------------------| | assistant-bot | activo | GPT-4o | Asistente general, responde DMs | +| asistente-2 | activo | GPT-4o | Asistente con tools (current_time) | | devops-bot | pendiente | Claude | SSH, deployments, healthchecks | ## Dependencias clave @@ -90,12 +103,15 @@ Secciones principales del config: `agent`, `personality`, `llm`, `tools`, `matri ## Cómo añadir un nuevo bot -1. Generar scaffold: `./dev-scripts/new-agent.sh "Display Name"` -2. Registrarlo en Matrix: `./dev-scripts/register.sh "Display Name"` -3. Añadir el token al `.env` -4. Añadir una línea en `cmd/launcher/main.go` → `rulesRegistry` -5. Editar `agents//agent.go` con las reglas reales -6. Arrancar: `./dev-scripts/start.sh ` +Guía rápida (detalle completo en `docs/creating-agents.md`, policy en `.claude/policies/create_agent.md`): + +1. Crear scaffold: `./dev-scripts/new-agent.sh "Display Name"` o manual en `agents//` +2. Crear `agent.go` (reglas puras), `config.yaml`, `prompts/system.md` +3. Registrar en `cmd/launcher/main.go` → import + `rulesRegistry` +4. Registrar en Matrix: `./dev-scripts/register.sh "Display Name"` +5. Avatar y nombre: `./dev-scripts/avatar.sh static/.jpg` +6. Verificación E2EE: `go run -tags goolm ./cmd/verify --homeserver ... --username --password ... --token ...` +7. Arrancar: `./dev-scripts/start.sh ` ## Dev-scripts disponibles diff --git a/.claude/policies/create_agent.md b/.claude/policies/create_agent.md new file mode 100644 index 0000000..7327d26 --- /dev/null +++ b/.claude/policies/create_agent.md @@ -0,0 +1,144 @@ +# Cómo crear un nuevo agente + +Guía para LLMs que asisten en la creación de agentes en este proyecto. + +## Estructura requerida + +Cada agente vive en `agents//` con esta estructura: + +``` +agents// +├── agent.go # Package propio, exporta Rules() []decision.Rule +├── config.yaml # Configuración completa (ver schema en internal/config/schema.go) +└── prompts/ + └── system.md # System prompt del LLM +``` + +## Archivos a crear + +### 1. `agents//agent.go` — Reglas puras + +```go +package + +import "github.com/enmanuel/agents/pkg/decision" + +func Rules() []decision.Rule { + return []decision.Rule{ + // Regla help explícita + { + Name: "help", + Match: decision.MatchCommand("help"), + Actions: []decision.Action{{ + Kind: decision.ActionKindReply, + Reply: &decision.ReplyAction{Content: "Descripción de capacidades del bot."}, + }}, + }, + // Catch-all → LLM + { + Name: "llm-all", + Match: func(ctx decision.MessageContext) bool { + return ctx.IsDirectMsg || ctx.IsMention + }, + Actions: []decision.Action{{ + Kind: decision.ActionKindLLM, + LLM: &decision.LLMAction{}, + }}, + }, + } +} +``` + +**Reglas del archivo de reglas:** +- **PURO**: sin imports de I/O, sin side effects, solo `pkg/decision` +- El package name debe ser Go-valid (sin guiones): `agents/mi-bot/` → `package mibot` +- Las reglas se evalúan en orden — poner las específicas antes del catch-all +- El catch-all debe cubrir `ctx.IsDirectMsg || ctx.IsMention` como mínimo +- `ActionKindReply` para respuestas estáticas, `ActionKindLLM` para respuestas dinámicas + +### 2. `agents//config.yaml` — Configuración + +Usar como plantilla `agents/assistant/config.yaml` o `agents/asistente2/config.yaml`. + +**Campos que SIEMPRE hay que personalizar:** + +```yaml +agent: + id: # DEBE coincidir con el directorio y rulesRegistry + name: "Display Name" + description: "Qué hace este agente" + +llm: + primary: + provider: openai # o anthropic + model: gpt-4o # o claude-sonnet-4-20250514 + api_key_env: OPENAI_API_KEY # o ANTHROPIC_API_KEY + tool_use: + enabled: true/false # true si el agente usa herramientas + +matrix: + user_id: "@:matrix-af2f3d.organic-machine.com" + access_token_env: MATRIX_TOKEN_ + device_id: "" +``` + +**Convención de nombres de env vars:** +- Token: `MATRIX_TOKEN_` donde ID se convierte a mayúsculas y guiones a underscores +- Ejemplo: `asistente-2` → `MATRIX_TOKEN_ASISTENTE2` +- Password: `MATRIX_PASSWORD_` con la misma convención + +### 3. `agents//prompts/system.md` — System prompt + +Debe incluir: +- Identidad del bot (quién es, qué hace) +- Capacidades y limitaciones +- Herramientas disponibles (si `tool_use.enabled: true`) +- Estilo de respuesta (idioma, tono, formato) +- Instrucciones de uso de herramientas (cuándo y cómo usarlas) + +## Archivos a modificar + +### 4. `cmd/launcher/main.go` — Registro en el launcher + +Dos cambios: + +**Import:** +```go +agent "github.com/enmanuel/agents/agents/" +``` + +**rulesRegistry:** +```go +var rulesRegistry = map[string]func() []decision.Rule{ + // ... agentes existentes ... + "": agent.Rules, // ← nuevo +} +``` + +**El ID en rulesRegistry DEBE coincidir exactamente con `agent.id` del config.yaml.** + +### 5. `agents/runtime.go` — Registro de herramientas (solo si hay tools nuevas) + +Si el agente necesita una herramienta nueva (no existente), ver la policy `create_tool.md`. + +Las herramientas "siempre disponibles" (`current_time`, `matrix_send`) ya están registradas para todos los agentes. + +## Después de crear los archivos + +Verificar compilación: +```bash +go build -tags goolm ./... +``` + +Luego seguir con registro, avatar, verificación y arranque (ver `docs/creating-agents.md`). + +## Reglas generales + +- **Nunca** poner side effects en `agent.go` — es código puro +- **Siempre** verificar que `agent.id` coincide entre config.yaml, rulesRegistry y el directorio +- **Siempre** compilar con `-tags goolm` para soporte E2EE +- **Idioma**: español en configs, prompts y descripciones de dominio; inglés en código Go +- **No** crear archivos `data/` — se generan automáticamente al arrancar +- **No** commitear tokens ni passwords — solo van en `.env` +- Si el agente usa tool_use, asegurarse de que `llm.tool_use.enabled: true` en el config +- Usar `agents/asistente2/` como referencia completa de un agente con tools habilitadas diff --git a/.claude/rules/create_tool.md b/.claude/policies/create_tool.md similarity index 100% rename from .claude/rules/create_tool.md rename to .claude/policies/create_tool.md diff --git a/.claude/policies/index.md b/.claude/policies/index.md new file mode 100644 index 0000000..471c8c2 --- /dev/null +++ b/.claude/policies/index.md @@ -0,0 +1,23 @@ +# Políticas del proyecto + +Guías operativas para LLMs que trabajan en este codebase. Cada política describe cómo ejecutar una tarea específica respetando la arquitectura y convenciones del proyecto. + +## Políticas disponibles + +| Política | Archivo | Cuándo aplicarla | +|----------|---------|------------------| +| **Crear agente** | [create_agent.md](create_agent.md) | Al crear un nuevo bot/agente Matrix completo | +| **Crear herramienta** | [create_tool.md](create_tool.md) | Al añadir una nueva tool para LLM function calling | + +## Cuándo consultar las políticas + +- **Crear agente**: cuando el usuario pida crear un nuevo bot, agente, o asistente. Incluye la estructura de archivos, reglas puras, config YAML, system prompt y registro en el launcher. +- **Crear herramienta**: cuando el usuario pida añadir una nueva herramienta/tool al sistema. Incluye el patrón Def (puro) + Exec (impuro), registro en runtime.go y habilitación en config. + +## Principio general + +Todas las políticas respetan el patrón **pure core / impure shell**: +- `pkg/` es puro — nunca añadir side effects +- `shell/` es impuro — todo I/O va aquí +- `agents/` compone ambos — reglas puras + ensamblado con shell +- `tools/` sigue el mismo patrón: `Def` (datos puros) + `Exec` (función impura) diff --git a/.gitignore b/.gitignore index c9d4f72..347aac2 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ run/*.pid run/*.log /agentctl -/dashboard \ No newline at end of file +/dashboard +/verify \ No newline at end of file diff --git a/docs/creating-agents.md b/docs/creating-agents.md new file mode 100644 index 0000000..7bc9a23 --- /dev/null +++ b/docs/creating-agents.md @@ -0,0 +1,322 @@ +# Guía completa: Crear un nuevo agente + +Esta guía documenta todos los pasos para crear, registrar, configurar y poner en marcha un nuevo bot/agente en el sistema. + +## Requisitos previos + +- Go 1.23+ instalado (`/usr/local/go/bin`) +- Acceso al homeserver Matrix (`MATRIX_HOMESERVER` y `MATRIX_ADMIN_TOKEN` en `.env`) +- Variables de entorno cargadas (`.env` con todos los secretos) + +## Paso 1: Crear el scaffold del agente + +### Opción A: Script automático + +```bash +./dev-scripts/new-agent.sh "Display Name" +# Ejemplo: ./dev-scripts/new-agent.sh mi-bot "Mi Bot" +``` + +Esto crea la estructura base en `agents//`. + +### Opción B: Manual + +Crear la estructura de directorios: + +``` +agents// +├── agent.go # Reglas puras de decisión +├── config.yaml # Configuración completa del agente +├── prompts/ +│ └── system.md # System prompt para el LLM +└── data/ # Runtime (auto-generado, en .gitignore) + └── crypto/ # Store E2EE +``` + +### 1.1 Crear `agents//agent.go` + +Archivo de reglas puras. El package debe exportar una función `Rules() []decision.Rule`. + +```go +package mibot + +import ( + "github.com/enmanuel/agents/pkg/decision" +) + +// Rules returns the decision rules for this agent. +func Rules() []decision.Rule { + return []decision.Rule{ + // !help — comando de ayuda explícito + { + Name: "help", + Match: decision.MatchCommand("help"), + Actions: []decision.Action{{ + Kind: decision.ActionKindReply, + Reply: &decision.ReplyAction{ + Content: "Soy mi-bot. Escríbeme lo que necesitas.", + }, + }}, + }, + + // Catch-all: DMs y menciones → LLM + { + Name: "llm-all", + Match: func(ctx decision.MessageContext) bool { + return ctx.IsDirectMsg || ctx.IsMention + }, + Actions: []decision.Action{{ + Kind: decision.ActionKindLLM, + LLM: &decision.LLMAction{}, + }}, + }, + } +} +``` + +**Reglas importantes:** +- Este archivo es **puro** — sin imports de I/O, sin side effects +- Solo usa types de `pkg/decision` +- Las reglas se evalúan en orden; la primera que matchea gana + +### 1.2 Crear `agents//config.yaml` + +Configuración completa del agente. Referencia: `internal/config/schema.go`. + +Secciones principales: + +| Sección | Descripción | +|---------|-------------| +| `agent` | Identidad: id, name, version, enabled, description, tags | +| `personality` | Tono, verbosidad, idioma, templates, comportamiento | +| `llm` | Provider (openai/anthropic), modelo, tokens, temperature, tool_use | +| `tools` | SSH, HTTP, scripts, file_ops, MCP — cada uno con su enabled/config | +| `matrix` | Homeserver, user_id, token, device_id, encryption, rooms, filters | +| `agents` | Peers conocidos, delegación, protocolo inter-agente | +| `ssh` | Configuración SSH (solo si aplica) | +| `security` | Roles, audit, secrets provider | +| `schedules` | Tareas programadas (cron) | +| `observability` | Logging, metrics, health, tracing | +| `resilience` | Circuit breaker, retry, shutdown, queue | +| `storage` | State backend, cache, history | + +**Campos críticos en `matrix`:** + +```yaml +matrix: + homeserver: "https://matrix-af2f3d.organic-machine.com" + user_id: "@:matrix-af2f3d.organic-machine.com" + access_token_env: MATRIX_TOKEN_ # nombre de la env var + device_id: "" + + encryption: + enabled: true + store_path: "./data/crypto/" + trust_mode: tofu +``` + +**Para habilitar tool-use:** + +```yaml +llm: + tool_use: + enabled: true # DEBE ser true + max_iterations: 5 + parallel_calls: false +``` + +### 1.3 Crear `agents//prompts/system.md` + +System prompt que recibe el LLM. Debe incluir: +- Identidad y rol del bot +- Capacidades disponibles +- Herramientas disponibles (si tool_use está habilitado) +- Estilo de respuesta +- Limitaciones + +Usar como referencia: `agents/assistant/prompts/assistant-system.md` o `agents/asistente2/prompts/system.md`. + +## Paso 2: Registrar el agente en el launcher + +Editar `cmd/launcher/main.go`: + +1. Añadir import del package del agente: +```go +mibotAgent "github.com/enmanuel/agents/agents/mibot" +``` + +2. Añadir entrada en `rulesRegistry`: +```go +var rulesRegistry = map[string]func() []decision.Rule{ + "assistant-bot": assistantagent.Rules, + "mi-bot": mibotAgent.Rules, // ← nuevo + "devops-bot": devopsagent.Rules, +} +``` + +**Nota:** El ID aquí debe coincidir exactamente con `agent.id` en el `config.yaml`. + +## Paso 3: Registrar en Matrix + +```bash +./dev-scripts/register.sh "Display Name" +``` + +Este comando: +1. Crea el usuario en Synapse via admin API +2. Genera una contraseña aleatoria +3. Hace login para obtener un access token +4. Guarda `MATRIX_TOKEN_` en `.env` + +**Guardar la contraseña manualmente** — se necesita para la verificación E2EE: + +```bash +# Añadir al .env manualmente si no se guardó: +MATRIX_PASSWORD_= +``` + +**Importante:** El script `register.sh` imprime la password en la salida. Copiarla y guardarla. + +### Actualizar device_id en config.yaml + +El registro crea un `device_id` nuevo. Actualizarlo en `agents//config.yaml`: + +```yaml +matrix: + device_id: "" +``` + +## Paso 4: Configurar avatar y display name + +Colocar la imagen del bot en `static/`: + +```bash +# Subir avatar y sincronizar displayname desde el config +./dev-scripts/avatar.sh static/.jpg +``` + +Esto hace: +1. Sube la imagen al homeserver Matrix (obtiene una URL `mxc://`) +2. Establece el avatar del usuario bot +3. Sincroniza el displayname desde `agent.name` del `config.yaml` + +**Formatos soportados:** JPG, PNG. Recomendado: cuadrado, 256x256 o superior. + +## Paso 5: Verificación E2EE (cross-signing) + +Sin este paso, los mensajes del bot mostrarán: **"Encrypted by a device not verified by its owner"**. + +```bash +go run -tags goolm ./cmd/verify \ + --homeserver "https://matrix-af2f3d.organic-machine.com" \ + --username "" \ + --password "" \ + --token "" \ + --store "./agents//data/crypto/" +``` + +**Qué hace:** +1. Inicializa el crypto helper de mautrix +2. Genera claves de cross-signing (master + self-signing) +3. Las sube al homeserver usando UIA con la password del bot +4. Firma el device del bot con la self-signing key + +**Después de verificar:** Limpiar el crypto store temporal si se usó uno diferente al del agente. + +**Importante:** Si se cambia la password del bot (admin API), el token anterior se invalida. Hay que: +1. Re-login para obtener nuevo token +2. Actualizar `MATRIX_TOKEN_` en `.env` +3. Actualizar `device_id` en `config.yaml` +4. Borrar el crypto store viejo (`data/crypto/`) +5. Re-ejecutar `cmd/verify` + +## Paso 6: Arrancar el agente + +```bash +./dev-scripts/start.sh +``` + +Verificar que arrancó correctamente: + +```bash +# Ver logs +tail -f run/.log + +# Verificar proceso +./dev-scripts/ps.sh + +# Estado general +./dev-scripts/list.sh +``` + +**Logs esperados al arrancar correctamente:** +``` +{"level":"INFO","msg":"initializing e2ee","store":"data/crypto/crypto.db"} +{"level":"INFO","msg":"e2ee ready"} +{"level":"INFO","msg":"agent starting","id":"","tools":["current_time","matrix_send"]} +{"level":"INFO","msg":"starting matrix sync"} +``` + +## Paso 7: Verificar funcionamiento + +1. Abrir Element u otro cliente Matrix +2. Enviar un DM al bot: `@:matrix-af2f3d.organic-machine.com` +3. Verificar que responde +4. Verificar que no aparece el warning de "device not verified" +5. Si tiene tools, probar que las usa (e.g., preguntar la hora) + +## Resumen de comandos (en orden) + +```bash +# 1. Crear scaffold +./dev-scripts/new-agent.sh "Nombre" + +# 2. Editar reglas, config, prompt +# agents//agent.go +# agents//config.yaml +# agents//prompts/system.md + +# 3. Registrar en launcher +# Editar cmd/launcher/main.go → import + rulesRegistry + +# 4. Registrar en Matrix +./dev-scripts/register.sh "Nombre" + +# 5. Avatar y displayname +./dev-scripts/avatar.sh static/.jpg + +# 6. Verificación E2EE +go run -tags goolm ./cmd/verify \ + --homeserver "$MATRIX_HOMESERVER" \ + --username "" \ + --password "$MATRIX_PASSWORD_" \ + --token "$MATRIX_TOKEN_" + +# 7. Arrancar +./dev-scripts/start.sh + +# 8. Verificar +tail -f run/.log +``` + +## Troubleshooting + +| Problema | Causa | Solución | +|----------|-------|----------| +| `env var ... is not set` | La regex del `.env` loader no matchea | Verificar que el nombre de la var solo usa `[A-Z0-9_]` | +| `M_UNKNOWN_TOKEN` | Token invalidado (password cambiada) | Re-login, actualizar `.env` | +| `mismatching device ID` | Crypto store con device viejo | Borrar `data/crypto/`, actualizar `device_id` en config | +| `"Encrypted by device not verified"` | Falta cross-signing | Ejecutar `cmd/verify` | +| Bot no responde | Reglas no matchean | Verificar que hay regla catch-all para DMs/mentions | +| `no rules registered for agent` | ID no está en `rulesRegistry` | Añadir en `cmd/launcher/main.go` | +| Bot muere al arrancar | Revisar logs | `tail -f run/.log` | + +## Compilación + +Siempre usar la tag `goolm` para soporte E2EE puro (sin CGO): + +```bash +go build -tags goolm ./cmd/launcher +go build -tags goolm ./cmd/verify +go run -tags goolm ./cmd/verify --help +```