Files
agents_and_robots/.claude/policies/create_agent.md
T
egutierrez df714c44dd docs: update references after agent directory rename and devops removal
Actualizar todas las referencias en documentación para reflejar los
nuevos nombres de directorio (assistant-bot, asistente-2) y la
eliminación del agente devops-bot. Archivos actualizados: CLAUDE.md,
create_agent.md, README.md, e2ee.md, creating-agents.md,
03-bot-interaction.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 00:55:20 +00:00

8.6 KiB

Cómo crear un nuevo agente

Guía para LLMs que asisten en la creación de agentes en este proyecto.

Flujo completo automatizado

# 1. Scaffold — crea config.yaml (E2EE habilitado), agent.go, prompts/, data/
./dev-scripts/new-agent.sh <agent-id> "Display Name"

# 2. Registrar en Matrix — genera y guarda en .env:
#    MATRIX_TOKEN_<NORM>, MATRIX_PASSWORD_<NORM>, PICKLE_KEY_<NORM>
./dev-scripts/register.sh <agent-id> "Display Name"

# 3. Verificar E2EE — genera cross-signing keys, firma el device,
#    guarda SSSS_RECOVERY_KEY_<NORM> en .env
./dev-scripts/verify.sh <agent-id>

# 4. Arrancar — ya verificado desde el primer arranque
./dev-scripts/start.sh <agent-id>

Los scripts automatizan todo. Solo intervenir manualmente si un paso falla.

Convención de nombres de env vars — REGLA CRÍTICA

Normalización: agent ID → mayúsculas, guiones → underscores. Sin eliminar sufijos.

Función canónica en dev-scripts/_common.sh:

normalize_id() { echo "$1" | tr '[:lower:]-' '[:upper:]_'; }
Agent ID Sufijo normalizado Env vars
assistant-bot ASSISTANT_BOT MATRIX_TOKEN_ASSISTANT_BOT, MATRIX_PASSWORD_ASSISTANT_BOT, PICKLE_KEY_ASSISTANT_BOT, SSSS_RECOVERY_KEY_ASSISTANT_BOT
asistente-2 ASISTENTE_2 MATRIX_TOKEN_ASISTENTE_2, MATRIX_PASSWORD_ASISTENTE_2, PICKLE_KEY_ASISTENTE_2, SSSS_RECOVERY_KEY_ASISTENTE_2
monitor-bot MONITOR_BOT MATRIX_TOKEN_MONITOR_BOT, ...

NUNCA usar sed 's/_BOT$//' ni transformaciones que eliminen partes del ID.

Estructura requerida

Cada agente vive en agents/<agent-id>/ con esta estructura:

agents/<agent-id>/
├── agent.go                # Package propio, exporta Rules() []decision.Rule
├── config.yaml             # Configuración completa (ver schema en internal/config/schema.go)
├── data/                   # Runtime data (crypto, logs) — en .gitignore
│   └── crypto/             # Crypto store E2EE — NUNCA compartir entre agentes
└── prompts/
    └── system.md           # System prompt del LLM

Archivos a crear

1. agents/<agent-id>/agent.go — Reglas puras

package <agentpkg>

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/<agent-id>/config.yaml — Configuración

new-agent.sh genera esto automáticamente. Campos que hay que personalizar:

agent:
  id: <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: "@<agent-id>:matrix-af2f3d.organic-machine.com"
  access_token_env: MATRIX_TOKEN_<NORM>
  device_id: ""                     # se resuelve automáticamente via whoami

Sección E2EE en config.yaml (generada por new-agent.sh)

  encryption:
    enabled: true                                    # SIEMPRE true para agentes nuevos
    store_path: "./agents/<agent-id>/data/crypto/"   # SIEMPRE por agente, nunca compartida
    pickle_key_env: PICKLE_KEY_<NORM>                # generada por register.sh
    trust_mode: tofu
    recovery_key_env: SSSS_RECOVERY_KEY_<NORM>       # generada por verify.sh

3. agents/<agent-id>/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

new-agent.sh hace esto automáticamente. Dos cambios:

Import:

<agentpkg>agent "github.com/enmanuel/agents/agents/<agent-id>"

rulesRegistry:

var rulesRegistry = map[string]func() []decision.Rule{
    // ... agentes existentes ...
    "<agent-id>": <agentpkg>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.

E2EE — Cómo funciona la verificación

Flujo al arrancar (agents/runtime.go)

InitCrypto         → crea/carga el device y Olm account del crypto store
FetchCrossSigningKeys → obtiene private keys de SSSS usando recovery key
SignOwnDevice      → fetch device keys del servidor + firma con self-signing key

Qué hace cada script

Script Qué genera Dónde se guarda
register.sh Token, password, pickle key (32 bytes hex) .env
verify.sh Cross-signing keys (master, self-signing, user-signing) + recovery key Server (keys) + .env (recovery key)

Por qué cada credential importa

Credential Para qué Si falta
MATRIX_TOKEN_* Autenticación del bot con el homeserver Bot no arranca
MATRIX_PASSWORD_* UIA al subir cross-signing keys (verify.sh) verify.sh intenta dummy auth (MSC3967)
PICKLE_KEY_* Cifrar el crypto store en disco Usa sha256(token) como fallback — inseguro
SSSS_RECOVERY_KEY_* Recuperar private keys de cross-signing al arrancar Device no se firma → "not verified by its owner"

Problemas comunes y soluciones

"Encrypted by a device not verified by its owner" → Ejecutar ./dev-scripts/verify.sh <agent-id> y reiniciar

"self-signing private key not in cache" → La recovery key en .env no corresponde a las cross-signing keys actuales. Re-ejecutar verify.sh.

"received update for device with different signing key" → Bug resuelto: SignOwnDevice ahora hace FetchKeys antes de firmar. Si reaparece, recompilar el launcher: go build -tags goolm -o bin/launcher ./cmd/launcher

"data is not encrypted for given key ID" → Las cross-signing keys fueron regeneradas pero la recovery key en .env es la vieja. Re-ejecutar verify.sh (actualiza .env automáticamente).

Recovery key sin comillas en .env → Causan command not found al hacer source .env. Las recovery keys tienen espacios y DEBEN ir entre comillas: SSSS_RECOVERY_KEY_*="EsXX YYYY ZZZZ ..."

Después de crear los archivos

Verificar compilación:

go build -tags goolm ./...

Luego seguir con registro, verificación y arranque usando los dev-scripts.

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
  • Siempre usar normalize_id() de _common.sh para nombres de env vars
  • 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
  • No compartir crypto stores entre agentes — cada uno tiene su store_path
  • Si el agente usa tool_use, asegurarse de que llm.tool_use.enabled: true en el config
  • Usar agents/asistente-2/ como referencia completa de un agente con tools habilitadas