hermes-agent/CONTRIBUTING.es.md

602 lines
29 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Contribuir a Hermes Agent
¡Gracias por contribuir a Hermes Agent! Esta guía cubre todo lo que necesitas: configurar tu entorno de desarrollo, entender la arquitectura, decidir qué construir y conseguir que tu PR sea aceptado.
---
## Prioridades de Contribución
Valoramos las contribuciones en este orden:
1. **Correcciones de errores** — bloqueos, comportamiento incorrecto, pérdida de datos. Siempre la máxima prioridad.
2. **Compatibilidad entre plataformas** — macOS, diferentes distribuciones de Linux y WSL2 en Windows. Queremos que Hermes funcione en todas partes.
3. **Fortalecimiento de seguridad** — inyección de shell, inyección de prompts, traversal de rutas, escalada de privilegios. Ver [Consideraciones de Seguridad](#consideraciones-de-seguridad).
4. **Rendimiento y robustez** — lógica de reintento, manejo de errores, degradación elegante.
5. **Nuevas habilidades** — pero solo las ampliamente útiles. Ver [¿Debería ser una Habilidad o una Herramienta?](#debería-ser-una-habilidad-o-una-herramienta)
6. **Nuevas herramientas** — raramente necesarias. La mayoría de las capacidades deberían ser habilidades. Ver más abajo.
7. **Documentación** — correcciones, aclaraciones, nuevos ejemplos.
---
## ¿Debería ser una Habilidad o una Herramienta?
Esta es la pregunta más común para los nuevos colaboradores. La respuesta casi siempre es **habilidad**.
### Hazlo una Habilidad cuando:
- La capacidad se puede expresar como instrucciones + comandos de shell + herramientas existentes
- Envuelve una CLI externa o API que el agente puede llamar a través de `terminal` o `web_extract`
- No necesita integración personalizada de Python ni gestión de claves API integrada en el agente
- Ejemplos: búsqueda en arXiv, flujos de trabajo de git, gestión de Docker, procesamiento de PDF, email a través de herramientas CLI
### Hazlo una Herramienta cuando:
- Requiere integración de extremo a extremo con claves API, flujos de autenticación o configuración de múltiples componentes gestionada por el harness del agente
- Necesita lógica de procesamiento personalizada que debe ejecutarse con precisión en cada ocasión (no "mejor esfuerzo" de la interpretación del LLM)
- Maneja datos binarios, streaming o eventos en tiempo real que no pueden pasar por el terminal
- Ejemplos: automatización de navegador (gestión de sesiones Browserbase), TTS (codificación de audio + entrega en plataforma), análisis de visión (manejo de imágenes base64)
### ¿Debería la Habilidad estar incluida?
Las habilidades incluidas (en `skills/`) se envían con cada instalación de Hermes. Deben ser **ampliamente útiles para la mayoría de los usuarios**:
- Manejo de documentos, investigación web, flujos de trabajo de desarrollo comunes, administración de sistemas
- Usadas regularmente por una amplia gama de personas
Si tu habilidad es oficial y útil pero no universalmente necesaria (ej., una integración de servicio de pago, una dependencia pesada), ponla en **`optional-skills/`** — se envía con el repositorio pero no está activada por defecto. Los usuarios pueden descubrirla a través de `hermes skills browse` (etiquetada como "oficial") e instalarla con `hermes skills install` (sin advertencia de terceros, confianza integrada).
Si tu habilidad es especializada, contribuida por la comunidad o de nicho, es mejor para un **Skills Hub** — súbela a un registro de habilidades y compártela en el [Discord de Nous Research](https://discord.gg/NousResearch). Los usuarios pueden instalarla con `hermes skills install`.
---
## Proveedores de Memoria: Publicar como Plugin Independiente
**Ya no aceptamos nuevos proveedores de memoria en este repositorio.** El conjunto de proveedores integrados en `plugins/memory/` (honcho, mem0, supermemory, byterover, hindsight, holographic, openviking, retaindb) está cerrado. Si quieres añadir un nuevo backend de memoria, publícalo como un **repositorio de plugin independiente** que los usuarios instalen en `~/.hermes/plugins/` (o a través de un entry point de pip).
Los plugins de memoria independientes:
- Implementan el mismo ABC `MemoryProvider` (`agent/memory_provider.py`) — `sync_turn`, `prefetch`, `shutdown` y opcionalmente `post_setup(hermes_home, config)` para integración con el asistente de configuración
- Usan el mismo sistema de descubrimiento — `discover_memory_providers()` los recoge desde directorios de plugins de usuario/proyecto y entry points de pip
- Se integran con `hermes memory setup` a través de `post_setup()` — sin necesidad de tocar el código base
- Pueden registrar sus propios subcomandos CLI a través de `register_cli(subparser)` en un archivo `cli.py`
- Obtienen todos los mismos hooks de ciclo de vida y plomería de configuración que los proveedores incluidos en el árbol
Los PRs que añadan un nuevo directorio bajo `plugins/memory/` serán cerrados con un puntero para publicar el proveedor como su propio repositorio. Los proveedores en árbol existentes se mantienen; las correcciones de errores para ellos son bienvenidas.
Esto no es una barra de calidad — es una decisión de acoplamiento y mantenimiento. Los proveedores de memoria son el tipo de plugin más común y no deberían vivir todos en este árbol.
---
## Configuración del Desarrollo
### Prerequisitos
| Requisito | Notas |
|-----------|-------|
| **Git** | Con la extensión `git-lfs` instalada |
| **Python 3.113.13** | uv lo instalará si falta |
| **uv** | Gestor de paquetes Python rápido ([instalar](https://docs.astral.sh/uv/)) |
| **Node.js 20+** | Opcional — necesario para herramientas de navegador y puente WhatsApp (coincide con los engines de `package.json` raíz) |
### Clonar e instalar
```bash
git clone https://github.com/NousResearch/hermes-agent.git
cd hermes-agent
# Crear venv con Python 3.11
uv venv venv --python 3.11
export VIRTUAL_ENV="$(pwd)/venv"
# Instalar con todos los extras (mensajería, cron, menús CLI, herramientas de desarrollo)
uv pip install -e ".[all,dev]"
# Opcional: herramientas de navegador
npm install
```
### Configurar para desarrollo
```bash
mkdir -p ~/.hermes/{cron,sessions,logs,memories,skills}
cp cli-config.yaml.example ~/.hermes/config.yaml
touch ~/.hermes/.env
# Añadir al menos una clave de proveedor LLM:
echo "OPENROUTER_API_KEY=***" >> ~/.hermes/.env
```
### Ejecutar
```bash
# Enlace simbólico para acceso global
mkdir -p ~/.local/bin
ln -sf "$(pwd)/venv/bin/hermes" ~/.local/bin/hermes
# Verificar
hermes doctor
hermes chat -q "Hola"
```
### Ejecutar tests
```bash
# Preferido — coincide con CI (entorno hermético, 4 workers xdist); ver AGENTS.md
scripts/run_tests.sh
# Alternativa (activa el venv primero). El wrapper sigue recomendándose
# para paridad con GitHub Actions antes de abrir un PR:
pytest tests/ -v
```
---
## Estructura del Proyecto
```
hermes-agent/
├── run_agent.py # Clase AIAgent — bucle de conversación central, despacho de herramientas, persistencia de sesión
├── cli.py # Clase HermesCLI — TUI interactiva, integración prompt_toolkit
├── model_tools.py # Orquestación de herramientas (capa delgada sobre tools/registry.py)
├── toolsets.py # Agrupaciones y presets de herramientas (hermes-cli, hermes-telegram, etc.)
├── hermes_state.py # Base de datos de sesiones SQLite con búsqueda de texto completo FTS5, títulos de sesión
├── batch_runner.py # Procesamiento en lote paralelo para generación de trayectorias
├── agent/ # Internos del agente (módulos extraídos)
│ ├── prompt_builder.py # Ensamblaje del prompt del sistema (identidad, habilidades, archivos de contexto, memoria)
│ ├── context_compressor.py # Auto-resumición al acercarse a los límites de contexto
│ ├── auxiliary_client.py # Resuelve clientes OpenAI auxiliares (resumición, visión)
│ ├── display.py # KawaiiSpinner, formateo del progreso de herramientas
│ ├── model_metadata.py # Longitudes de contexto del modelo, estimación de tokens
│ └── trajectory.py # Ayudantes para guardar trayectorias
├── hermes_cli/ # Implementaciones de comandos CLI
│ ├── main.py # Punto de entrada, análisis de argumentos, despacho de comandos
│ ├── config.py # Gestión de configuración, migración, definiciones de variables de entorno
│ ├── setup.py # Asistente de configuración interactivo
│ ├── auth.py # Resolución de proveedor, OAuth, Nous Portal
│ ├── models.py # Listas de selección de modelos de OpenRouter
│ ├── banner.py # Banner de bienvenida, arte ASCII
│ ├── commands.py # Registro central de comandos de barra (CommandDef), autocompletado, ayudantes del gateway
│ ├── callbacks.py # Callbacks interactivos (aclarar, sudo, aprobación)
│ ├── doctor.py # Diagnósticos
│ ├── skills_hub.py # CLI del Skills Hub + comando de barra /skills
│ └── skin_engine.py # Motor de skins/temas — personalización visual de CLI basada en datos
├── tools/ # Implementaciones de herramientas (auto-registradas)
│ ├── registry.py # Registro central de herramientas (esquemas, manejadores, despacho)
│ ├── approval.py # Detección de comandos peligrosos + aprobación por sesión
│ ├── terminal_tool.py # Orquestación del terminal (sudo, ciclo de vida del entorno, backends)
│ ├── file_operations.py # read_file, write_file, búsqueda, patch, etc.
│ ├── web_tools.py # web_search, web_extract (Paralelo/Firecrawl + resumición Gemini)
│ ├── vision_tools.py # Análisis de imágenes a través de modelos multimodales
│ ├── delegate_tool.py # Lanzamiento de subagentes y ejecución paralela de tareas
│ ├── code_execution_tool.py # Python sandboxado con acceso a herramientas vía RPC
│ ├── session_search_tool.py # Búsqueda en conversaciones pasadas con FTS5 + ventanas ancladas
│ ├── cronjob_tools.py # Gestión de tareas programadas
│ ├── skill_tools.py # Búsqueda, carga y gestión de habilidades
│ └── environments/ # Backends de ejecución del terminal
│ ├── base.py # ABC BaseEnvironment
│ ├── local.py, docker.py, ssh.py, singularity.py, modal.py, daytona.py
├── gateway/ # Gateway de mensajería
│ ├── run.py # GatewayRunner — ciclo de vida de plataformas, enrutamiento de mensajes, cron
│ ├── config.py # Resolución de configuración de plataformas
│ ├── session.py # Almacén de sesiones, prompts de contexto, políticas de reset
│ └── platforms/ # Adaptadores de plataformas
│ ├── telegram.py, discord_adapter.py, slack.py, whatsapp.py
├── scripts/ # Scripts del instalador y puente
│ ├── install.sh # Instalador Linux/macOS
│ ├── install.ps1 # Instalador Windows PowerShell
│ └── whatsapp-bridge/ # Puente WhatsApp Node.js (Baileys)
├── skills/ # Habilidades incluidas (copiadas a ~/.hermes/skills/ en la instalación)
├── optional-skills/ # Habilidades opcionales oficiales (descubribles vía hub, no activadas por defecto)
├── tests/ # Suite de tests
├── website/ # Sitio de documentación (hermes-agent.nousresearch.com)
├── cli-config.yaml.example # Configuración de ejemplo (copiada a ~/.hermes/config.yaml)
└── AGENTS.md # Guía de desarrollo para asistentes de codificación IA
```
### Configuración del usuario (almacenada en `~/.hermes/`)
| Ruta | Propósito |
|------|-----------|
| `~/.hermes/config.yaml` | Configuración (modelo, terminal, toolsets, compresión, etc.) |
| `~/.hermes/.env` | Claves API y secretos |
| `~/.hermes/auth.json` | Credenciales OAuth (Nous Portal) |
| `~/.hermes/skills/` | Todas las habilidades activas (incluidas + instaladas desde hub + creadas por el agente) |
| `~/.hermes/memories/` | Memoria persistente (MEMORY.md, USER.md) |
| `~/.hermes/state.db` | Base de datos de sesiones SQLite |
| `~/.hermes/sessions/` | Índice de enrutamiento del gateway (`sessions.json`), migas de pan de solicitudes, transcripciones `*.jsonl` del gateway y (opcionalmente) snapshots JSON por sesión cuando `sessions.write_json_snapshots: true` está configurado. Los snapshots por sesión están desactivados por defecto; state.db es canónica. |
| `~/.hermes/cron/` | Datos de trabajos programados |
| `~/.hermes/whatsapp/session/` | Credenciales del puente WhatsApp |
---
## Descripción General de la Arquitectura
### Bucle Central
```
Mensaje del usuario → AIAgent._run_agent_loop()
├── Construir prompt del sistema (prompt_builder.py)
├── Construir kwargs de API (modelo, mensajes, herramientas, configuración de razonamiento)
├── Llamar al LLM (API compatible con OpenAI)
├── Si tool_calls en la respuesta:
│ ├── Ejecutar cada herramienta a través del despacho del registro
│ ├── Añadir resultados de herramientas a la conversación
│ └── Volver a la llamada al LLM
├── Si respuesta de texto:
│ ├── Persistir sesión en DB
│ └── Devolver final_response
└── Compresión de contexto si se acerca al límite de tokens
```
### Patrones de Diseño Clave
- **Herramientas auto-registradas**: Cada archivo de herramienta llama a `registry.register()` en el momento de importación. `model_tools.py` activa el descubrimiento importando todos los módulos de herramientas.
- **Agrupación en toolsets**: Las herramientas se agrupan en toolsets (`web`, `terminal`, `file`, `browser`, etc.) que pueden habilitarse/deshabilitarse por plataforma.
- **Persistencia de sesión**: Todas las conversaciones se almacenan en SQLite (`hermes_state.py`) con búsqueda de texto completo y títulos de sesión únicos.
- **Inyección efímera**: Los prompts del sistema y los mensajes de relleno se inyectan en el momento de la llamada API, nunca se persisten en la base de datos ni en los logs.
- **Abstracción de proveedor**: El agente funciona con cualquier API compatible con OpenAI. La resolución del proveedor ocurre en el momento de la inicialización.
- **Enrutamiento de proveedor**: Al usar OpenRouter, `provider_routing` en config.yaml controla la selección del proveedor.
---
## Estilo de Código
- **PEP 8** con excepciones prácticas (no imponemos longitud de línea estricta)
- **Comentarios**: Solo cuando se explica la intención no obvia, compromisos o peculiaridades de API. No narres lo que hace el código
- **Manejo de errores**: Captura excepciones específicas. Registra con `logger.warning()`/`logger.error()` — usa `exc_info=True` para errores inesperados
- **Multiplataforma**: Nunca asumas Unix. Ver [Compatibilidad Multiplataforma](#compatibilidad-multiplataforma)
---
## Añadir una Nueva Herramienta
Antes de escribir una herramienta, pregúntate: [¿debería ser una habilidad en su lugar?](#debería-ser-una-habilidad-o-una-herramienta)
Las herramientas se auto-registran en el registro central. Cada archivo de herramienta co-localiza su esquema, manejador y registro:
```python
"""my_tool — Breve descripción de lo que hace esta herramienta."""
import json
from tools.registry import registry
def my_tool(param1: str, param2: int = 10, **kwargs) -> str:
"""Manejador. Devuelve un resultado en cadena (a menudo JSON)."""
result = do_work(param1, param2)
return json.dumps(result)
MY_TOOL_SCHEMA = {
"type": "function",
"function": {
"name": "my_tool",
"description": "Qué hace esta herramienta y cuándo debería usarla el agente.",
"parameters": {
"type": "object",
"properties": {
"param1": {"type": "string", "description": "Qué es param1"},
"param2": {"type": "integer", "description": "Qué es param2", "default": 10},
},
"required": ["param1"],
},
},
}
def _check_requirements() -> bool:
"""Devuelve True si las dependencias de esta herramienta están disponibles."""
return True
registry.register(
name="my_tool",
toolset="my_toolset",
schema=MY_TOOL_SCHEMA,
handler=lambda args, **kw: my_tool(**args, **kw),
check_fn=_check_requirements,
)
```
**Conectar a un toolset (requerido):** Las herramientas integradas se auto-descubren: cualquier
archivo `tools/*.py` que contenga una llamada de nivel superior `registry.register(...)` es
importado por `discover_builtin_tools()` en `tools/registry.py` cuando `model_tools`
se carga. **No** hay una lista de importaciones manual en `model_tools.py` que mantener.
Todavía debes añadir el nombre de la herramienta a la lista apropiada en `toolsets.py`
(por ejemplo `_HERMES_CORE_TOOLS` o un toolset dedicado); de lo contrario la herramienta
se registra pero nunca se expone al agente.
Consulta `AGENTS.md` (sección **Adding New Tools**) para rutas conscientes del perfil y
orientación sobre plugins vs. núcleo.
---
## Añadir una Habilidad
Las habilidades incluidas viven en `skills/` organizadas por categoría. Las habilidades opcionales oficiales usan la misma estructura en `optional-skills/`:
```
skills/
├── research/
│ └── arxiv/
│ ├── SKILL.md # Requerido: instrucciones principales
│ └── scripts/ # Opcional: scripts auxiliares
│ └── search_arxiv.py
├── productivity/
│ └── ocr-and-documents/
│ ├── SKILL.md
│ ├── scripts/
│ └── references/
└── ...
```
### Formato de SKILL.md
```markdown
---
name: my-skill
description: Breve descripción (mostrada en los resultados de búsqueda de habilidades)
version: 1.0.0
author: Tu Nombre
license: MIT
platforms: [macos, linux] # Opcional — restringir a plataformas de SO específicas
required_environment_variables: # Opcional — metadatos de configuración segura al cargar
- name: MY_API_KEY
prompt: Clave API
help: Dónde obtenerla
required_for: funcionalidad completa
prerequisites: # Requisitos de tiempo de ejecución heredados opcionales
env_vars: [MY_API_KEY]
commands: [curl, jq]
metadata:
hermes:
tags: [Categoría, Subcategoría, Palabras clave]
related_skills: [other-skill-name]
fallback_for_toolsets: [web]
requires_toolsets: [terminal]
---
# Título de la Habilidad
Introducción breve.
## Cuándo Usar
Condiciones de activación — ¿cuándo debería el agente cargar esta habilidad?
## Referencia Rápida
Tabla de comandos o llamadas API comunes.
## Procedimiento
Instrucciones paso a paso que el agente sigue.
## Problemas Conocidos
Modos de fallo conocidos y cómo manejarlos.
## Verificación
Cómo confirma el agente que funcionó.
```
### Estándares de autoría de habilidades (OBLIGATORIOS)
Todo skill nuevo o modernizado — incluido, opcional o contribuido — debe cumplir estos estándares antes del merge:
1. **`description` ≤ 60 caracteres, una oración, termina con punto.** Las descripciones largas saturan la UI de listado de habilidades. Indica la capacidad, no la implementación. Sin palabras de marketing ("potente", "completo", "fluido", "avanzado").
2. **Las herramientas referenciadas en el cuerpo de SKILL.md deben ser herramientas nativas de Hermes o servidores MCP que la habilidad espere explícitamente.** Usa los nombres de herramientas en comillas invertidas: `` `terminal` ``, `` `web_extract` ``, `` `web_search` ``, `` `read_file` ``, `` `write_file` ``, etc.
3. **El campo `platforms:` auditado contra las importaciones reales del script.** Las habilidades que usen primitivos solo de POSIX deben declarar sus plataformas soportadas.
4. **`author` da crédito primero al colaborador humano.**
5. **El cuerpo de SKILL.md usa el orden moderno de secciones:** título, intro de 2-3 oraciones, luego: `## Cuándo Usar`, `## Prerequisitos`, `## Cómo Ejecutar`, `## Referencia Rápida`, `## Procedimiento`, `## Problemas Conocidos`, `## Verificación`.
6. **Los scripts van en `scripts/`, las referencias en `references/`, las plantillas en `templates/`.**
7. **Los tests viven en `tests/skills/test_<skill>_skill.py`** y usan solo stdlib + pytest + `unittest.mock`. Sin llamadas de red en vivo.
8. **Las adiciones a `.env.example` están aisladas en un bloque claramente delimitado.**
---
## Añadir una Skin / Tema
Hermes usa un sistema de skins basado en datos — no se necesitan cambios de código para añadir una nueva skin.
**Opción A: Skin de usuario (archivo YAML)**
Crea `~/.hermes/skins/<nombre>.yaml`:
```yaml
name: mitema
description: Breve descripción del tema
colors:
banner_border: "#HEX"
banner_title: "#HEX"
banner_accent: "#HEX"
banner_dim: "#HEX"
banner_text: "#HEX"
response_border: "#HEX"
spinner:
waiting_faces: ["(⚔)", "(⛨)"]
thinking_faces: ["(⚔)", "(⌁)"]
thinking_verbs: ["forjando", "planeando"]
branding:
agent_name: "Mi Agente"
welcome: "Mensaje de bienvenida"
response_label: " ⚔ Agente "
prompt_symbol: "⚔"
tool_prefix: "╎"
```
Todos los campos son opcionales — los valores faltantes se heredan de la skin predeterminada.
**Opción B: Skin integrada**
Añade al dict `_BUILTIN_SKINS` en `hermes_cli/skin_engine.py`. Usa el mismo esquema que arriba pero como dict de Python.
**Activar:**
- CLI: `/skin mitema` o establece `display.skin: mitema` en config.yaml
---
## Compatibilidad Multiplataforma
Hermes se ejecuta en Linux, macOS y Windows nativo (además de WSL2). Al escribir código
que toca el SO, asume que *cualquier* plataforma puede alcanzar tu ruta de código.
> **Antes de hacer PR:** ejecuta `scripts/check-windows-footguns.py` para detectar
> los patrones inseguros comunes de Windows en tu diff. Es basado en grep y barato;
> CI también lo ejecuta en cada PR.
### Reglas críticas
1. **Nunca llames `os.kill(pid, 0)` para comprobaciones de liveness.** En Windows **NO es una operación sin efecto**. Usa `psutil.pid_exists(pid)` en su lugar.
2. **Usa `shutil.which()` antes de hacer shell — no asumas que Windows tiene las herramientas que tiene Linux.** `ps`, `kill`, `grep`, `awk`, etc. simplemente no existen en Windows.
3. **`termios` y `fcntl` son solo de Unix.** Siempre captura tanto `ImportError` como `NotImplementedError`.
4. **Codificación de archivos.** Windows puede guardar archivos `.env` en `cp1252`. Siempre maneja errores de codificación.
5. **Gestión de procesos.** `os.setsid()`, `os.killpg()`, `os.fork()`, `os.getuid()` y el manejo de señales POSIX difieren en Windows.
6. **Señales que no existen en Windows:** `SIGALRM`, `SIGCHLD`, `SIGHUP`, `SIGUSR1`, `SIGUSR2`, etc.
7. **Separadores de ruta.** Usa `pathlib.Path` en lugar de concatenación de cadenas con `/`.
8. **Los enlaces simbólicos necesitan privilegios elevados en Windows** (a menos que el Modo Desarrollador esté activado).
9. **Los modos de archivo POSIX (0o600, 0o644, etc.) NO se aplican en NTFS** por defecto.
10. **Los daemons de fondo desacoplados en Windows necesitan `pythonw.exe`, NO `python.exe`.**
---
## Consideraciones de Seguridad
Hermes tiene acceso al terminal. La seguridad importa.
### Protecciones existentes
| Capa | Implementación |
|------|---------------|
| **Piping de contraseña sudo** | Usa `shlex.quote()` para prevenir inyección de shell |
| **Detección de comandos peligrosos** | Patrones regex en `tools/approval.py` con flujo de aprobación del usuario |
| **Inyección de prompts en cron** | Escáner en `tools/cronjob_tools.py` bloquea patrones de anulación de instrucciones |
| **Lista de denegación de escritura** | Rutas protegidas resueltas a través de `os.path.realpath()` para prevenir bypass de enlaces simbólicos |
| **Skills Guard** | Escáner de seguridad para habilidades instaladas desde el hub (`tools/skills_guard.py`) |
| **Sandbox de ejecución de código** | El proceso hijo `execute_code` se ejecuta con claves API eliminadas del entorno |
| **Fortalecimiento de contenedor** | Docker: todas las capacidades eliminadas, sin escalada de privilegios, límites de PID, tmpfs de tamaño limitado |
### Al contribuir código sensible a la seguridad
- **Siempre usa `shlex.quote()`** al interpolar entrada del usuario en comandos de shell
- **Resuelve enlaces simbólicos** con `os.path.realpath()` antes de comprobaciones de control de acceso basadas en rutas
- **No registres secretos.** Las claves API, tokens y contraseñas nunca deben aparecer en la salida de log
- **Captura excepciones amplias** alrededor de la ejecución de herramientas para que un solo fallo no bloquee el bucle del agente
- **Prueba en todas las plataformas** si tu cambio toca rutas de archivos, gestión de procesos o comandos de shell
### Política de fijación de dependencias (fortalecimiento de la cadena de suministro)
Tras el [compromiso de la cadena de suministro de litellm](https://github.com/BerriAI/litellm/issues/24512) en marzo de 2026 y la [campaña del gusano Mini Shai-Hulud](https://socket.dev/blog/tanstack-npm-packages-compromised-mini-shai-hulud-supply-chain-attack) en mayo de 2026, todas las dependencias deben seguir estas reglas:
| Tipo de fuente | Tratamiento requerido | Justificación |
|---|---|---|
| **Paquete PyPI** | `>=suelo,<siguiente_mayor` | Las versiones de PyPI son inmutables una vez publicadas, pero pueden empujarse nuevas versiones en tu rango. |
| **URL de Git** | SHA completo del commit | Las ramas y etiquetas son refs mutables; el SHA está direccionado por contenido. |
| **GitHub Actions** | SHA completo del commit + comentario de versión | Las etiquetas de acción son refs mutables. Fija como `uses: owner/action@<sha> # vX.Y.Z` |
| **Instalaciones pip solo de CI** | `==exacto` | Builds de CI herméticos; el cambio es aceptable. |
**Cada nueva dependencia de PyPI en un PR debe tener un límite superior `<siguiente_mayor`.** Los PRs que añadan especificaciones `>=X.Y.Z` sin límite superior serán rechazados.
---
## Proceso de Pull Request
### Nomenclatura de ramas
```
fix/descripcion # Correcciones de errores
feat/descripcion # Nuevas funcionalidades
docs/descripcion # Documentación
test/descripcion # Tests
refactor/descripcion # Reestructuración de código
```
### Antes de enviar
1. **Ejecutar tests**: `scripts/run_tests.sh` (recomendado; igual que CI) o `pytest tests/ -v` con el venv del proyecto activado
2. **Probar manualmente**: Ejecuta `hermes` y ejercita la ruta de código que cambiaste
3. **Verificar impacto multiplataforma**: Si tocas E/S de archivos, gestión de procesos o manejo del terminal, considera macOS, Linux y WSL2
4. **Mantén los PRs enfocados**: Un cambio lógico por PR. No mezcles una corrección de error con una refactorización con una nueva funcionalidad.
### Descripción del PR
Incluye:
- **Qué** cambió y **por qué**
- **Cómo probarlo** (pasos de reproducción para errores, ejemplos de uso para funcionalidades)
- **Qué plataformas** probaste
- Referencia cualquier issue relacionado
### Mensajes de commit
Usamos [Conventional Commits](https://www.conventionalcommits.org/):
```
<tipo>(<alcance>): <descripción>
```
| Tipo | Usar para |
|------|-----------|
| `fix` | Correcciones de errores |
| `feat` | Nuevas funcionalidades |
| `docs` | Documentación |
| `test` | Tests |
| `refactor` | Reestructuración de código (sin cambio de comportamiento) |
| `chore` | Build, CI, actualizaciones de dependencias |
Alcances: `cli`, `gateway`, `tools`, `skills`, `agent`, `install`, `whatsapp`, `security`, etc.
Ejemplos:
```
fix(cli): prevenir bloqueo en save_config_value cuando el modelo es una cadena
feat(gateway): añadir aislamiento de sesión multi-usuario de WhatsApp
fix(security): prevenir inyección de shell en el piping de contraseña sudo
test(tools): añadir tests unitarios para file_operations
```
---
## Reportar Issues
- Usa [GitHub Issues](https://github.com/NousResearch/hermes-agent/issues)
- Incluye: SO, versión de Python, versión de Hermes (`hermes version`), traza de error completa
- Incluye pasos para reproducir
- Verifica los issues existentes antes de crear duplicados
- Para vulnerabilidades de seguridad, por favor reporta de forma privada
---
## Comunidad
- **Discord**: [discord.gg/NousResearch](https://discord.gg/NousResearch) — para preguntas, mostrar proyectos y compartir habilidades
- **GitHub Discussions**: Para propuestas de diseño y discusiones de arquitectura
- **Skills Hub**: Sube habilidades especializadas a un registro y compártelas con la comunidad
---
## Licencia
Al contribuir, aceptas que tus contribuciones serán licenciadas bajo la [Licencia MIT](LICENSE).