In questo articolo

🔍 Cos'è coder_eval e cosa non è

coder_eval si autodefinisce «la palestra degli agenti di coding»: un framework riproducibile per valutare, benchmarkare e confrontare in A/B agenti di coding. Oggi supporta Claude Code, OpenAI Codex e Google Antigravity (Gemini), con un plugin SPI per aggiungerne altri. La meccanica è semplice da raccontare: prende un task scritto in YAML, prepara una sandbox, lancia l'agente vero con il suo giro di tool, e poi controlla i file e i comandi che sono usciti da quel giro.

La distinzione che conta è con i benchmark a dataset fisso. SWE-bench o SkillsBench misurano modelli su un insieme canonico di problemi e producono una classifica; coder_eval non ha classifica e non ha dataset proprio, valuta i task che scrivi tu. È anche diverso dagli strumenti che giudicano l'output testuale di un modello: qui non si valuta una stringa, si valuta il risultato di un agente che ha letto, scritto ed eseguito cose in una directory.

La carta d'identità del repo
repo       UiPath/coder_eval
cosa       valuta e benchmarka agenti di coding e le loro skill
agenti     claude-code · codex · antigravity (Gemini) · plugin SPI
come       task YAML → sandbox → agente reale → criteri pesati 0.0–1.0
chicca     skill_triggered: la skill è davvero scattata? sì/no + metriche
licenza    Apache-2.0 · Python 3.13+ · pip install coder-eval

Repo ufficiale · UiPath/coder_eval

Progetto giovane (poche stelle, ma pacchetto pubblicato su PyPI e action sul Marketplace GitHub).

📄 Un task è un file YAML, niente di più

L'unità di lavoro è un file YAML con quattro cose: un prompt, la configurazione dell'agente, una sandbox e i criteri di successo. I campi obbligatori sono `task_id`, `description`, `initial_prompt` e almeno un criterio; `agent` e `sandbox` sono opzionali e, se omessi, vengono risolti dal layer degli esperimenti. Ci sono anche `tags` per filtrare le esecuzioni, `reference` per una soluzione di riferimento, `pre_run` e `post_run` per comandi prima e dopo l'agente.

La sandbox ha due driver: `tempdir`, il default, che prepara una directory temporanea con un ambiente Python; e `docker`, il container, l'unico che la documentazione considera accettabile per task non fidati — e lo dice esplicitamente, `tempdir` non è un confine di sicurezza. Sul lato agente si configurano `type`, `model`, `permission_mode` (`acceptEdits` è quello consigliato per le valutazioni) e la lista di tool ammessi.

Un task minimo · tasks/hello_world.yaml
task_id: "hello_world"
description: "Create a Python script that prints Hello, World!"
initial_prompt: "Create hello.py that prints 'Hello, World!'"

agent:
  type: "claude-code"
  permission_mode: "acceptEdits"
  allowed_tools: ["Read", "Write", "Bash"]

sandbox:
  driver: "tempdir"
  python: {}

success_criteria:
  - type: "file_exists"
    path: "hello.py"
    description: "hello.py must be created"
  - type: "run_command"
    command: "python hello.py"
    timeout: 10
    description: "Script must execute successfully"

Task Definition Guide · schema completo e tipi di criterio

Esempio dalla documentazione ufficiale: il task descrive il risultato atteso, non i passi da eseguire.

🎯 skill_triggered: la skill è scattata o no?

Questo è il criterio per cui vale la pena guardare il progetto. `skill_triggered` è un classificatore binario che scandisce le trace del run e cerca due segnali alternativi: una chiamata esplicita al tool `Skill` il cui parametro combacia con `skill_name` — i prefissi di namespace vengono rimossi, quindi `uipath-agents` intercetta anche `uipath-coded-agents:uipath-agents` — oppure, per un agente che il tool `Skill` non ce l'ha (Codex, per esempio), un comando che legge i file della skill da disco sotto `skills/<skill_name>/`.

L'etichetta osservata è «yes» se uno dei due segnali compare, «no» altrimenti; quella attesa è «yes» solo se `expected_skill` combacia con `skill_name`. Il punteggio è binario: 1.0 quando osservato e atteso coincidono, 0.0 altrimenti. Il pattern consigliato è etichettare ogni riga di un dataset con la skill che dovrebbe scattare — stringa vuota per le righe negative, dove la skill non deve partire — e impilare un criterio `skill_triggered` per skill sullo stesso dataset. Ognuno produce la propria matrice di confusione dalle stesse trace, e si può mettere una soglia su accuracy, F1 o precision/recall per etichetta.

Il criterio skill_triggered con soglie di suite
- type: "skill_triggered"
  description: "uipath-agents activation"
  skill_name: uipath-agents          # la skill da rilevare
  expected_skill: "${row.expected_skill}"   # attesa della riga; "" = negativa
  suite_thresholds:
    recall.yes: 0.70
    precision.yes: 0.80

Documentazione del criterio skill_triggered

Il criterio richiede telemetria reale: senza turn records restituisce 0.0 e un errore, non un falso verde.

⚖️ Criteri pesati, non un pass/fail secco

Ogni criterio ha un `weight` (default 1.0) e una `pass_threshold` (default 0.9). Il task passa quando tutti i criteri raggiungono la propria soglia; in parallelo viene sempre calcolato un punteggio pesato con la formula `weighted_score = sum(score * weight) / sum(weight)`, utile per vedere il trend anche quando l'esito booleano è già noto. È il punto in cui questo approccio si stacca dagli script fatti in casa: il credito parziale esiste, e un peggioramento si vede prima che diventi un fallimento.

I tipi di criterio coprono un ventaglio ampio. Ci sono i controlli statici sui file (`file_exists`, `file_contains`, `file_check` con includes/excludes/regex, `file_matches_regex`, `json_check` con asserzioni JMESPath e JSON Schema), quelli sull'esecuzione (`run_command` con exit code e match su stdout, `command_executed`), il confronto con una soluzione di riferimento (`reference_comparison` con soglia di similarità) e i due giudici LLM: `llm_judge`, che valuta con una rubrica testuale, e `agent_judge`, che è un intero agente secondario con difese di sicurezza obbligatorie sui path sensibili.

Due modi di verificare una skill

A occhio, come si fa di solito

  • Provo tre prompt e vedo se «sembra» che scatti
  • Il modello cambia e non me ne accorgo
  • Due skill con descrizioni simili si rubano i trigger
  • Nessun numero da confrontare fra una settimana e l'altra

Con un criterio skill_triggered

  • Righe positive e negative etichettate in un dataset
  • Matrice di confusione con accuracy, precision, recall, F1
  • Soglie di suite che fanno uscire il run con codice diverso da zero
  • Storico dei punteggi pesati, quindi trend leggibili

Il valore non è il tool in sé: è passare da un'impressione a una metrica ripetibile.

🔁 A/B, dataset e gate in continuous integration

Sopra ai task c'è un layer di esperimenti che permette di far girare gli stessi task su varianti diverse: modello contro modello, prompt contro prompt, tool acceso contro tool spento, e — il caso più interessante per chi scrive skill — plugin della skill installato contro non installato. È il complemento naturale di `skill_triggered`: si misura quanto la skill sposta davvero il risultato, invece di assumerlo. Con la modalità dataset si prende un singolo task e lo si moltiplica su molte righe, ottenendo una suite di dimensioni serie da poche decine di righe di YAML.

L'ultimo pezzo è il gate in CI. Esiste una composite action pubblicata sul Marketplace GitHub che installa la CLI pinnata, esegue i task, scrive un report JUnit, appende il riepilogo al job summary e fa fallire lo step su qualunque task o soglia non rispettata. C'è anche un `minimum-task-score` opzionale, un pavimento stretto sul punteggio pesato che si somma all'exit code della CLI. La documentazione insiste su due cose: pinnare la versione, perché un aggiornamento del framework non deve spostare silenziosamente i risultati; e non esporre segreti a PR di fork, perché i task eseguono codice generato dall'agente.

Il gate in GitHub Actions
- uses: actions/setup-node@v4      # l'agente claude-code ha bisogno della CLI…
  with: { node-version: '20' }
- run: npm install -g @anthropic-ai/claude-code

- uses: UiPath/coder_eval@v0       # …poi gira il gate
  with:
    tasks: tests/tasks/**/*.yaml
    model: claude-sonnet-5
    minimum-task-score: "0.8"
    env: |
      ANTHROPIC_API_KEY=${{ secrets.ANTHROPIC_API_KEY }}

Composite action coder_eval sul Marketplace GitHub

L'action installa la CLI ma non il runtime dell'agente: quello resta responsabilità di chi la usa.

💡 Perché lo trovo interessante, per chi sviluppa e per una PMI

Sul lato sviluppo il ragionamento è quello dei test di regressione, applicato a un pezzo di sistema che finora non ne aveva. Una skill, un server MCP, un CLAUDE.md: sono tutti artefatti che influenzano il comportamento di un agente senza che nessuno li verifichi mai in modo automatico. Il giorno in cui il modello cambia versione, l'unica cosa che si nota è che «l'agente si comporta un po' diverso». Un task YAML con due o tre criteri, eseguito su schedule, trasforma quella sensazione in una riga rossa nella pipeline.

Sul lato azienda il punto è la ripetibilità nel tempo. Se in un team si stanno introducendo agenti nei processi — revisione del codice, generazione di documentazione, triage dei ticket — la domanda che prima o poi arriva è «come sappiamo che continua a funzionare?». Avere una suite di task eseguibile è la differenza fra un'adozione governata e una serie di aneddoti. Aggiungo che la telemetria per tool call, token e costo che il framework raccoglie è utile quanto lo scoring: rende visibile quanto costa davvero un flusso agentico prima di generalizzarlo su tutto il team.

Come lo integrerei in un flusso reale
  1. 01
    Scrivo la skillSKILL.md con la descrizione che decide se e quando scatterà
  2. 02
    Scrivo 5-10 righe di datasetcasi positivi dove deve scattare, negativi dove non deve
  3. 03
    Un task YAMLskill_triggered + un paio di criteri sull'esito concreto (file, comandi)
  4. 04
    Run localecoder-eval plan per validare senza spendere token, poi run e report
  5. 05
    Gate schedulatol'action in CI su ogni modifica alla skill e a cadenza fissa

Il costo di ingresso è basso: il valore arriva quando il run diventa periodico, non alla prima esecuzione.

⚠️ Cosa mettere in conto prima di provarlo

Tre cose vanno dette con chiarezza. La prima: il progetto è molto giovane. Poche stelle, pochissimi commit sul ramo principale, versione ancora sotto l'1.0 — la action stessa si referenzia come `@v0` in attesa del rilascio stabile. Ha però una base solida attorno: pacchetto su PyPI, action sul Marketplace, sito di documentazione, licenza Apache-2.0 e una CI pubblica. È materiale da studiare e da usare in un progetto interno, non ancora da mettere al centro di un processo critico.

La seconda: valutare costa. Ogni run lancia un agente vero con credenziali vere — Anthropic, Bedrock o Gemini — e coder_eval non fa da proxy né fornisce accesso al modello. Il comando `plan` valida un task senza spendere token, ed è il primo posto dove abituarsi a passare. La terza: la telemetria d'uso anonima è attiva di default e si disattiva con `TELEMETRY_ENABLED=false`; la documentazione precisa che non cattura prompt, contenuti dei file o path del repository, ma è una scelta consapevole da fare prima di installarlo in azienda. Infine, richiede Python 3.13 o superiore.

✅ Da dove partire

Il percorso più corto è il tutorial ufficiale: clonare il repo, `uv sync --extra dev`, e far girare `coder-eval plan tasks/hello_date.yaml` per vedere la validazione senza consumare nulla. Solo dopo il `run` e il `report`. Chi vuole usarlo su un progetto proprio installa il pacchetto pubblicato — `uv tool install coder-eval` oppure `pip install coder-eval` — e punta la CLI ai propri file di task, pinnando la versione se finisce in una pipeline.

Il segnale più ampio che leggo in questo repo, però, va oltre il tool. Le skill e i server MCP stanno diventando artefatti di prodotto: hanno una superficie pubblica, un comportamento osservabile e delle regressioni. È esattamente la fase in cui in ogni altro ambito del software sono comparsi i test. Che sia coder_eval o un altro framework a vincere conta poco: il pattern — descrivo il comportamento atteso in un file, lo eseguo in sandbox, lo misuro e lo gate in CI — è quello che vale la pena portarsi a casa.

Domande frequenti su coder_eval

Che cos'è coder_eval e a cosa serve?

È un framework open source Apache-2.0 pubblicato da UiPath per valutare e benchmarkare agenti di coding e le loro skill. Esegue un agente reale (Claude Code, Codex o Antigravity/Gemini) dentro una sandbox contro task scritti in YAML, poi assegna un punteggio ai file e ai comandi effettivamente prodotti usando criteri pesati da 0.0 a 1.0. Serve a trasformare in metrica ripetibile qualcosa che di solito si giudica a occhio.

Come faccio a sapere se una skill di Claude Code è davvero scattata?

Con il criterio `skill_triggered`. È un classificatore binario che scandisce le trace del run cercando una chiamata al tool Skill con parametro corrispondente, oppure — per agenti senza quel tool — la lettura dei file della skill sotto `skills/<nome>/`. Su un task alimentato da dataset, con righe positive e negative, produce accuratezza, precision, recall, F1 e matrice di confusione, e si può gatare con soglie di suite.

coder_eval è un benchmark come SWE-bench?

No, ed è una differenza sostanziale. SWE-bench e SkillsBench sono dataset fissi che producono una classifica di modelli su problemi canonici. coder_eval non ha classifica né dataset proprio: valuta i task, le skill e i workflow che scrivi tu, con criteri pesati e soglie decise da te. Può comunque incapsulare un dataset esterno tramite la modalità bring-your-own-dataset.

Quanto costa far girare una suite di valutazione?

Dipende dai token consumati dall'agente, perché ogni run lancia un agente vero con le tue credenziali: coder_eval non fa da proxy e non fornisce accesso ai modelli. Il comando `plan` valida i task senza spendere nulla, ed è il modo giusto per iterare sullo YAML. Il framework raccoglie inoltre telemetria per tool call, token e costo, quindi il conto di ogni suite è visibile nei report.

Posso usarlo come gate in continuous integration?

Sì: esiste una composite action sul Marketplace GitHub che installa la CLI pinnata, esegue i task, scrive un report JUnit e fa fallire lo step su qualunque task o soglia non rispettata, con un `minimum-task-score` opzionale come pavimento sul punteggio pesato. Due avvertenze dalla documentazione: pinnare la versione e non esporre segreti a pull request di fork, perché i task eseguono codice generato dall'agente.

Parliamone

Se questo tema ti riguarda, scrivimi: confrontarsi su codice e AI è sempre tempo speso bene.