# Policy: Crear un nuevo agente o robot Guia ejecutable para Claude. Seguir paso a paso sin desviarse. ## Robot vs Agent — decidir primero | | Agent | Robot | |---|---|---| | **Cuando usar** | Necesita LLM, reglas, memoria, tools | Solo responde comandos (!xxx) | | **Runtime** | `devagents.New()` — completo | `devagents.NewRobot()` — ligero | | **Config type** | `type: agent` (default) | `type: robot` | | **LLM** | Si | No | | **Reglas** | Si (`agent.go` con `Rules()`) | No (sin `agent.go`) | | **Memoria/Knowledge/Skills** | Si (opcionales) | No | | **Tools** | Si (opcionales) | No | | **System prompt** | Si (`prompts/system.md`) | No necesario | | **Comandos built-in** | help, ping, tools, tool, status, info, clear, prompts, version | help, ping, status, info, version | | **Comandos custom** | Si (`RegisterCommand`) | Si (`RegisterCommand`) | | **Template** | `agents/_template/` | `agents/_template_robot/` | | **Config ejemplo** | ~260 lineas | ~55 lineas | **Regla**: si el bot necesita entender lenguaje natural, es un Agent. Si solo necesita comandos directos, es un Robot. ## Inputs — preguntar al usuario si no los da | Input | Requerido | Default | Ejemplo | |-------|-----------|---------|---------| | `agent-id` | si | — | `monitor-bot` | | `display-name` | si | — | `"Monitor Agent"` | | `description` | si | — | `"Monitorea servicios y reporta estado"` | | `type` | no | `agent` | `agent` o `robot` | | `llm.provider` | no (N/A para robots) | `openai` | `openai` o `anthropic` | | `llm.model` | no (N/A para robots) | `gpt-4o` | `gpt-4o`, `claude-sonnet-4-20250514` | | `tool_use` | no (N/A para robots) | `false` | `true` si necesita herramientas | | System prompt | si (N/A para robots) | — | Texto describiendo rol y capacidades | Si el usuario da todos los inputs, ir directo a la Ruta Rapida. Si faltan, preguntar antes de empezar. ## Ruta rápida — script automatizado ```bash ./dev-scripts/agent/create-full.sh "Display Name" ``` Este script ejecuta en orden: scaffold → build → register Matrix → verify E2EE. Crea todos los archivos, registra en el launcher, genera todas las env vars en `.env`. Después del script, personalizar los 3 archivos del agente (ver sección siguiente). ## Archivos a personalizar después del scaffold ### 1. `agents//agent.go` — Reglas puras Template base (generado por el scaffold): ```go package // sin guiones: "monitor-bot" → package monitor (strip hyphens, strip _bot) import ( "github.com/enmanuel/agents/devagents" "github.com/enmanuel/agents/pkg/decision" ) func init() { devdevagents.Register("", Rules) } func Rules() []decision.Rule { return []decision.Rule{ // Any DM or mention → 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 estrictas:** - **PURO**: solo imports de `pkg/decision` y `agents` (para Register), cero I/O, cero side effects - **Auto-registro**: cada agente se registra via `init()` con `devagents.Register("", Rules)` - Package name = ID sin guiones ni `_bot` (e.g. `monitor-bot` → `package monitor`) - **No usar reglas para comandos** (`!help`, `!ping`, etc.) — los comandos se gestionan via `RegisterCommand` (ver policy `create_command.md`) - Las reglas solo aplican a mensajes normales (sin prefijo `!`) Tipos de acción disponibles: - `ActionKindReply` — respuesta estática (con `ReplyAction{Content: "..."}`) - `ActionKindLLM` — pasa al LLM (con `LLMAction{}`) ### 2. `agents//config.yaml` — Configuración El scaffold genera un config completo con defaults sensatos. Solo personalizar estas secciones: **Identidad** (siempre editar): ```yaml agent: description: "" ``` **LLM** (si quieres cambiar provider/model): ```yaml llm: primary: provider: anthropic # o openai (default) model: claude-sonnet-4-20250514 # o gpt-4o (default) api_key_env: ANTHROPIC_API_KEY # o OPENAI_API_KEY (default) ``` **Claude-code provider** (si usa `claude-code` como provider): ```yaml llm: primary: provider: claude-code claude_code: working_dir: "/tmp/claude-agents/" # SIEMPRE configurar, nunca dejar vacío permission_mode: "bypassPermissions" ``` **Importante**: `working_dir` debe apuntar fuera del repositorio para evitar que el subproceso `claude -p` acceda al código fuente. Si se deja vacío, se usará un directorio temporal (con WARN en logs). **Tool use** (si el agente necesita herramientas): ```yaml llm: tool_use: enabled: true # cambiar de false a true max_iterations: 5 ``` **Personalidad** (ajustar tono): ```yaml personality: tone: friendly # friendly | professional | casual | technical language: es # es | en prefix: "🤖" # emoji del bot ``` **Threads** (habilitado por defecto en el scaffold): ```yaml matrix: threads: enabled: true # responder en threads cuando el mensaje viene de un thread auto_thread: false # true para crear thread automático por cada conversación nueva ``` Referencia completa del schema: `internal/config/schema.go` ### 3. `agents//prompts/system.md` — System prompt Escribir el system prompt completo. Debe incluir: - **Identidad**: quién es, cómo se llama - **Rol**: qué hace, para qué sirve - **Capacidades**: qué puede hacer (incluir tools si `tool_use.enabled: true`) - **Estilo**: idioma, tono, formato de respuestas - **Restricciones**: qué NO debe hacer - **Seguridad** (obligatorio): copiar la seccion de `.claude/templates/security-prompt.md` al final del prompt. Esta seccion protege contra prompt injection. Ejemplo de referencia: `agents/asistente-2/prompts/system.md` ## Registro en el launcher — `cmd/launcher/main.go` El script `new-agent.sh` (ejecutado por `create-full.sh`) hace esto automáticamente. Si falla, hacer manualmente: **Blank import** (en la sección de blank imports de agentes): ```go _ "github.com/enmanuel/agents/agents/" ``` Las reglas se registran automáticamente via `init()` en el paquete del agente. No se necesita editar ningún map ni registry manualmente. **El ID en `devagents.Register()` DEBE coincidir exactamente con `agent.id` en config.yaml.** ## Convención de env vars — REGLA CRÍTICA Normalización: `normalize_id()` → mayúsculas, guiones → underscores. **Sin eliminar sufijos.** | Agent ID | Normalizado | Env vars | |---|---|---| | `assistant-bot` | `ASSISTANT_BOT` | `MATRIX_TOKEN_ASSISTANT_BOT`, `MATRIX_PASSWORD_ASSISTANT_BOT`, `PICKLE_KEY_ASSISTANT_BOT`, `SSSS_RECOVERY_KEY_ASSISTANT_BOT` | | `mi-bot` | `MI_BOT` | `MATRIX_TOKEN_MI_BOT`, ... | **NUNCA** aplicar transformaciones que eliminen partes del ID (no `sed 's/_BOT$//'`). ## Verificación post-creación Checklist a verificar antes de considerar el agente listo: - [ ] `go build -tags goolm ./...` compila sin errores - [ ] `agents//agent.go` exporta `Rules()` y es puro (sin I/O) - [ ] `agents//config.yaml` tiene `agent.id` = nombre del directorio - [ ] `cmd/launcher/main.go` tiene blank import del paquete del agente - [ ] `.env` contiene: `MATRIX_TOKEN_`, `MATRIX_PASSWORD_`, `PICKLE_KEY_`, `SSSS_RECOVERY_KEY_` - [ ] `prompts/system.md` tiene contenido real (no el stub) - [ ] `prompts/system.md` incluye la seccion de seguridad anti-injection (de `.claude/templates/security-prompt.md`) - [ ] Si `tool_use.enabled: true`, el prompt menciona las tools disponibles ## Arranque y verificación ```bash # Arrancar (reconstruye y lanza todos los agentes habilitados) ./dev-scripts/server/start.sh # Verificar logs tail -f run/launcher.log # Logs esperados al arrancar correctamente: # {"level":"INFO","msg":"e2ee ready"} # {"level":"INFO","msg":"agent running"} # {"level":"INFO","msg":"starting matrix sync"} ``` ## Troubleshooting E2EE | Problema | Solución | |----------|----------| | "device not verified by its owner" | `./dev-scripts/agent/verify.sh ` y reiniciar | | "self-signing private key not in cache" | Recovery key incorrecta → re-ejecutar verify.sh | | "received update for device with different signing key" | Recompilar launcher: `go build -tags goolm -o bin/launcher ./cmd/launcher` | | Recovery key sin comillas en .env | Añadir comillas: `SSSS_RECOVERY_KEY_*="EsXX YYYY ..."` | ## Reglas generales - **Nunca** side effects en `agent.go` - **Siempre** compilar con `-tags goolm` - **Siempre** que `agent.id` coincida entre config.yaml, `devagents.Register()` y directorio - **No** crear `data/` manualmente — se auto-genera - **No** commitear tokens ni passwords - **No** compartir crypto stores entre agentes - Referencia de agente con tools: `agents/asistente-2/` - Referencia de agente simple: `agents/assistant-bot/`