agents/ ahora solo contiene carpetas de agentes (config, reglas, prompts). El runtime (Agent, Robot, Runner, registry, handler, commands, llm, memory) vive en devagents/ como package devagents. Cambios: - git mv agents/*.go → devagents/*.go - package agents → package devagents en todos los archivos movidos - Actualizar imports en agents/*/agent.go, cmd/launcher/, dev-scripts/ - Actualizar docs: CLAUDE.md, rules/, docs/e2ee.md, issues pendientes Build y tests pasan sin errores. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
8.9 KiB
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
./dev-scripts/agent/create-full.sh <agent-id> "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-id>/agent.go — Reglas puras
Template base (generado por el scaffold):
package <pkgname> // 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("<agent-id>", 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/decisionyagents(para Register), cero I/O, cero side effects - Auto-registro: cada agente se registra via
init()condevagents.Register("<agent-id>", 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 viaRegisterCommand(ver policycreate_command.md) - Las reglas solo aplican a mensajes normales (sin prefijo
!)
Tipos de acción disponibles:
ActionKindReply— respuesta estática (conReplyAction{Content: "..."})ActionKindLLM— pasa al LLM (conLLMAction{})
2. agents/<agent-id>/config.yaml — Configuración
El scaffold genera un config completo con defaults sensatos. Solo personalizar estas secciones:
Identidad (siempre editar):
agent:
description: "<la descripción del agente>"
LLM (si quieres cambiar provider/model):
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):
llm:
primary:
provider: claude-code
claude_code:
working_dir: "/tmp/claude-agents/<agent-id>" # 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):
llm:
tool_use:
enabled: true # cambiar de false a true
max_iterations: 5
Personalidad (ajustar tono):
personality:
tone: friendly # friendly | professional | casual | technical
language: es # es | en
prefix: "🤖" # emoji del bot
Threads (habilitado por defecto en el scaffold):
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/<agent-id>/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.mdal 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):
_ "github.com/enmanuel/agents/agents/<agent-id>"
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 erroresagents/<id>/agent.goexportaRules()y es puro (sin I/O)agents/<id>/config.yamltieneagent.id= nombre del directoriocmd/launcher/main.gotiene blank import del paquete del agente.envcontiene:MATRIX_TOKEN_<NORM>,MATRIX_PASSWORD_<NORM>,PICKLE_KEY_<NORM>,SSSS_RECOVERY_KEY_<NORM>prompts/system.mdtiene contenido real (no el stub)prompts/system.mdincluye 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
# 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 <id> 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.idcoincida 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/