needhelp
← Back to blog

DeepSeek Harness: Um framework de agente open source onde literalmente tudo é um plugin

by needhelp
DeepSeek
AI Agents
Open Source
Cordis
Plugin Architecture

Uma pilha completa de agente, publicada no GitHub

A DeepSeek lançou uma prévia para desenvolvedores do DeepSeek Harness (dsh) em 13 de agosto de 2026. O repositório fica em deepseek-ai/deepseek-harness. Ao final do dia, já tinha 1,6k estrelas, 12.293 commits e 19 contribuidores — números que indicam que não é um projeto de fim de semana. A base de código é 97,1% TypeScript, com 1,6% CSS e 0,7% Python. Versão do pacote no lançamento: 0.1.0-rc.5.

A página inicial está em deepseek.com/harness e a documentação para desenvolvedores em deepseek-harness.github.io/deepseek-harness.

Licenciado sob MIT.

O pitch em uma linha

Do README: “Agente = Modelo + Harness.”

O modelo é a alma. Um harness permite que um agente entenda seu ambiente, use ferramentas e continue trabalhando em cenários do mundo real. A proposta da DeepSeek: cada capacidade — modelos, ferramentas, habilidades, sessões, sandboxes, armazenamento, loops, agendamento e a UI — é um plugin substituível.

Isso não é um slogan. A arquitetura impõe isso.

Cordis: O kernel sob tudo

O DeepSeek Harness é construído sobre o Cordis, um framework de plugins incluso. O design do Cordis é descrito em um artigo chamado A Programming Paradigm for Spatiotemporal Composability.

Todo o framework se reduz a cinco ideias:

  1. Um plugin é um objeto que implementa Service. Pode ser uma função com inject e apply(ctx), ou uma subclasse de Service.
  2. Um contexto é um repositório de serviços. Um plugin reclama uma chave estável como ctx.tools, ctx.llm ou ctx.sessions. Outros plugins encontram serviços por chave, em vez de importar implementações concretas.
  3. Declare dependência de serviço via inject. Um plugin que nomeia serviços necessários espera até que esses serviços existam. Sem sequenciamento manual de inicialização.
  4. Eventos tipados para comunicação. Quatro modos de despacho: emit (dispara e esquece), waterfall (estilo middleware com next()), parallel (todos os listeners rodam juntos) e serial (listeners rodam em ordem com valores de retorno).
  5. Registros são efeitos reversíveis. Seções de prompt, schemas de ferramentas, adaptadores, listeners — tudo se instala via ctx.effect(), para que reload e teardown os desfaçam de forma previsível.

O modelo waterfall do Cordis é um middleware envolvente. Um listener recebe (...args, next). Chama next() para delegar ao próximo serviço; retorna sem next() para curto-circuitar. Para eventos de decisão única, o curto-circuito faz parte do design — um listener de política pode tomar posse total de uma decisão.

Tudo é um plugin (sério)

A lista de plugins em deepseek.com/harness detalha toda a superfície de capacidades:

  • Models — os backends LLM (DeepSeek, OpenAI, Anthropic, Bedrock, Vertex, Azure, Codex, além de qualquer endpoint compatível com OpenAI)
  • Tools — o que o modelo pode chamar
  • Skills — pacotes reutilizáveis de prompt e ferramentas
  • Sessions — gerenciamento de estado de conversa
  • Sandboxes — onde o código roda (bash PTY, backend local danger-full-access, sandbox nativa baseada em landlock)
  • Storage — persistência de sessões
  • Loops — a lógica de turnos do agente
  • Scheduling — despacho de subagentes e tarefas
  • UI — a interface Web servida na porta 3080 por padrão

Um desenvolvedor pode selecionar, trocar ou estender qualquer um desses via configuração — sem alterar o código-fonte do próprio DeepSeek Harness. O Catálogo de Config de Plugins é gerado automaticamente da fonte (scripts/gen-config-catalog.ts) e verificado em tempo real pela CI, então cada campo em um bloco config: de cordis.yml corresponde exatamente ao tipo de config declarado de um plugin.

Quatro modos de execução

A documentação traz quatro predefinições. Cada uma mira um caso de uso diferente.

Modo Standard — Agente de codificação completo: edição de arquivos, shell, busca de arquivos e web, habilidades, planejamento, metas, subagentes e fluxos de trabalho. Essa é a experiência padrão da interface Web.

Modo Code — Tudo do Standard, mas as ferramentas são expostas através de um SDK Code Mode para que o modelo possa combinar operações de vários passos em um único programa TypeScript. Um programa gerado pelo modelo substitui várias rodadas de chamadas a ferramentas.

Modo Minimal — Apenas duas ferramentas: um shell bash persistente e str_replace_editor. Serve para avaliar modelos em um ambiente enxuto. Sem habilidades, sem planejamento, sem subagentes — capacidade bruta do modelo contra uma base de código real.

Modo Creator — Feito para escrever predefinições de agente personalizadas. Inclui todas as capacidades do modo Standard mais inspeção em tempo de execução, experimentos de plugins Cordis em memória e orientação para criação de predefinições. É assim que se constrói o quinto, sexto, sétimo modo.

Cada execução é rastreável

Aqui o Harness se distingue da maioria das ferramentas para agentes. Tudo o que o modelo vê é registrado em um registro de sessão somente-acréscimo:

  • Prompts do sistema
  • Saída de raciocínio
  • Chamadas de ferramentas e seus resultados
  • Decisões de agendamento de subagentes
  • Cada injeção de contexto

A interface Web tem uma visão Trajectory onde se inspeciona esses registros filtrados por fonte. Retomar, bifurcar, buscar e reproduzir — as quatro operações funcionam contra o mesmo fluxo de eventos. Sem banco de dados de traces separado, sem etapa de exportação. O JSONL da sessão é a fonte da verdade.

Para o SDK Python, o diretório de sessões armazena JSONL não compactado contendo as requisições de modelo montadas e as chamadas de ferramentas. O exemplo em examples/jsonrpc-agent/minimal.py mostra isso do início ao fim.

Configuração de modelos: DeepSeek + qualquer coisa

A página de configuração de modelos (Configurar modelos) tem três camadas.

Oficial da DeepSeek. Abra Settings → Models, cole uma chave API da DeepSeek, salve. A chave é somente escrita. Depois de salvar, a UI recebe um descritor ofuscado, nunca o texto claro. As chaves ficam em \$DSH_HOME/.credentials.yaml; a página de configurações só guarda uma referência de credencial.

Provedores do catálogo. Clique em “Add provider”, escolha Anthropic ou OpenAI, cole a chave. Provedores que usam autenticação nativa (Bedrock via credenciais AWS + região, Vertex via projeto ADC, Azure via api-version, Codex via OAuth) não funcionam só com um campo de chave API — cada um precisa de seu próprio caminho de autenticação.

Provedores personalizados. Para um gateway corporativo, servidor auto-hospedado ou qualquer provedor que não esteja no catálogo. Defina um ID de provedor em minúsculas (permanente — requisições, sessões salvas, padrões de modelo e referências de credencial todos o usam), URL base, protocolo API, credenciais e pelo menos um modelo.

Modelos visuais precisam de um passo extra. Como um endpoint personalizado não tem como anunciar suas modalidades suportadas, o formulário não consegue detectar automaticamente o suporte a visão. Você adiciona input: [text, image] ao modelo em \$DSH_HOME/settings.yaml. Se todos os seus modelos personalizados aceitarem imagens, defina defaultInput: [text, image] uma vez no nível do provedor, em vez de por modelo. O campo input é uma afirmação, não uma checagem — se você alegar que um modelo faz visão mas o endpoint realmente não faz, o provedor rejeita a requisição, não o Harness.

A solução de problemas está diretamente descrita na documentação:

  • MISSING_CREDENTIAL → armazene a chave do provedor pela página Models ou exporte a variável de ambiente referenciada
  • UNKNOWN_MODEL → escolha um modelo configurado, ou adicione o modelo que falta ao provedor personalizado
  • “Get available models returns 401” → verifique a chave. A descoberta de modelos chama o endpoint GET /models compatível com OpenAI. Se seu serviço não expõe isso, digite os modelos manualmente.
  • “Image rejected before send” → o modelo não declarou a modalidade image. Adicione input: [text, image].
  • “Provider rejects a request with an image” → o modelo alegou capacidade de visão que seu endpoint não tem. Remova image da lista e comece uma sessão nova (a imagem antiga permanece no registro de sessão e continua repetindo a mesma requisição).

Primeiros passos: três caminhos

Caminho 1: npx @deepseek-ai/dsh web

Instale o Node.js, execute um comando. A interface Web inicia em http://127.0.0.1:3080. É isso. Sem clone, sem build, sem pnpm.

Terminal window
npx @deepseek-ai/dsh web

Depois: Settings → Models → cole a chave API da DeepSeek. Escolha um workspace (o diretório onde o dsh foi invocado serve). Inicie uma sessão:

Resuma este repositório e identifique seus principais pacotes.

O agente lê e edita arquivos do workspace, executa comandos, delega trabalho e mantém um plano. Qualquer operação que precise de aprovação sob a política de permissões ativa abre um diálogo na interface Web antes de ser executada.

Caminho 2: Clonar e compilar da fonte

Terminal window
git clone https://github.com/deepseek-ai/deepseek-harness.git
cd deepseek-harness
pnpm install
pnpm run build
pnpm dsh web

Caminho 3: SDK Python

Requisitos: Python 3.10+, Linux x64 / Linux arm64 / macOS 14+ em arm64, um endpoint compatível com DeepSeek.

Terminal window
git clone https://github.com/deepseek-ai/deepseek-harness.git
cd deepseek-harness
python -m venv .venv
. .venv/bin/activate
python -m pip install deepseek-harness-sdk

Configure credenciais:

8000/v1
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.'

Execute uma tarefa contra um workspace isolado:

Terminal window
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 seu próprio código, o ponto de entrada do SDK é DeepSeekHarness como gerenciador de contexto:

from pathlib import Path
from 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 inicia preguiçosamente o runtime incluído e o reutiliza até que o bloco with seja encerrado. Reutilize o mesmo ID de sessão para preservar o processo Bash (diretório de trabalho, variáveis de ambiente, funções de shell). Use um ID de sessão novo para uma tarefa independente.

A composição mínima jsonrpc-agent é deliberadamente esparsa: apenas bash persistente e str_replace_editor como ferramentas voltadas para o modelo. Timeout do Bash: 300 segundos. Limite de saída do editor: 16.000 caracteres. Compactação de contexto desativada. O sistema de arquivos usa o backend local básico — os caminhos do editor podem endereçar qualquer coisa que o processo runtime consiga ver. A documentação avisa explicitamente: “Execute apenas dentro de um checkout descartável ou container.” O backend PTY persistente também requer um substrato de terminal POSIX — sem suporte a Windows para essa composição.

Escreva seu primeiro plugin

Tutorial: Seu primeiro plugin. Um plugin é um módulo TypeScript que exporta uma função apply:

import type { Context } from '@deepseek-ai/cordis'
export const name = 'hello-plugin'
export function apply(ctx: Context) {
console.log('[hello-plugin] plugin loaded!')
}

Registre-o em um patch cordis.yml:

- insert:
- id: hello
name: '/absolute/path/to/deepseek-harness/scratch-plugin/src/my-plugin.ts'

Inicialize com a sobreposição:

Terminal window
pnpm dsh web --patch ./scratch-plugin/cordis.yml

Limpeza automática é a função de destaque. Qualquer coisa registrada via ctx — listeners de evento, ferramentas, timers — é limpa quando o plugin é descarregado. Sem removeListener nem clearInterval manuais. Para limpeza explícita (conexões de rede), retorne um disposer a partir de ctx.effect().

As dependências são declaradas com inject:

export const name = 'my-tool-plugin'
export const inject = ['tools']
export function apply(ctx: Context) {
// ctx.tools está pronto aqui
}

O Cordis espera por cada serviço necessário antes de carregar o plugin.

Existem três formas de plugin: função (acima), objeto com apply e classe que estende Service. Use a forma de classe quando o próprio plugin fornece um serviço que outros plugins consomem.

Escreva sua primeira ferramenta

Tutorial: Construa uma ferramenta. Use 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 infere e valida args a partir de parameters. execute retorna o valor canônico declarado por output.schema. output.render converte esse valor canônico em conteúdo voltado para o modelo. Depois de um reinício com o patch, peça à interface Web: “Use the greet tool to greet Ada.” O modelo chama greet e recebe Hello, Ada!.

Os próximos passos do tutorial são configuração de plugin, a referência para criação de ferramentas (schemas aninhados, valores canônicos, trabalho em segundo plano, hooks de política, Code Mode, cards de UI) e camadas de capacidade (Definição de Serviço → Provedor de Serviço → divisão do pacote Consumidor).

Modos de entrada CLI

O comando @deepseek-ai/dsh é o lançador do produto. Quatro pontos de entrada:

Comando Propósito
dsh --profile <name> Inicializa o perfil nomeado sob \$DSH_HOME/profiles/<name>
dsh --profile headless "job" Executa uma sessão persistente nova, imprime a resposta final, sai
dsh web Alias de --profile web
dsh plugin --profile <name> <pnpm args> Gerencia os plugins de um perfil encaminhando para o pnpm

O diretório de invocação é a raiz padrão do workspace. Os perfis web e headless se inicializam automaticamente dos modelos entregues no primeiro uso. Qualquer outro perfil deve ser criado através de dsh plugin.

As flags do lançador vêm primeiro. O primeiro token que o lançador não reconhece vira os argumentos do app. Exemplo: dsh --profile web --port 8080 entrega --port 8080 para o app web, não para o lançador.

Um diretório de perfil contém um package.json (dependências de plugins fora da árvore, mais o manifesto do perfil dsh.profile com sua lista ordenada bundles) e um cordis.patch.yml (a própria camada de patch do usuário). A ordem de composição sobre uma raiz vazia é: o patch de cada bundle na ordem dsh.profile.bundles → o cordis.patch.yml do perfil → o \$DSH_HOME/cordis.patch.yml no nível home → sobreposições --patch. Use --dump-default-config e --dump-config para inspecionar a árvore composta sem inicializá-la.

Plugins da comunidade e ecossistema

Marque seu repositório de plugin com dsh-plugin no GitHub para ser encontrado. O site oficial liga diretamente para essa página de tópicos. Há também uma comunidade Discord do DeepSeek Harness para discussões.

O projeto usa GitHub Discussions para feedback e relatos de bugs. A documentação liga para CONTRIBUTING.md sobre o fluxo de desenvolvimento, architecture.md sobre design do sistema e AGENTS.md sobre convenções de codificação específicas para agentes.

Prévia para desenvolvedores — sim, vai quebrar

O README põe isso em MAIÚSCULAS: “HAVERÁ MUDANÇAS QUE QUEBRAM A COMPATIBILIDADE.”

Plugins e APIs centrais ainda evoluem. A página inicial diz diretamente: “O DeepSeek Harness permanece em prévia para desenvolvedores e continua sendo testado por desenvolvedores que constroem harnesses de agentes.”

Se você está construindo sobre isso, fixe um hash de commit, mantenha seus plugins enxutos frente ao catálogo de config e espere ter que retestar a cada aumento de rc. A limpeza automática de plugins e a injeção de dependência tornam o reteste menos doloroso do que em frameworks monolíticos, mas “prévia para desenvolvedores” significa exatamente o que diz.

O que faz isso diferente

A maioria dos frameworks de agente hoje começa com um loop de turnos e acrescenta extensibilidade como algo pensado depois. O Harness inverte: a extensibilidade é o framework, e o loop de turnos é só mais um plugin. O resultado observável são três coisas que normalmente não se consegue em um único pacote:

  • Troque qualquer coisa sem fork. Não gostou do sistema de ferramentas integrado? Substitua. Quer uma camada de roteamento LLM diferente? Troque o provedor. Tudo é resolvido através de chaves de serviço do Cordis.
  • Rastreabilidade por padrão. O registro somente-acréscimo não é um add-on de observabilidade. É como as sessões funcionam. Retomar, bifurcar, buscar e reproduzir usam todos o mesmo fluxo.
  • Predefinições componíveis, não flags de recurso. Os quatro modos (Standard / Code / Minimal / Creator) são só camadas ordenadas de patch de bundles de plugins. Você pode sobrepor suas próprias predefinições com YAML em vez de código.

Se essa abordagem vence sobre os SDKs monolíticos depende de se o ecossistema de plugins produzir ferramentas e provedores de terceiros suficientes para tornar a história de troca/recomposição real. Com 1,6k estrelas e 12k commits no primeiro dia, o momentum está claramente lá.

Referências

Share this page