DeepSeek Harness (dsh): instalei o agente de codificação open-source da DeepSeek, conectei-o ao meu aplicativo de chat e fiz benchmark dele
- Categoria
- IA e LLM Local
- Publicado em
- 18 agosto 2026
- Por
- Jacob Lloyd — escrito com ajuda de IA, depois do projeto
- Tempo de leitura
- 16 min de leitura
Em termos simples: A DeepSeek lançou um 'agente de codificação' gratuito e open-source — um programa que lê seu projeto, edita arquivos e executa comandos para você, como o Claude Code. Este artigo mostra como o instalei no meu PC Linux, fiz com que ele iniciasse automaticamente, conectei-o ao meu aplicativo de chat caseiro e o testei em pequenas tarefas reais de codificação, tanto com os modelos em nuvem da DeepSeek quanto com um modelo rodando no meu próprio hardware. Funcionou, foi barato, e há algumas arestas.
Em 13 de agosto de 2026, a DeepSeek lançou o DeepSeek Harness — dsh — um agente de codificação licenciado sob MIT construído sobre a ideia de que tudo é um plugin: o adaptador de modelo, as ferramentas, o sandbox, até o loop do agente. Ele atingiu 95.000 estrelas no GitHub em dois dias. Instalei-o na minha máquina caseira na mesma semana, dei a ele um lugar ao lado do Reasonix, meu agente de codificação existente, dentro do DisPatch, apontei-o tanto para os modelos na nuvem da DeepSeek quanto para um modelo no meu próprio setup com GPU, e o passei por uma pequena suíte de tarefas. Isto é o que foi preciso, o que custou e onde doeu.
tl;dr
- O que é: um agente da classe do Claude Code (lê/edita arquivos, executa shell, mantém um plano, gera subagentes) distribuído como um pacote npm. Dois modos: uma interface web em
127.0.0.1:3080e um modo headless de execução única que imprime uma resposta e encerra — feito para scripts e outros agentes. - Quanto custa: o software é gratuito. Todo o meu benchmark de 5 tarefas custou cerca de 3 centavos no V4-Flash e cerca de 7 centavos no V4-Pro nas tarifas de pico; nada no modelo local.
- O que você precisa: Node.js 22.19+/24, uma chave de API da DeepSeek ou qualquer servidor compatível com OpenAI (usei os dois).
- Com o que você fica:
dsh --profile headless "fix the failing test"em qualquer pasta de projeto, uma interface web como serviço em segundo plano, troca de modelo ao editar um arquivo YAML e — no meu caso — um bot "DeepSeek Harness" no meu aplicativo de chat com um botão Run. - O resultado: 15/15 aprovações em V4-Flash, V4-Pro e um Gemma-4-26B local, 2–18 s por tarefa. Prévia para desenvolvedores — o README adverte em maiúsculas que as coisas vão quebrar entre versões, e eu esbarrei em algumas das arestas listadas abaixo.
O percurso, do básico ao avançado
Os passos 1–3 dão a você um agente funcional em dez minutos. Os passos 4–5 são o que fiz por cima para que outros softwares — e outros agentes — possam chamá-lo.
O que você acaba tendo
O que eu realmente uso é o modo headless. De dentro de um diretório de projeto:
$ cd ~/Projects/dsh-playground
$ dsh --profile headless "Create fizz.py that prints FizzBuzz for 1..15 and run it; reply with the program output only."
1
2
Fizz
4
Buzz
…
FizzBuzz
$ echo $?
0
Seis segundos, arquivo criado, programa executado, resposta impressa, código de saída 0. Ele não escreve nada fora da pasta em que você o iniciou (modo de permissão padrão workspace-write), imprime apenas a mensagem final no stdout e persiste cada execução para que você possa abri-la depois na interface web e ler exatamente o que ele fez — cada chamada de ferramenta, cada contagem de tokens.
A interface web é o layout familiar de 2026 — sessões à esquerda, chat no meio, uma página de configurações para modelos — com um bom hábito: a chave da API é colada na página de configurações, nunca em um arquivo de configuração. A minha roda como um serviço de usuário do systemd e está incorporada no meu aplicativo de chat ao lado do Reasonix:
Passo 1: instalar (dois minutos)
Um pacote npm. Eu mantenho um prefixo Node privado para ferramentas de agente, para que nada caia na árvore do sistema — em uma distro imutável como a Bluefin, esse é o único lugar sensato para isso, de qualquer forma — mas uma instalação global simples é o mesmo comando:
npm install -g @deepseek-ai/dsh
dsh --version # 0.1.0-rc.7 at the time of writing
dsh web # starts the UI, prints http://127.0.0.1:3080
Abra a URL, vá para Configurações → Modelos, cole sua chave DeepSeek e salve. Isso grava ~/.dsh/.credentials.yaml (modo 0600) e a rota do modelo funciona imediatamente, sem reiniciar. Para automatizar, o arquivo é um mapeamento YAML simples — DEEPSEEK_API_KEY: sk-… — e eu escrevi o meu a partir do arquivo de env que meus outros serviços já leem, então o segredo existe em mais um lugar, mas nunca em um histórico de shell ou em um arquivo de unit.
Duas coisas que vale a pena saber antes de continuar:
- A telemetria está desativada por padrão (
DSH_TELEMETRY_MODEnão definido = desativada). Eu verifiquei a configuração enviada, não o material de marketing; o exportador OTLP existe, só não está ligado. - O sandbox é real, mas limitado.
workspace-writeconfina as escritas ao diretório a partir do qual você o iniciou. As leituras não são confinadas — a documentação diz isso claramente — então não o execute a partir do seu diretório pessoal para uma tarefa real e não o aponte para pastas com segredos.
Passo 2: executá-lo como um serviço
A interface web é um processo Node de longa duração; eu queria que ela estivesse ativa no login, sem terminal, apenas loopback. Uma unit do systemd --user resolve isso:
# ~/.config/systemd/user/dsh-web.service
[Unit]
Description=DeepSeek Harness web UI (dsh web) on 127.0.0.1:3080
After=network.target
[Service]
WorkingDirectory=%h
Environment=DSH_HOME=%h/.dsh
Environment=DSH_PERMISSION_MODE=workspace-write
ExecStart=/usr/local/bin/dsh web --host 127.0.0.1 --port 3080 # `which dsh`
Restart=on-failure
RestartSec=3
[Install]
WantedBy=default.target
systemctl --user daemon-reload
systemctl --user enable --now dsh-web.service
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:3080/ # 200
WorkingDirectory é a raiz do espaço de trabalho padrão da interface web, mas a interface ainda faz você escolher um espaço de trabalho explicitamente antes de permitir que você digite. Bom padrão. A CLI também recusa --host 0.0.0.0 — os autores descrevem a vinculação a todas as interfaces como "intencionalmente ainda não suportada", e como a interface não tem autenticação alguma, concordo. Quer acessá-la de outra máquina? Coloque um proxy reverso com autenticação na frente, ou alcance o navegador do host pela sua área de trabalho remota (é o que eu faço).
Etapa 3: modelos — um arquivo YAML, recarregado a quente
~/.dsh/settings.yaml contém o modelo padrão e quaisquer provedores adicionais, e o dsh o relê para a próxima solicitação — sem reiniciar, sem novo login. O meu:
agent-default-model:
provider: deepseek-official
model: deepseek-v4-flash # or deepseek-v4-pro
llm-deepseek:
reasoningEffort: high # off | low | high | max
# A local OpenAI-compatible server (mine is llama.cpp-based on a GPU rig).
llm-pi-ai:
providers:
buildpc:
displayName: StudioForge (GPU rig)
apiKeyEnv: STUDIOFORGE_PLACEHOLDER_KEY # a reference, not a value
api: openai-completions
baseURL: http://my-gpu-rig:1234/v1 # your server; mine sits on the tailnet
defaultContextWindow: 65536
models:
- id: unsloth/gemma-4-26B-A4B-it-qat-GGUF/gemma-4-26B-A4B-it-qat-UD-Q4_K_XL
name: Gemma 4 26B-A4B (rig)
Dois detalhes que me custaram dez minutos cada: apiKeyEnv é uma referência resolvida a partir de .credentials.yaml ou do ambiente, nunca um literal — e um servidor local sem chave ainda precisa de alguma credencial referenciada, porque o cliente compatível com OpenAI exige um bearer token. Um valor de espaço reservado em .credentials.yaml resolve isso. E o ID do provedor (buildpc) é permanente depois que as sessões o referenciam; para renomear, adicione um novo.
Como o arquivo é a interface inteira, “mudar o dsh para o modelo local” é uma edição de duas linhas que qualquer script — ou qualquer outro agente — pode fazer. Meu agente principal redireciona o harness para um modelo local gratuito para tarefas rotineiras e de volta para o V4-Pro para problemas difíceis, sem tocar em mais nada.
Etapa 4: ao lado do Reasonix no DisPatch
Eu já tinha o Reasonix vivendo dentro do DisPatch como um pseudo-bot: clique nele e o painel de bate-papo vira um terminal executando a TUI dele sobre um PTY. Eu queria o dsh ao lado dele. O problema: o pacote oficial não tem TUI. Plugins de terceiros no estilo “Claude Code TUI” existem no npm, mas tinham quatro dias de vida com dependências workspace:* quebradas, e um pacote não revisado com acesso ao shell não vai para um servidor de família. Então o painel do dsh é construído a partir do que o pacote oficial oferece:
- a interface web embutida em um iframe (ela não envia cabeçalhos de bloqueio de frame), mostrada apenas quando o navegador consegue alcançar o loopback do host — um celular na tailnet recebe uma explicação simples;
- Iniciar / Reiniciar / Parar para a unit do systemd, além da saúde;
- um menu suspenso de Modelo que reescreve
agent-default-modelnaquele arquivo YAML; - uma aba Trabalhos headless: digite uma tarefa, escolha uma pasta dentro do home, pressione Executar. O servidor executa
dsh --profile headless "…"como uma lista de argumentos fixa (sem shell — a tarefa é um único elemento argv, então uma tarefa contendo; rm -rf /é apenas texto), um trabalho por vez, e mantém um histórico curto com cada resposta final.
dsh --profile headless; a resposta é a última coisa que o dsh imprimiu. Três execuções reais: 5 s, 5 s, 19 s.Tudo nesse painel fica atrás do desbloqueio de administrador do aplicativo — um trabalho headless é execução arbitrária de código, e os dispositivos familiares bloqueados nunca ficam sabendo que o painel existe. Se você conectar o dsh a algo seu, copie isso: trate “executar uma tarefa” exatamente como trata um shell.
dsh vs Reasonix, lado a lado
Ambos são agentes com formato Claude Code que cobram por token na DeepSeek. Eles diferem em quem os fez e qual superfície oferecem:
| DeepSeek Harness (dsh) | Reasonix | |
|---|---|---|
| Quem | DeepSeek, oficial, MIT | Terceiros, estilo Claude-Code |
| Superfície | Interface web + one-shot headless; sem TUI | TUI no terminal (sessão interativa em um PTY) |
| Chamar de um script | dsh --profile headless "…" — uma resposta, código de saída | Feito para um humano no comando; uso via script é incômodo |
| Troca de modelo | Edite o settings.yaml, recarregado a quente; sem flag --model | Camadas no config.toml (flash/pro) + roteamento por skill |
| Modelos locais | Qualquer servidor compatível com OpenAI via um bloco de provider | A mesma tríplice: base URL, env da chave, ids de modelo |
| Extensibilidade | Tudo é um plugin (modelo, ferramentas, sandbox, loop) | Subagentes, skills, memória por projeto |
| No meu DisPatch | iframe + controles da unit + aba de trabalhos headless | Terminal xterm.js sobre um PTY |
| Maturidade | Developer preview (rc.7), quebras entre versões | v1.18, auto-atualizador, configuração estável |
Na prática: o Reasonix é o que eu abro quando vou sentar com o agente; o dsh é o que meus outros softwares chamam. Essa divisão é o motivo de ambos permanecerem.
O benchmark: 5 tarefas, 3 modelos, 15/15
Nada de científico — cinco tarefas pequenas que eu realmente entregaria a um agente de codificação, cada uma em uma pasta scratch nova, cada uma verificada automaticamente (o arquivo existe e roda? os testes passam sem tocar no arquivo de teste? a renomeação deixou zero referências antigas?). O tempo total (wall time) é o processo inteiro, incluindo o system prompt de ~7.500 tokens; os tokens vêm do log de sessão do próprio dsh.
| Tarefa | V4-Flash | V4-Pro | Gemma-4-26B (local, na máquina) |
|---|---|---|---|
| Responder "PONG" (inicialização + uma chamada) | ✅ 2,1 s | ✅ 2,8 s | ✅ 13,2 s* |
| Escrever e executar FizzBuzz | ✅ 5,3 s · 2 ferramentas | ✅ 8,4 s · 2 ferramentas | ✅ 4,9 s · 2 ferramentas |
| Corrigir 2 bugs para os testes unitários passarem (testes intactos) | ✅ 11,7 s · 8 ferramentas | ✅ 15,8 s · 7 ferramentas | ✅ 10,4 s · 8 ferramentas |
| Resumir uma base de código de 6 módulos (<150 palavras) | ✅ 8,9 s · 9 ferramentas | ✅ 10,9 s · 7 ferramentas | ✅ 12,1 s · 7 ferramentas |
| Renomear uma função em 3 arquivos + testes, comprovar que está verde | ✅ 15,1 s · 14 ferramentas | ✅ 18,2 s · 12 ferramentas | ✅ 12,2 s · 11 ferramentas |
| Tempo total (wall time) | 43 s | 56 s | 53 s |
| Tokens (entrada sem cache / leitura de cache / saída) | 42,6k / 136k / 4,5k | 41,4k / 107k / 3,2k | 40,5k / 237k / 5,6k |
| Custo nas tarifas de pico (fora do pico é a metade) | ≈ US$ 0,027 | ≈ US$ 0,072 | US$ 0 (eletricidade) |
*primeira chamada depois que o modelo foi carregado a frio na máquina; as tarefas seguintes mostram a velocidade já aquecida. Preços conforme a página de preços da DeepSeek em 2026-08-18: Flash US$ 0,014 / US$ 0,44 / US$ 1,32 por milhão (cache hit / cache miss / saída), Pro US$ 0,044 / US$ 1,32 / US$ 3,96.
O que a tabela diz:
- O cache de prompt é o que paga a conta. Cada tarefa gasta ~7,5 mil tokens de system prompt, mas depois da primeira etapa é quase tudo leitura de cache a 3% do preço de cache miss. Tarefas de várias etapas saem baratas porque o harness mantém o prefixo estável.
- O Pro usou menos etapas e menos ferramentas para o mesmo resultado (12 contra 14 chamadas de ferramenta na renomeação; 3 contra 4 etapas no resumo). Neste conjunto, o Flash foi mais rápido e custou um terço do preço, então continua sendo o meu padrão.
- O modelo local se saiu bem. O Gemma-4-26B (um MoE de 4B ativos, quantização Q4, servido pelo llama.cpp em duas RTX 5090s) passou em tudo, com mais etapas e mais tokens, mas com tempo total competitivo. Foi a primeira vez que um modelo local foi uma opção real para as tarefas daqui, em vez de uma novidade — embora cinco tarefas pequenas não digam nada sobre uma refatoração de 40 arquivos.
Depois, o teste do "trabalho comum": apontei o agente para o repositório deste site e pedi que lesse o runbook do projeto, executasse o build-and-link-check e fizesse um relatório — sem publicar, sem editar. Ele leu o runbook, executou o comando certo, informou as linhas exatas da verificação (290 páginas, 1.752 imagens, nenhum link quebrado), o tempo de build e — sem que eu pedisse — notou que o runbook ainda dizia "288 páginas" e sinalizou a divergência. Cinquenta e três segundos. É esse o tipo de tarefa de baixo risco que eu passo adiante o dia inteiro.
O teste divertido: construa um brinquedo para mim
Benchmarks são uma coisa; eu também queria ver o que ele faz com um briefing criativo aberto. Então: "faça uma versão interativa em pixel art do logotipo deste site — JavaScript puro, embutível em qualquer lugar, passar o mouse faz algo físico, clicar faz algo legal, sem dependências, teste você mesmo." Aqui está o que ele construiu — está no ar, pode testar:
prefers-reduced-motion.
Como foi, honestamente:
- Tentativa 1 (V4-Flash): um loop de 10 minutos, sem arquivos. O briefing permitia um bitmap desenhado à mão ou um procedural. Ele escolheu desenhar à mão um bitmap 40×40 dentro do próprio raciocínio e caiu em um loop degenerado — o log da sessão tem centenas de linhas de
################/....— até que meu timeout o encerrasse. Cerca de 2¢ desperdiçados. Lição: nunca deixe um modelo desenhar pixels à mão na cabeça. - Tentativa 2 (V4-Flash, briefing alterado para "rasterizar a partir da geometria, sem bitmaps"): 25 minutos, tudo entregue. 100 etapas de modelo, 201 chamadas de ferramenta, 172 mil tokens de saída (123 mil deles de raciocínio), 16,3M tokens de leitura de cache — ≈ 49¢ a preços de pico. Ele escreveu um
ll-pixel-logo.jsde 399 linhas com uma API de um único global e opçõesdata-, uma página de demonstração, um README, um teste unitário Node para o rasterizador e — sem ser solicitado — um script Playwright que captura a demo em três tamanhos. Ele atingiu meu limite de 25 minutos enquanto polia o README, então o código de saída foi timeout, mas o trabalho estava concluído. Códigos de saída mentem nos dois sentidos. - A arte: o anel e os dois L inclinados são reconhecidos como a marca à primeira vista; eles são mais encorpados e mais parecidos com um Z do que o logotipo real, e eu passaria dez minutos ajustando as constantes de cisalhamento antes de usá-lo a sério. Não ajustei — o que você vê está intocado.
- Incorporá-lo aqui levou uma linha porque o CSP do site é
script-src 'self'e o widget não faz nenhuma requisição de rede. Isso estava no briefing; ele honrou isso.
Gotchas
- Prévia para desenvolvedores, e isso está em letras maiúsculas.
0.1.0-rc.7na instalação; a rc.6 foi três dias antes. Perfis, chaves de configuração e o layout de plugins podem mudar. Fixe a versão em qualquer automação e rode um teste de fumaça após cada atualização. - O modo headless é silencioso até terminar. Nada é transmitido para o stdout — uma tarefa longa parece travada. Leia o log da sessão (
~/.dsh/sessions/…/session.jsonl.zstd, JSONL comprimido com zstd) ou acompanhe-o na interface web. E o código de saída 0 significa "a rodada foi concluída", não "a tarefa foi bem-sucedida". Confira o resultado. - Não há flag
--modelno modo headless. O modelo padrão vem dosettings.yaml; altere-o lá (hot-reload) ou na interface. - Servidores locais sem chave de API precisam de uma credencial fictícia referenciada por
apiKeyEnv, e os IDs de provedores são permanentes. Já abordamos isso acima; vai te morder. - Os assets da interface web usam caminhos absolutos (
/assets/…,/api), então não dá para montá-la em um subcaminho atrás do seu próprio proxy reverso sem reescrever; incorpore-a ou dê a ela um hostname próprio. - A localidade da interface segue o seu navegador — o index.html enviado diz
lang="zh-CN", e a primeira coisa que você vê é uma caixa de diálogo "Internal Testing Notice". Clique em Continuar; tudo depois disso estava em inglês para mim. - A instalação executa scripts pós-instalação (node-pty, koffi, protobufjs). O npm avisa sobre isso. Nada malicioso que eu pudesse ver, mas é código nativo compilando no seu prefixo — mais um motivo para mantê-lo em um prefixo privado, não no do sistema.
- Apenas Node 22.19+ ou 24. Versões LTS mais antigas se recusam a executá-lo.
Onde isso me deixa
Ganhou seu lugar em uma tarde. O modo headless é a forma certa para um agente de codificação que outros softwares chamam — um comando, uma resposta, um código de saída, um log auditável — e a definição do modelo por YAML significa que minha stack de agentes pode apontá-lo para qualquer cérebro que sirva para o trabalho. Se você já executa um servidor de modelo local, experimente as mesmas cinco tarefas; dez centavos de crédito de API e uma pasta de rascunho são tudo o que é preciso.
Relacionados: Reasonix (o outro agente de codificação deste artigo), DeepSeek Everywhere (integrando DeepSeek ao Claude Code e a uma stack de agentes), DisPatch (o aplicativo de chat onde o painel está), e bench-llm (avaliando modelos locais com mais rigor do que fiz aqui).