refactor: migrar policies/ a rules/ y añadir create_issue
Se renombra .claude/policies/ a .claude/rules/ para usar terminología más clara y consistente. Se añade la nueva regla create_issue.md con guía completa para crear issues en dev/issues/, incluyendo el template en .claude/templates/issue.md. El índice (index.md) se actualiza con la nueva regla. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
# Policy: Crear un nuevo agente
|
||||
|
||||
Guía ejecutable para Claude. Seguir paso a paso sin desviarse.
|
||||
|
||||
## Inputs — preguntar al usuario si no los da
|
||||
|
||||
| Input | Requerido | Default | Ejemplo |
|
||||
|-------|-----------|---------|---------|
|
||||
| `agent-id` | sí | — | `monitor-bot` |
|
||||
| `display-name` | sí | — | `"Monitor Agent"` |
|
||||
| `description` | sí | — | `"Monitorea servicios y reporta estado"` |
|
||||
| `llm.provider` | no | `openai` | `openai` o `anthropic` |
|
||||
| `llm.model` | no | `gpt-4o` | `gpt-4o`, `claude-sonnet-4-20250514` |
|
||||
| `tool_use` | no | `false` | `true` si necesita herramientas |
|
||||
| System prompt | sí | — | Texto describiendo rol y capacidades |
|
||||
|
||||
Si el usuario da todos los inputs, ir directo a la Ruta Rápida. Si faltan, preguntar antes de empezar.
|
||||
|
||||
## Ruta rápida — script automatizado
|
||||
|
||||
```bash
|
||||
./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):
|
||||
|
||||
```go
|
||||
package <pkgname> // sin guiones: "monitor-bot" → package monitor (strip hyphens, strip _bot)
|
||||
|
||||
import "github.com/enmanuel/agents/pkg/decision"
|
||||
|
||||
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`, cero I/O, cero side effects
|
||||
- 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/<agent-id>/config.yaml` — Configuración
|
||||
|
||||
El scaffold genera un config completo con defaults sensatos. Solo personalizar estas secciones:
|
||||
|
||||
**Identidad** (siempre editar):
|
||||
```yaml
|
||||
agent:
|
||||
description: "<la descripción del agente>"
|
||||
```
|
||||
|
||||
**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)
|
||||
```
|
||||
|
||||
**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
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
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:
|
||||
|
||||
**Import** (después de los imports de agentes existentes):
|
||||
```go
|
||||
<pkg>agent "github.com/enmanuel/agents/agents/<agent-id>"
|
||||
```
|
||||
|
||||
**rulesRegistry** (dentro del map):
|
||||
```go
|
||||
"<agent-id>": <pkg>agent.Rules,
|
||||
```
|
||||
|
||||
El `<pkg>` es el package name del agent.go (sin guiones, sin `_bot`).
|
||||
**El ID en rulesRegistry 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/<id>/agent.go` exporta `Rules()` y es puro (sin I/O)
|
||||
- [ ] `agents/<id>/config.yaml` tiene `agent.id` = nombre del directorio
|
||||
- [ ] `cmd/launcher/main.go` tiene import + entry en rulesRegistry con el mismo ID
|
||||
- [ ] `.env` contiene: `MATRIX_TOKEN_<NORM>`, `MATRIX_PASSWORD_<NORM>`, `PICKLE_KEY_<NORM>`, `SSSS_RECOVERY_KEY_<NORM>`
|
||||
- [ ] `prompts/system.md` tiene contenido real (no el stub)
|
||||
- [ ] 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 <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.id` coincida entre config.yaml, rulesRegistry 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/`
|
||||
@@ -0,0 +1,149 @@
|
||||
# Policy: Crear un comando para un agente
|
||||
|
||||
Los comandos (`!xxx`) son respuestas directas que no pasan por reglas ni por el LLM.
|
||||
Siempre se resuelven primero en el flujo de eventos.
|
||||
|
||||
## Arquitectura del sistema de comandos
|
||||
|
||||
```
|
||||
Usuario envía "!help"
|
||||
→ listener.go parsea → msgCtx.Command = "help"
|
||||
→ runtime.go handleEvent:
|
||||
1. Busca en built-in commands (help, ping, tools, etc.) → match → responde → FIN
|
||||
2. Si no match → "Comando desconocido" → FIN
|
||||
(Nunca llega a reglas ni LLM)
|
||||
|
||||
Usuario envía "hola"
|
||||
→ Command == "" → reglas → LLM → respuesta normal
|
||||
```
|
||||
|
||||
## Tipos de comandos
|
||||
|
||||
### Built-in (todos los agentes)
|
||||
|
||||
Definidos en `pkg/command/builtins.go` (specs puras) y `agents/commands.go` (handlers).
|
||||
Todos los agentes los tienen automáticamente: `!help`, `!ping`, `!tools`, `!tool`, `!status`, `!info`, `!clear`, `!version`.
|
||||
|
||||
**No modificar los built-in para agregar funcionalidad por agente.** Usar `RegisterCommand` en su lugar.
|
||||
|
||||
### Agent-specific (por agente)
|
||||
|
||||
Se registran con `agent.RegisterCommand(spec, handler)` en el launcher, después de `agents.New()` y antes de `agent.Run()`.
|
||||
|
||||
## Pasos para crear un comando de agente
|
||||
|
||||
### 1. Definir el handler en el paquete del agente
|
||||
|
||||
Crear un archivo `commands.go` en `agents/<agent-id>/`:
|
||||
|
||||
```go
|
||||
package <pkgname>
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/enmanuel/agents/pkg/command"
|
||||
"github.com/enmanuel/agents/pkg/decision"
|
||||
)
|
||||
|
||||
// Commands returns the command specs and handlers for this agent.
|
||||
// Handlers are functions, but must NOT do I/O directly — they receive
|
||||
// dependencies via closure when registered in the launcher.
|
||||
func Commands() []CommandEntry {
|
||||
return []CommandEntry{
|
||||
{
|
||||
Spec: command.Spec{
|
||||
Name: "deploy",
|
||||
Aliases: []string{"d"},
|
||||
Description: "Despliega al entorno indicado",
|
||||
Usage: "!deploy <env>",
|
||||
},
|
||||
Handler: func(ctx context.Context, msgCtx decision.MessageContext) string {
|
||||
if len(msgCtx.Args) < 2 {
|
||||
return "Uso: !deploy <env>"
|
||||
}
|
||||
env := msgCtx.Args[1]
|
||||
return fmt.Sprintf("Desplegando a %s...", env)
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// CommandEntry pairs a spec with its handler.
|
||||
type CommandEntry struct {
|
||||
Spec command.Spec
|
||||
Handler func(ctx context.Context, msgCtx decision.MessageContext) string
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Registrar en el launcher (`cmd/launcher/main.go`)
|
||||
|
||||
Después de `agents.New()` y antes de `wg.Add(1)`:
|
||||
|
||||
```go
|
||||
a, err := agents.New(cfg, rules, agentLogger)
|
||||
if err != nil { ... }
|
||||
|
||||
// Register agent-specific commands
|
||||
if cfg.Agent.ID == "<agent-id>" {
|
||||
for _, cmd := range <pkg>agent.Commands() {
|
||||
a.RegisterCommand(cmd.Spec, cmd.Handler)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Documentar en el system prompt
|
||||
|
||||
Si el agente tiene LLM, mencionar los comandos en `prompts/system.md` para que el LLM pueda informar al usuario:
|
||||
|
||||
```markdown
|
||||
## Comandos disponibles
|
||||
- `!deploy <env>` — Despliega al entorno indicado
|
||||
- `!help` — Lista todos los comandos
|
||||
```
|
||||
|
||||
## API de registro
|
||||
|
||||
```go
|
||||
// En agents/runtime.go
|
||||
func (a *Agent) RegisterCommand(spec command.Spec, handler CommandHandler)
|
||||
```
|
||||
|
||||
- `spec.Name`: nombre del comando (lo que va después de `!`)
|
||||
- `spec.Aliases`: nombres cortos alternativos (opcional)
|
||||
- `spec.Description`: texto que aparece en `!help`
|
||||
- `spec.Usage`: ejemplo de uso que aparece en `!help`
|
||||
- `spec.Hidden`: si es `true`, no aparece en `!help`
|
||||
- `handler`: recibe `(ctx, msgCtx)` y devuelve un string
|
||||
|
||||
El handler tiene acceso a:
|
||||
- `msgCtx.Args` — argumentos parseados por `strings.Fields` (incluye el nombre del comando en `Args[0]` solo si viene de `!tool xxx`)
|
||||
- `msgCtx.Command` — nombre del comando (ya sin `!`)
|
||||
- `msgCtx.SenderID`, `msgCtx.RoomID`, `msgCtx.IsDirectMsg`, etc.
|
||||
|
||||
## Prioridad de resolución
|
||||
|
||||
```
|
||||
1. Built-in commands (help, ping, tools, etc.) ← siempre ganan
|
||||
2. Agent-specific commands (RegisterCommand) ← segundo
|
||||
3. Si no hay match → "Comando desconocido" ← nunca llega al LLM
|
||||
```
|
||||
|
||||
Un agent-specific command **no puede** sobrescribir un built-in. Si se registra un comando con el mismo nombre que un built-in, el built-in prevalece.
|
||||
|
||||
## Reglas
|
||||
|
||||
- **No usar reglas (`agent.go`) para comandos.** Las reglas son para lógica de decisión sobre mensajes normales.
|
||||
- **Los handlers pueden ser impuros** (HTTP, SSH, etc.) — se ejecutan en el contexto del runtime.
|
||||
- **Respuesta siempre es string** — el runtime lo envía por Matrix automáticamente.
|
||||
- **Validar argumentos** al inicio del handler y devolver usage si faltan.
|
||||
- **Logs automáticos** — el runtime loguea `command_received` y `command_executed` a nivel INFO.
|
||||
- **`msgCtx.Args`** para `!deploy prod` contiene `["prod"]` (sin el nombre del comando).
|
||||
|
||||
## Verificación
|
||||
|
||||
- [ ] `go build -tags goolm ./...` compila
|
||||
- [ ] `!help` muestra el comando nuevo en la sección "Comandos del agente"
|
||||
- [ ] Enviar el comando por Matrix produce la respuesta esperada
|
||||
- [ ] En logs aparece `command_received` y `command_executed`
|
||||
@@ -0,0 +1,63 @@
|
||||
# Regla: Crear un nuevo issue
|
||||
|
||||
Guia para crear issues de features, mejoras o bugs en `dev/issues/`.
|
||||
|
||||
## Inputs — preguntar al usuario si no los da
|
||||
|
||||
| Input | Requerido | Ejemplo |
|
||||
|-------|-----------|---------|
|
||||
| Titulo | si | "Hot reload de configuracion" |
|
||||
| Descripcion/objetivo | si | "Recargar config sin reiniciar el agente" |
|
||||
| Dependencias | no | "Requiere issue 010" |
|
||||
|
||||
## Pasos
|
||||
|
||||
### 1. Determinar el numero del issue
|
||||
|
||||
Buscar el numero mas alto en `dev/issues/` y usar el siguiente. Formato: 3 digitos con ceros a la izquierda (`019`, `020`, etc.).
|
||||
|
||||
### 2. Crear el archivo desde el template
|
||||
|
||||
Copiar `.claude/templates/issue.md` a `dev/issues/<NNN>-<slug>.md`.
|
||||
|
||||
El slug debe ser:
|
||||
- Lowercase
|
||||
- Palabras separadas por guiones
|
||||
- Conciso (2-4 palabras)
|
||||
- Ejemplo: `019-hot-reload.md`
|
||||
|
||||
### 3. Rellenar el template
|
||||
|
||||
Completar todas las secciones del template:
|
||||
|
||||
- **Objetivo**: 1-3 frases claras de que se quiere lograr
|
||||
- **Contexto**: que existe, que falta, dependencias
|
||||
- **Arquitectura**: archivos afectados, marcar `NEW` los nuevos. Incluir como se respeta pure core / impure shell
|
||||
- **Tareas**: desglosar en fases con tareas numeradas (`1.1`, `1.2`, etc.). Cada tarea debe ser concreta y verificable. Incluir siempre una fase de tests y una de cleanup/docs
|
||||
- **Ejemplo de uso**: flujo concreto mostrando la feature funcionando
|
||||
- **Decisiones de diseno**: justificar las decisiones clave
|
||||
- **Prerequisitos**: que debe estar implementado antes
|
||||
- **Riesgos**: problemas potenciales y mitigacion
|
||||
|
||||
### 4. Actualizar el indice
|
||||
|
||||
Agregar una fila al final de la tabla en `dev/issues/README.md`:
|
||||
|
||||
```markdown
|
||||
| <N> | <Titulo> | [<NNN>-<slug>.md](<NNN>-<slug>.md) | pendiente |
|
||||
```
|
||||
|
||||
## Reglas
|
||||
|
||||
- **Patron pure core / impure shell**: toda feature debe explicar que va en `pkg/` (puro) vs `shell/` (impuro).
|
||||
- **Tareas atomicas**: cada tarea debe ser implementable de forma independiente.
|
||||
- **Numeracion continua**: nunca reusar numeros de issues eliminados.
|
||||
- **Estado**: los issues nuevos siempre empiezan como `pendiente`.
|
||||
- **Completados**: cuando se termine un issue, moverlo a `dev/issues/completed/` y actualizar el README.
|
||||
|
||||
## Verificacion
|
||||
|
||||
- [ ] Archivo creado en `dev/issues/<NNN>-<slug>.md`
|
||||
- [ ] Todas las secciones del template rellenadas
|
||||
- [ ] Fila agregada en `dev/issues/README.md`
|
||||
- [ ] Numero de issue es consecutivo (no hay saltos ni duplicados)
|
||||
@@ -0,0 +1,66 @@
|
||||
# Cómo crear una nueva herramienta (tool)
|
||||
|
||||
Las herramientas viven en `tools/` y siguen el patrón **spec puro + función impura**.
|
||||
|
||||
## Pasos
|
||||
|
||||
### 1. Crear el archivo `tools/<nombre>.go`
|
||||
|
||||
```go
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// NewMiTool creates a mi_tool tool that does X.
|
||||
// Accepts dependencies needed for execution (configs, clients, etc).
|
||||
func NewMiTool(/* deps */) Tool {
|
||||
return Tool{
|
||||
Def: Def{
|
||||
Name: "mi_tool",
|
||||
Description: "Description clara de qué hace la herramienta para el LLM.",
|
||||
Parameters: []Param{
|
||||
{Name: "param1", Type: "string", Description: "What this param is", Required: true},
|
||||
{Name: "param2", Type: "number", Description: "Optional param", Required: false},
|
||||
},
|
||||
},
|
||||
Exec: func(ctx context.Context, args map[string]any) Result {
|
||||
p1 := getString(args, "param1")
|
||||
if p1 == "" {
|
||||
return Result{Err: fmt.Errorf("mi_tool: param1 is required")}
|
||||
}
|
||||
|
||||
// Execute the actual work here (impure)
|
||||
output := doSomething(p1)
|
||||
|
||||
return Result{Output: output}
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Registrar en `agents/runtime.go` → `buildToolRegistry()`
|
||||
|
||||
```go
|
||||
if /* condición basada en config */ {
|
||||
reg.Register(tools.NewMiTool(/* deps */))
|
||||
logger.Debug("registered mi_tool")
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Habilitar en el config del agente (`agents/<id>/config.yaml`)
|
||||
|
||||
Asegurarse de que `llm.tool_use.enabled: true` y la sección relevante de `tools:` esté habilitada.
|
||||
|
||||
## Reglas
|
||||
|
||||
- **Def es PURO**: solo datos (nombre, descripción, parámetros). Sin side effects.
|
||||
- **Exec es IMPURO**: hace I/O real. Recibe `context.Context` y `map[string]any`.
|
||||
- **Validar inputs**: siempre validar parámetros requeridos al inicio del Exec.
|
||||
- **Validar permisos**: usar los campos del config (AllowedDomains, AllowedPaths, etc.) para restringir acceso.
|
||||
- **Limitar output**: truncar a 64 KB máximo para no saturar el contexto del LLM.
|
||||
- **Usar `getString()`**: helper del package para extraer strings de args de forma segura.
|
||||
- **Param types válidos**: "string", "number", "integer", "boolean", "object", "array" (JSON Schema types).
|
||||
- **Descripción clara**: el LLM decide cuándo usar la tool basándose en el Description del Def.
|
||||
@@ -0,0 +1,27 @@
|
||||
# Reglas del proyecto
|
||||
|
||||
Guias operativas para LLMs que trabajan en este codebase. Cada regla describe como ejecutar una tarea especifica respetando la arquitectura y convenciones del proyecto.
|
||||
|
||||
## Reglas disponibles
|
||||
|
||||
| Regla | Archivo | Cuando 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 |
|
||||
| **Crear comando** | [create_command.md](create_command.md) | Al añadir un comando directo (!xxx) a un agente |
|
||||
| **Crear issue** | [create_issue.md](create_issue.md) | Al crear un nuevo issue/feature request en `dev/issues/` |
|
||||
|
||||
## Cuando consultar las reglas
|
||||
|
||||
- **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 patron Def (puro) + Exec (impuro), registro en runtime.go y habilitacion en config.
|
||||
- **Crear comando**: cuando el usuario pida añadir un comando directo (!xxx) a un agente. Los comandos se resuelven sin pasar por reglas ni LLM.
|
||||
- **Crear issue**: cuando el usuario pida crear un nuevo issue, feature request o task. Usa el template en `.claude/templates/issue.md`.
|
||||
|
||||
## Principio general
|
||||
|
||||
Todas las reglas respetan el patron **pure core / impure shell**:
|
||||
- `pkg/` es puro — nunca añadir side effects
|
||||
- `shell/` es impuro — todo I/O va aqui
|
||||
- `agents/` compone ambos — reglas puras + ensamblado con shell
|
||||
- `tools/` sigue el mismo patron: `Def` (datos puros) + `Exec` (funcion impura)
|
||||
Reference in New Issue
Block a user