DeepSeek Harness: Un framework de agente open source donde literalmente todo es un plugin
Una pila de agente completa, publicada en GitHub
DeepSeek lanzó una vista previa para desarrolladores de DeepSeek Harness (dsh) el 13 de agosto de 2026. El repositorio está en deepseek-ai/deepseek-harness. Al final del día ya tenía 1.6k estrellas, 12,293 commits y 19 contribuidores — cifras que indican que esto no es un proyecto de fin de semana. La base de código es 97.1% TypeScript, con 1.6% CSS y 0.7% Python. Versión del paquete al publicar: 0.1.0-rc.5.
La página de presentación está en deepseek.com/harness y la documentación para desarrolladores en deepseek-harness.github.io/deepseek-harness.
Licenciado bajo MIT.
El pitch en una línea
Del README: “Agente = Modelo + Harness.”
El modelo es el alma. Un harness permite que un agente entienda su entorno, use herramientas y siga funcionando en escenarios del mundo real. La propuesta de DeepSeek: cada capacidad — modelos, herramientas, habilidades, sesiones, sandboxes, almacenamiento, bucles, programación y la UI — es un plugin intercambiable.
Esto no es un eslogan. La arquitectura lo impone.
Cordis: El kernel que lo sustenta todo
DeepSeek Harness está construido sobre Cordis, un framework de plugins incluido. El diseño de Cordis se describe en un artículo llamado A Programming Paradigm for Spatiotemporal Composability.
Todo el framework se reduce a cinco ideas:
- Un plugin es un objeto que implementa Service. Puede ser una función con
injectyapply(ctx), o una subclase deService. - Un contexto es un repositorio de servicios. Un plugin reclama una clave estable como
ctx.tools,ctx.llmoctx.sessions. Otros plugins encuentran servicios por clave en lugar de importar implementaciones concretas. - Declara dependencias de servicio mediante
inject. Un plugin que nombre servicios requeridos espera hasta que esos servicios existan. Sin secuenciación manual de arranque. - Eventos tipados para comunicación. Cuatro modos de envío:
emit(dispara y olvida),waterfall(estilo middleware connext()),parallel(todos los listeners corren concurrentemente) yserial(listeners corren en orden con valores de retorno). - Los registros son efectos reversibles. Secciones de prompt, esquemas de herramientas, adaptadores, listeners — todo se instala a través de
ctx.effect()para que la recarga y el cierre los deshagan de forma predecible.
El modelo waterfall de Cordis es middleware envolvente. Un listener recibe (...args, next). Llama next() para delegar al siguiente servicio; retorna sin next() para cortocircuitar. Para eventos de decisión única, el cortocircuito es el diseño — un listener de política puede tomar posesión total de una decisión.
Todo es un plugin (en serio)
La lista de plugins en deepseek.com/harness detalla toda la superficie de capacidades:
- Models — los backends LLM (DeepSeek, OpenAI, Anthropic, Bedrock, Vertex, Azure, Codex, además de cualquier endpoint compatible con OpenAI)
- Tools — lo que el modelo puede invocar
- Skills — paquetes reutilizables de prompt y herramientas
- Sessions — gestión del estado de conversación
- Sandboxes — dónde se ejecuta el código (bash PTY, backend local
danger-full-access, sandbox nativo basado en landlock) - Storage — persistencia de sesiones
- Loops — la lógica de turno del agente
- Scheduling — despacho de subagentes y tareas
- UI — la interfaz web servida en el puerto 3080 por defecto
Un desarrollador puede seleccionar, intercambiar o extender cualquiera de estas mediante configuración — sin cambios en el código fuente de DeepSeek Harness. El Catálogo de Configuración de Plugins se genera automáticamente desde el código fuente (scripts/gen-config-catalog.ts) y CI lo verifica al momento, así que cada campo en un bloque config: de cordis.yml coincide exactamente con el tipo de configuración declarado de un plugin.
Cuatro modos de ejecución
La documentación incluye cuatro ajustes predefinidos. Cada uno apunta a un caso de uso distinto.
Modo Standard — Agente de codificación completo: edición de archivos, shell, búsqueda de archivos y web, habilidades, planificación, metas, subagentes y flujos de trabajo. Esta es la experiencia predeterminada de la interfaz web.
Modo Code — Todo lo de Standard, pero las herramientas se exponen a través de un SDK Code Mode para que el modelo pueda combinar operaciones de varios pasos en un solo programa TypeScript. Un programa generado por el modelo reemplaza varias rondas de llamadas a herramientas.
Modo Minimal — Solo dos herramientas: un shell bash persistente y str_replace_editor. Sirve para evaluar modelos en un entorno reducido. Sin habilidades, sin planificación, sin subagentes — capacidad cruda del modelo contra una base de código real.
Modo Creator — Diseñado para escribir ajustes predefinidos de agente personalizados. Incluye todas las capacidades del modo Standard más inspección en tiempo de ejecución, experimentos de plugins Cordis en memoria y guías de autoría de ajustes. Así es como construyes el quinto, sexto, séptimo modo.
Cada ejecución es trazable
Aquí es donde Harness se distingue de la mayoría de herramientas para agentes. Todo lo que el modelo ve queda registrado en un registro de sesiones inmutable:
- Prompts del sistema
- Salida de razonamiento
- Llamadas a herramientas y sus resultados
- Decisiones de programación de subagentes
- Cada inyección de contexto
La interfaz web tiene una vista Trajectory donde inspeccionas estos registros filtrados por fuente. Reanudar, bifurcar, buscar y reproducir — las cuatro operaciones funcionan contra el mismo flujo de eventos. Sin base de datos de trazas separada, sin paso de exportación. El JSONL de sesión es la fuente de verdad.
Para el SDK de Python, el directorio de sesiones almacena JSONL sin comprimir con las solicitudes de modelo ensambladas y las llamadas a herramientas. El ejemplo en examples/jsonrpc-agent/minimal.py muestra esto de principio a fin.
Configuración de modelos: DeepSeek + lo que sea
La página de configuración de modelos (Configurar modelos) tiene tres capas.
Oficial de DeepSeek. Abre Settings → Models, pega una clave API de DeepSeek, guarda. La clave es de solo escritura. Después de guardar, la UI recibe un descriptor enmascarado, nunca el texto plano. Las claves residen en \$DSH_HOME/.credentials.yaml; la página de ajustes solo guarda una referencia a la credencial.
Proveedores del catálogo. Haz clic en “Add provider”, elige Anthropic o OpenAI, pega la clave. Los proveedores que usan autenticación nativa (Bedrock vía credenciales AWS + región, Vertex vía proyecto ADC, Azure vía api-version, Codex vía OAuth) no funcionan solo con un campo de clave API — cada uno necesita su propia ruta de autenticación.
Proveedores personalizados. Para un gateway corporativo, servidor autoalojado o cualquier proveedor que no esté en el catálogo. Establece un ID de proveedor en minúsculas (permanente — solicitudes, sesiones guardadas, valores por defecto de modelo y referencias de credenciales lo usan), URL base, protocolo API, credenciales y al menos un modelo.
Los modelos visuales necesitan un paso extra. Como un endpoint personalizado no tiene forma de anunciar sus modalidades soportadas, el formulario no puede detectar automáticamente el soporte de visión. Añades input: [text, image] al modelo en \$DSH_HOME/settings.yaml. Si todos tus modelos personalizados aceptan imágenes, establece defaultInput: [text, image] una vez a nivel de proveedor en lugar de por modelo. El campo input es una afirmación, no una comprobación — si afirmas que un modelo hace visión pero el endpoint en realidad no lo hace, el proveedor rechaza la solicitud en lugar de Harness.
La resolución de problemas se explica directamente en la documentación:
MISSING_CREDENTIAL→ guarda la clave del proveedor a través de la página Models o exporta la variable de entorno referenciadaUNKNOWN_MODEL→ elige un modelo configurado, o añade el modelo faltante al proveedor personalizado- “Get available models returns 401” → verifica la clave. El descubrimiento de modelos llama al endpoint
GET /modelscompatible con OpenAI. Si tu servicio no expone eso, introduce los modelos manualmente. - “Image rejected before send” → el modelo no declaró la modalidad
image. Añadeinput: [text, image]. - “Provider rejects a request with an image” → el modelo afirmó capacidad de visión que su endpoint en realidad no tiene. Elimina
imagede la lista y empieza una sesión nueva (la imagen antigua permanece en el registro de sesión y repite la misma solicitud).
Primeros pasos: tres rutas
Ruta 1: npx @deepseek-ai/dsh web
Instala Node.js, ejecuta un comando. La interfaz web arranca en http://127.0.0.1:3080. Eso es todo. Sin clonar, sin compilar, sin pnpm.
npx @deepseek-ai/dsh webLuego: Settings → Models → pega la clave API de DeepSeek. Elige un espacio de trabajo (el directorio donde se invocó dsh sirve). Inicia una sesión:
Resume este repositorio e identifica sus paquetes principales.
El agente lee y edita archivos del espacio de trabajo, ejecuta comandos, delega trabajo y mantiene un plan. Cualquier operación que necesite aprobación bajo la política de permisos activa muestra un diálogo en la interfaz web antes de ejecutarse.
Ruta 2: Clonar y compilar desde el código fuente
git clone https://github.com/deepseek-ai/deepseek-harness.gitcd deepseek-harnesspnpm installpnpm run buildpnpm dsh webRuta 3: SDK de Python
Requisitos: Python 3.10+, Linux x64 / Linux arm64 / macOS 14+ en arm64, un endpoint compatible con DeepSeek.
git clone https://github.com/deepseek-ai/deepseek-harness.gitcd deepseek-harnesspython -m venv .venv. .venv/bin/activatepython -m pip install deepseek-harness-sdkConfigura credenciales:
export DEEPSEEK_API_KEY=sk-your-key-here# Opcional:# export DSH_MODEL=deepseek-v4-flash# export DSH_SYSTEM_PROMPT='You are a helpful software engineer assistant.'Ejecuta una tarea contra un espacio de trabajo aislado:
python examples/jsonrpc-agent/minimal.py \ --workspace /absolute/path/to/workspace \ --session-root /absolute/path/to/sessions \ --session-id example-001 \ "Inspect the repository and fix the failing tests."Para tu propio código, el punto de entrada del SDK es DeepSeekHarness como gestor de contexto:
from pathlib import Pathfrom deepseek_harness import DeepSeekHarness
config = Path("examples/jsonrpc-agent/minimal.cordis.yml").resolve()workspace = Path("/absolute/path/to/workspace").resolve()sessions = Path("/absolute/path/to/sessions").resolve()
with DeepSeekHarness( provider="deepseek-official", model="deepseek-v4-flash", max_tokens=49_152, cwd=str(workspace), session_root=str(sessions), cordis=str(config),) as harness: result = harness.run( "Inspect the repository and fix the failing tests.", session_id="example-001", ) print(result.final_response)DeepSeekHarness arranca diferidamente el runtime empaquetado y lo reutiliza hasta que el bloque with sale. Reutiliza el mismo ID de sesión para preservar el proceso Bash (directorio de trabajo, variables de entorno, funciones de shell). Usa un ID de sesión nuevo para una tarea independiente.
La composición mínima jsonrpc-agent es deliberadamente escueta: solo bash persistente y str_replace_editor como herramientas orientadas al modelo. Tiempo de espera de Bash: 300 segundos. Límite de salida del editor: 16,000 caracteres. Compactación de contexto desactivada. El sistema de archivos usa el backend local básico — las rutas del editor pueden direccionar cualquier cosa que el proceso runtime pueda ver. La documentación advierte explícitamente: “Ejecútalo solo dentro de un checkout desechable o contenedor.” El backend PTY persistente también requiere un sustrato de terminal POSIX — sin soporte para Windows en esta composición.
Escribe tu primer plugin
Tutorial: Tu primer plugin. Un plugin es un módulo TypeScript que exporta una función apply:
import type { Context } from '@deepseek-ai/cordis'
export const name = 'hello-plugin'
export function apply(ctx: Context) { console.log('[hello-plugin] plugin loaded!')}Regístralo en un parche cordis.yml:
- insert: - id: hello name: '/absolute/path/to/deepseek-harness/scratch-plugin/src/my-plugin.ts'Arranca con la superposición:
pnpm dsh web --patch ./scratch-plugin/cordis.ymlLa limpieza automática es la característica estrella. Cualquier cosa registrada a través de ctx — listeners de eventos, herramientas, temporizadores — se limpia cuando el plugin se descarga. Sin removeListener ni clearInterval manuales. Para limpieza explícita (conexiones de red), retorna un desechador desde ctx.effect().
Las dependencias se declaran con inject:
export const name = 'my-tool-plugin'export const inject = ['tools']
export function apply(ctx: Context) { // ctx.tools está listo aquí}Cordis espera a que cada servicio requerido esté disponible antes de cargar el plugin.
Existen tres formas de plugin: función (arriba), objeto con apply y clase que extiende Service. Usa la forma de clase cuando el plugin mismo proporciona un servicio que otros plugins consumen.
Escribe tu primera herramienta
Tutorial: Construye una herramienta. Usa defineTool de @deepseek-ai/dsh-tools:
import type { Context } from '@deepseek-ai/cordis'import { defineTool } from '@deepseek-ai/dsh-tools'
export const name = 'greet-tool'export const inject = ['tools']
export function apply(ctx: Context) { ctx.tools.register(defineTool({ name: 'greet', description: 'Greet someone by name.', parameters: { name: { type: 'string', required: true, description: 'The name to greet', }, }, output: { schema: { type: 'string' }, render: (_args, value) => [{ type: 'text', text: value }], }, async execute(args) { return `Hello, ${args.name}!` }, }))}defineTool infiere y valida args desde parameters. execute retorna el valor canónico declarado por output.schema. output.render convierte ese valor canónico en contenido orientado al modelo. Tras un reinicio con el parche, pide a la interfaz web: “Use the greet tool to greet Ada.” El modelo llama a greet y recibe Hello, Ada!.
Los siguientes pasos del tutorial son configuración de plugins, la referencia de autoría de herramientas (esquemas anidados, valores canónicos, trabajo en segundo plano, hooks de política, Code Mode, tarjetas de UI) y capas de capacidad (definición de servicio → proveedor de servicio → división de paquete consumidor).
Modos de entrada CLI
El comando @deepseek-ai/dsh es el lanzador del producto. Cuatro puntos de entrada:
| Comando | Propósito |
|---|---|
dsh --profile <name> |
Arranca el perfil nombrado bajo \$DSH_HOME/profiles/<name> |
dsh --profile headless "job" |
Ejecuta una sesión persistente nueva, imprime la respuesta final, sale |
dsh web |
Alias de --profile web |
dsh plugin --profile <name> <pnpm args> |
Gestiona los plugins de un perfil reenviando a pnpm |
El directorio de invocación es la raíz por defecto del espacio de trabajo. Los perfiles web y headless se inicializan automáticamente desde las plantillas incluidas en el primer uso. Cualquier otro perfil debe crearse a través de dsh plugin.
Los flags del lanzador van primero. El primer token que el lanzador no reconoce se convierte en argumentos de la app. Ejemplo: dsh --profile web --port 8080 entrega --port 8080 a la app web, no al lanzador.
Un directorio de perfil contiene un package.json (dependencias de plugins fuera del árbol, más el manifiesto del perfil dsh.profile con su lista ordenada bundles) y un cordis.patch.yml (la propia capa de parche del usuario). El orden de composición sobre una raíz vacía es: el parche de cada bundle en orden dsh.profile.bundles → el cordis.patch.yml del perfil → el \$DSH_HOME/cordis.patch.yml a nivel de hogar → superposiciones --patch. Usa --dump-default-config y --dump-config para inspeccionar el árbol compuesto sin arrancarlo.
Plugins comunitarios y ecosistema
Etiqueta tu repositorio de plugins con dsh-plugin en GitHub para que se pueda descubrir. El sitio oficial enlaza directamente a esa página de temas. También hay una comunidad Discord de DeepSeek Harness para discusiones.
El proyecto usa GitHub Discussions para comentarios y reportes de errores. La documentación enlaza a CONTRIBUTING.md para el flujo de desarrollo, architecture.md para el diseño del sistema y AGENTS.md para las convenciones de codificación específicas de agentes.
Vista previa para desarrolladores — sí, se romperá
El README lo pone en MAYÚSCULAS: “HABRÁ CAMBIOS QUE ROMPAN LA COMPATIBILIDAD.”
Los plugins y APIs centrales siguen evolucionando. La página de presentación lo dice directamente: “DeepSeek Harness permanece en vista previa para desarrolladores y sigue siendo probado por desarrolladores que construyen harnesses de agentes.”
Si construyes sobre él, fija un hash de commit, mantén tus plugins delgados frente al catálogo de configuración y espera tener que volver a probar en cada aumento de rc. La limpieza automática de plugins y la inyección de dependencias hacen que volver a probar sea menos doloroso que con los frameworks monolíticos, pero “vista previa para desarrolladores” significa exactamente lo que dice.
Qué hace que esto sea distinto
La mayoría de frameworks de agentes hoy empiezan con un bucle de turnos y añaden la extensibilidad como una idea de último momento. Harness lo invierte: la extensibilidad es el framework, y el bucle de turnos es solo otro plugin. El resultado observable son tres cosas que normalmente no obtienes en un solo paquete:
- Intercambia cualquier cosa sin un fork. ¿No te gusta el sistema de herramientas integrado? Reemplázalo. ¿Quieres una capa de enrutamiento LLM distinta? Intercambia el proveedor. Todo se resuelve a través de claves de servicio Cordis.
- Trazabilidad por defecto. El registro inmutable no es un complemento de observabilidad. Es cómo funcionan las sesiones. Reanudar, bifurcar, buscar y reproducir usan todos el mismo flujo.
- Ajustes predefinidos componibles, no flags de características. Los cuatro modos (Standard / Code / Minimal / Creator) son solo capas ordenadas de parche de bundles de plugins. Puedes superponer tus propios ajustes predefinidos encima con YAML en lugar de código.
Si este enfoque gana a los SDK monolíticos depende de si el ecosistema de plugins produce suficientes herramientas y proveedores de terceros para hacer que la historia de intercambio/recomposición sea real. Con 1.6k estrellas y 12k commits el primer día, el impulso está claramente ahí.
Referencias
- Página de presentación de DeepSeek Harness
- deepseek-ai/deepseek-harness en GitHub
- Inicio rápido de la documentación para desarrolladores
- Guía de configuración de modelos
- Guía del SDK de Python
- Tutorial Tu primer plugin
- Tutorial Construye una herramienta
- Introducción a Cordis
- Catálogo de configuración de plugins
- README del CLI
- Cordis en GitHub
- Artículo de Cordis: A Programming Paradigm for Spatiotemporal Composability
- Tema comunitario dsh-plugin en GitHub
- Discord de DeepSeek Harness