needhelp
← Back to blog

DeepSeek Harness: Un Framework Agent Open Source Dove Letteralmente Tutto È un Plugin

by needhelp
DeepSeek
AI Agents
Open Source
Cordis
Plugin Architecture

Uno Stack Agent Completo, Rilasciato Su GitHub

DeepSeek ha rilasciato un’anteprima per sviluppatori di DeepSeek Harness (dsh) il 13 agosto 2026. Il repository si trova su deepseek-ai/deepseek-harness. A fine giornata aveva 1.6k stelle, 12.293 commit e 19 contributori — numeri che dicono che non è un progetto fatto nel fine settimana. La codebase è al 97.1% TypeScript, con 1.6% CSS e 0.7% Python. Versione del pacchetto alla pubblicazione: 0.1.0-rc.5.

La landing page è su deepseek.com/harness e la documentazione per sviluppatori vive su deepseek-harness.github.io/deepseek-harness.

Concesso in licenza sotto MIT.

La Descrizione in Una Riga

Dal README: “Agent = Model + Harness.”

Il modello è l’anima. Un harness consente a un agent di capire il proprio ambiente, usare strumenti e continuare a lavorare in contesti reali. La visione di DeepSeek: ogni capacità — modelli, strumenti, skill, sessioni, sandbox, storage, loop, scheduling e UI — è un plugin sostituibile.

Non è uno slogan. È imposto dall’architettura.

Cordis: Il Kernel Sotto Tutto

DeepSeek Harness è costruito su Cordis, un framework plugin incluso come dipendenza. Il design di Cordis è descritto in un articolo intitolato A Programming Paradigm for Spatiotemporal Composability.

L’intero framework si riduce a cinque idee:

  1. Un plugin è un oggetto che implementa Service. Può essere una funzione con inject e apply(ctx), o una sottoclasse di Service.
  2. Un contesto è un archivio di servizi. Un plugin rivendica una chiave stabile come ctx.tools, ctx.llm o ctx.sessions. Altri plugin trovano i servizi per chiave invece di importare implementazioni concrete.
  3. Dichiara la dipendenza dal servizio tramite inject. Un plugin che nomina i servizi richiesti aspetta che quei servizi esistano. Nessuna sequenza di avvio manuale.
  4. Eventi tipizzati per la comunicazione. Quattro modalità di dispatch: emit (fuoco e dimentica), waterfall (stile middleware con next()), parallel (tutti i listener girano in contemporanea) e serial (listener eseguiti in ordine con valori di ritorno).
  5. Le registrazioni sono effetti reversibili. Sezioni di prompt, schemi di strumenti, adattatori, listener — tutto si installa tramite ctx.effect() così ricaricamento e teardown li annullano in modo predicibile.

Il modello waterfall di Cordis è un middleware around. Un listener riceve (...args, next). Chiama next() per delegare al servizio successivo; ritorna senza next() per cortocircuitare. Per eventi a decisione singola, il cortocircuito è il design — un listener di policy può possedere una decisione del tutto.

Tutto È un Plugin (Sul Serio)

L’elenco dei plugin su deepseek.com/harness delinea tutta la superficie di capacità:

  • Models — i backend LLM (DeepSeek, OpenAI, Anthropic, Bedrock, Vertex, Azure, Codex, più qualsiasi endpoint compatibile con OpenAI)
  • Tools — ciò che il modello può chiamare
  • Skills — bundle di prompt e strumenti riutilizzabili
  • Sessions — gestione dello stato della conversazione
  • Sandboxes — dove gira il codice (PTY bash, backend locale danger-full-access, sandbox nativa basata su landlock)
  • Storage — persistenza della sessione
  • Loops — la logica di turno dell’agent
  • Scheduling — dispatch di subagent e task
  • UI — l’interfaccia web servita sulla porta 3080 di default

Uno sviluppatore può selezionare, scambiare o estendere ognuno di questi tramite configurazione — nessuna modifica al codice sorgente di DeepSeek Harness stesso. Il Catalogo Configurazione Plugin è auto-generato dal sorgente (scripts/gen-config-catalog.ts) e verificato fresco dalla CI, quindi ogni campo in un blocco config: di cordis.yml corrisponde esattamente al tipo di configurazione dichiarato da un plugin.

Quattro Modalità Runtime

La documentazione spedisce quattro preset. Ognuno mira a un caso d’uso diverso.

Standard Mode — Agent di codifica completo: modifica file, shell, ricerca file e web, skill, pianificazione, obiettivi, subagent e workflow. Questa è l’esperienza Web UI di default.

Code Mode — Tutto ciò che c’è in Standard, ma gli strumenti sono esposti tramite un Code Mode SDK così il modello può combinare operazioni multi-step in un unico programma TypeScript. Un programma generato dal modello sostituisce diversi round di chiamate a strumenti.

Minimal Mode — Solo due strumenti: una shell bash persistente e str_replace_editor. Serve per il benchmarking dei modelli in un ambiente ridotto all’osso. Nessuna skill, nessuna pianificazione, nessun subagent — pura capacità del modello contro una codebase reale.

Creator Mode — Costruito per scrivere preset agent personalizzati. Include tutte le capacità della modalità Standard più ispezione runtime, esperimenti di plugin Cordis in memoria e linee guida per la creazione di preset. È così che costruisci la quinta, sesta, settima modalità.

Ogni Esecuzione È Tracciabile

È qui che Harness si distingue dalla maggior parte degli strumenti per agent. Tutto ciò che il modello vede viene registrato in un log di sessione append-only:

  • Prompt di sistema
  • Output di ragionamento
  • Chiamate a strumenti e i loro risultati
  • Decisioni di scheduling dei subagent
  • Ogni iniezione di contesto

La Web UI ha una vista Trajectory dove si ispezionano questi record filtrati per fonte. Ripresa, fork, ricerca e riproduzione — tutte e quattro le operazioni lavorano sullo stesso flusso di eventi. Nessun database di trace separato, nessun passo di esportazione. Il JSONL di sessione è la fonte di verità.

Per l’SDK Python, la directory di sessione archivia JSONL non compresso contenente le richieste al modello assemblate e le chiamate a strumenti. L’esempio in examples/jsonrpc-agent/minimal.py mostra questo end to end.

Configurazione Modello: DeepSeek + Qualsiasi Cosa

La pagina di configurazione del modello (Configura modelli) ha tre strati.

DeepSeek Ufficiale. Apri Impostazioni → Modelli, incolla una chiave API DeepSeek, salva. La chiave è write-only. Dopo il salvataggio, la UI riceve un descrittore oscurato, mai il testo in chiaro. Le chiavi vivono in \$DSH_HOME/.credentials.yaml; la pagina delle impostazioni mantiene solo un riferimento alla credenziale.

Provider del catalogo. Clicca “Aggiungi provider”, scegli Anthropic o OpenAI, incolla la chiave. I provider che usano autenticazione nativa (Bedrock tramite credenziali AWS + regione, Vertex tramite progetto ADC, Azure tramite api-version, Codex tramite OAuth) non funzionano con un solo campo chiave API — ognuno ha bisogno del proprio percorso di autenticazione.

Provider personalizzati. Per un gateway aziendale, server self-hosted o qualsiasi provider non nel catalogo. Imposta un Provider ID minuscolo (permanente — richieste, sessioni salvate, default del modello e riferimenti alle credenziali lo usano tutti), URL base, protocollo API, credenziali e almeno un modello.

I modelli visuali richiedono un passo in più. Poiché un endpoint personalizzato non ha modo di pubblicizzare le modalità supportate, il form non può rilevare automaticamente il supporto alla visione. Aggiungi input: [text, image] al modello in \$DSH_HOME/settings.yaml. Se tutti i tuoi modelli personalizzati accettano immagini, imposta defaultInput: [text, image] una volta a livello di provider invece che per ogni modello. Il campo input è un’asserzione, non un controllo — se dichiari che un modello fa visione ma l’endpoint in realtà non lo fa, il provider rifiuta la richiesta invece di Harness.

La risoluzione dei problemi è scritta direttamente nella documentazione:

  • MISSING_CREDENTIAL → salva la chiave del provider tramite la pagina Modelli o esporta la variabile env referenziata
  • UNKNOWN_MODEL → scegli un modello configurato, o aggiungi il modello mancante al provider personalizzato
  • “Get available models restituisce 401” → controlla la chiave. Il discovery dei modelli chiama l’endpoint compatibile con OpenAI GET /models. Se il tuo servizio non lo espone, inserisci i modelli manualmente.
  • “Immagine rifiutata prima dell’invio” → il modello non ha dichiarato la modalità image. Aggiungi input: [text, image].
  • “Il provider rifiuta una richiesta con un’immagine” → il modello ha dichiarato una capacità di visione che il suo endpoint non ha effettivamente. Rimuovi image dall’elenco e avvia una sessione fresca (la vecchia immagine rimane nel log della sessione e continua a ripetere la stessa richiesta).

Per Iniziare: Tre Percorsi

Percorso 1: npx @deepseek-ai/dsh web

Installa Node.js, esegui un comando. La Web UI parte su http://127.0.0.1:3080. Fine. Nessun clone, nessun build, nessun pnpm.

Terminal window
npx @deepseek-ai/dsh web

Poi: Impostazioni → Modelli → incolla la chiave API DeepSeek. Scegli la workspace (va bene la directory dove hai invocato dsh). Avvia una sessione:

Riassumi questo repository e identifica i suoi pacchetti principali.

L’agent legge e modifica i file della workspace, esegue comandi, delega il lavoro e mantiene un piano. Qualsiasi operazione che necessita approvazione sotto la policy di autorizzazione attiva fa apparire un dialogo nella Web UI prima dell’esecuzione.

Percorso 2: Clona e Builda dal Sorgente

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

Percorso 3: SDK Python

Requisiti: Python 3.10+, Linux x64 / Linux arm64 / macOS 14+ su arm64, un endpoint compatibile con 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

Imposta le credenziali:

8000/v1
export DEEPSEEK_API_KEY=sk-your-key-here
# Opzionale:
# export DSH_MODEL=deepseek-v4-flash
# export DSH_SYSTEM_PROMPT='You are a helpful software engineer assistant.'

Esegui un task contro una workspace isolata:

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."

Per il tuo codice, l’entrypoint dell’SDK è DeepSeekHarness come context manager:

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 avvia pigramente il runtime incluso e lo riusa finché il blocco with non esce. Riusa lo stesso ID sessione per preservare il processo Bash (directory di lavoro, variabili env, funzioni di shell). Usa un ID sessione fresco per un task indipendente.

La composizione minimal di jsonrpc-agent è deliberatamente sparsa: solo bash persistente e str_replace_editor come strumenti rivolti al modello. Timeout Bash 300 secondi. Limite di output dell’editor 16.000 caratteri. Compattazione del contesto disabilitata. Il filesystem usa il backend locale nudo — i percorsi dell’editor possono indirizzare qualsiasi cosa il processo di runtime possa vedere. La documentazione avvisa esplicitamente: “Esegui solo dentro un checkout usa-e-getta o un container.” Anche il backend PTY persistente richiede un substrato terminale POSIX — nessun supporto a Windows per questa composizione.

Scrivi il Tuo Primo Plugin

Tutorial: Il tuo primo plugin. Un plugin è un modulo TypeScript che esporta una funzione apply:

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

Registralo in una patch cordis.yml:

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

Avvia con l’overlay:

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

La pulizia automatica è la caratteristica killer. Qualsiasi cosa registrata tramite ctx — listener di eventi, strumenti, timer — viene pulita quando il plugin si scarica. Nessun removeListener o clearInterval manuale. Per la pulizia esplicita (connessioni di rete), restituisci un disposer da ctx.effect().

Le dipendenze sono dichiarate con inject:

export const name = 'my-tool-plugin'
export const inject = ['tools']
export function apply(ctx: Context) {
// ctx.tools is ready here
}

Cordis aspetta che ogni servizio richiesto sia pronto prima di caricare il plugin.

Esistono tre forme di plugin: funzione (sopra), oggetto con apply e classe che estende Service. Usa la forma a classe quando il plugin stesso fornisce un servizio che altri plugin consumano.

Scrivi il Tuo Primo Strumento

Tutorial: Costruisci uno strumento. Usa defineTool da @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 inferisce e valida args da parameters. execute restituisce il valore canonico dichiarato da output.schema. output.render converte quel valore canonico in contenuto rivolto al modello. Dopo un riavvio con la patch, chiedi alla Web UI: “Usa lo strumento greet per salutare Ada.” Il modello chiama greet e riceve Hello, Ada!.

I passi successivi del tutorial sono configurazione plugin, il riferimento per la scrittura di strumenti (schemi annidati, valori canonici, lavoro in background, hook di policy, Code Mode, carte UI) e stratificazione delle capacità (definizione servizio → fornitore servizio → divisione pacchetto consumatore).

Modalità di Ingresso CLI

Il comando @deepseek-ai/dsh è il launcher del prodotto. Quattro punti di ingresso:

Comando Scopo
dsh --profile <name> Avvia il profilo nominato sotto \$DSH_HOME/profiles/<name>
dsh --profile headless "job" Esegue una nuova sessione persistente, stampa la risposta finale, esce
dsh web Alias di --profile web
dsh plugin --profile <name> <pnpm args> Gestisce i plugin di un profilo inoltrando a pnpm

La directory di invocazione è la radice della workspace di default. I profili web e headless si auto-inizializzano dai template forniti al primo uso. Qualsiasi altro profilo deve essere creato tramite dsh plugin.

I flag del launcher vengono prima. Il primo token che il launcher non riconosce diventa argomento dell’app. Esempio: dsh --profile web --port 8080 passa --port 8080 all’app web, non al launcher.

Una directory di profilo contiene un package.json (dipendenze plugin fuori dall’albero, più il manifest del profilo dsh.profile con il suo elenco ordinato bundles) e un cordis.patch.yml (il livello patch dell’utente). L’ordine di composizione su una radice vuota è: patch di ogni bundle nell’ordine di dsh.profile.bundlescordis.patch.yml del profilo → \$DSH_HOME/cordis.patch.yml a livello home → overlay --patch. Usa --dump-default-config e --dump-config per ispezionare l’albero composto senza avviarlo.

Plugin della Comunità ed Ecosistema

Tagga il tuo repo plugin con dsh-plugin su GitHub per la reperibilità. Il sito ufficiale linka direttamente a quella pagina di topic. C’è anche una comunità Discord di DeepSeek Harness per le discussioni.

Il progetto usa GitHub Discussions per feedback e segnalazioni di bug. La documentazione linka a CONTRIBUTING.md per il flusso di sviluppo, architecture.md per il design del sistema e AGENTS.md per le convenzioni di codifica specifiche degli agent.

Anteprima per Sviluppatori — Sì, Si Romperà

Il README lo mette tutto in MAIUSCOLO: “CI SARANNO MODIFICHE CHE ROMPONO LA COMPATIBILITÀ.”

I plugin e le API core stanno ancora evolvendo. La landing page lo dice direttamente: “DeepSeek Harness rimane in anteprima per sviluppatori ed è ancora in fase di test da parte degli sviluppatori che costruiscono harness per agent.”

Se stai costruendo sopra di esso, blocca un hash di commit, mantieni i tuoi plugin sottili rispetto al catalogo di configurazione e aspettati di ritestare a ogni bump di rc. La pulizia automatica dei plugin e l’iniezione di dipendenze rendono il ritestare meno doloroso che con i framework monolitici, ma “anteprima per sviluppatori” significa esattamente quello che dice.

Cosa lo Rende Diverso

Oggi la maggior parte dei framework per agent inizia con un loop di turno e imbullonna l’estensibilità come dopopenza. Harness lo ribalta: l’estensibilità è il framework, e il loop di turno è solo un altro plugin. Il risultato osservabile sono tre cose che di solito non ottieni in un solo pacchetto:

  • Scambia qualsiasi cosa senza un fork. Non ti piace il sistema di strumenti integrato? Sostituiscilo. Vuoi un layer di routing LLM diverso? Scambia il provider. Tutto si risolve tramite le chiavi di servizio Cordis.
  • Tracciabilità di default. Il log append-only non è un add-on di osservabilità. È come funzionano le sessioni. Ripresa, fork, ricerca e riproduzione usano tutti lo stesso flusso.
  • Preset componibili, non flag di funzionalità. Le quattro modalità (Standard / Code / Minimal / Creator) sono solo livelli ordinati di patch di bundle di plugin. Puoi stratificare i tuoi preset sopra con YAML invece che con codice.

Se questo approccio vincerà contro gli SDK monolitici dipende dal fatto che l’ecosistema dei plugin produca abbastanza strumenti e provider di terze parti per rendere reale la storia dello scambio/ricomposizione. Con 1.6k stelle e 12k commit il giorno uno, lo slancio c’è chiaramente.

Riferimenti

Share this page