<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/rss.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Florian Sabani</title><description>Software Engineer | Tech Entrepreneur | Cloud Specialist</description><link>https://floriansabani.com</link><item><title>Dai occhi al tuo coding agent: Cloudflare Skills, Observability MCP e TDD local-first</title><link>https://floriansabani.com/it/posts/give-your-coding-agent-eyes</link><guid isPermaLink="true">https://floriansabani.com/it/posts/give-your-coding-agent-eyes</guid><pubDate>Sat, 04 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I coding agent sono instancabili e veloci — e ciechi, di default. Questo post parla dei due feedback loop che ho cablato nel mio progetto su Cloudflare Workers perché Claude Code possa &lt;em&gt;vedere&lt;/em&gt; cosa fa il mio codice: log di produzione che può interrogare da solo, e una test suite locale che simula l&apos;intera piattaforma — Durable Objects, SQLite, R2, API di terze parti — in pochi secondi. È la cosa più vicina a una pallottola d&apos;argento che abbia trovato per l&apos;agentic coding.&lt;/p&gt;
&lt;h2&gt;Lo scultore cieco&lt;/h2&gt;
&lt;p&gt;Di recente ho guardato un video di Salvatore Sanfilippo (antirez) — &lt;a href=&quot;https://youtu.be/TJ6ruN-o0PA&quot;&gt;&lt;em&gt;&quot;Il trucco decisivo (davvero) per lavorare coi coding agent&quot;&lt;/em&gt;&lt;/a&gt; — che mette in parole qualcosa attorno a cui giravo da mesi. Tutto il merito dell&apos;inquadratura è suo; andate a vederlo.&lt;/p&gt;
&lt;p&gt;Il suo ragionamento è questo. Avete già sentito tutti i consigli standard sui coding agent: scrivere spec precise, condividere le proprie intuizioni di design in linguaggio non vincolante, tenere il codebase pulito, commentare le &lt;em&gt;tensioni&lt;/em&gt; del codice e non solo la meccanica. Tutto vero, tutto utile. Ma c&apos;è una proprietà degli agenti LLM di cui quasi nessuno parla, ed è quella che cambia tutto: la &lt;strong&gt;tenacia&lt;/strong&gt;. Un agente prova, riprova, e riprova ancora, a una velocità che nessun umano può eguagliare. Ogni tentativo fallito gli costa secondi, non un pomeriggio di motivazione.&lt;/p&gt;
&lt;p&gt;Poi arriva la sua metafora, che non riesco a togliermi dalla testa. Immaginate un operaio instancabile davanti a un blocco di marmo. Può persino viaggiare indietro nel tempo: scheggia il marmo nel punto sbagliato, riavvolge, riprova, all&apos;infinito. I suoi strumenti sono rozzi — non sa scolpire come Michelangelo, sa solo lanciare sassi — ma non si ferma mai e non si stanca mai. Con abbastanza tentativi, arriverà da qualche parte di notevole.&lt;/p&gt;
&lt;p&gt;A meno che non sia cieco.&lt;/p&gt;
&lt;p&gt;Se l&apos;operaio non può &lt;em&gt;vedere&lt;/em&gt; il marmo, nessuna quantità di tenacia o di viaggi nel tempo lo aiuta. I suoi tentativi non sono informati dai risultati di quelli precedenti. Sta solo lanciando sassi nel buio.&lt;/p&gt;
&lt;p&gt;Ecco cos&apos;è il vostro coding agent senza feedback loop. Ed ecco perché ho smesso di ottimizzare i miei prompt e ho iniziato a ottimizzare i &lt;em&gt;sensi&lt;/em&gt; del mio agente.&lt;/p&gt;
&lt;h2&gt;Due tipi di vista&lt;/h2&gt;
&lt;p&gt;Un coding agent ha bisogno di vedere due cose diverse:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Cosa ha fatto davvero il codice&lt;/strong&gt; — il comportamento in produzione: errori, log, timeline, la richiesta fallita alle 11:51 e tutto quello che le è successo intorno.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cosa farà il codice&lt;/strong&gt; — le conseguenze della modifica appena fatta, prima che vada in produzione: il flusso funziona ancora, il database è finito nello stato giusto, abbiamo chiamato l&apos;API di terze parti nel modo in cui pensiamo di averlo fatto.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Su Cloudflare, entrambe sono ormai cose che l&apos;agente può fare &lt;em&gt;da solo&lt;/em&gt;, senza che io clicchi tra le dashboard o faccia da babysitter a un ambiente di staging. La prima arriva dalle &lt;a href=&quot;https://developers.cloudflare.com/agent-setup/claude-code/&quot;&gt;skill e dai server MCP di Cloudflare&lt;/a&gt;; la seconda da &lt;code&gt;@cloudflare/vitest-pool-workers&lt;/code&gt; e da un&apos;architettura di test deliberatamente local-first.&lt;/p&gt;
&lt;p&gt;Ve le mostro entrambe, con materiale reale (leggermente anonimizzato) dal mio progetto: una piattaforma multi-tenant su Workers che si integra con exchange crypto — API in Hono, Durable Objects con SQLite, R2, D1, drizzle-orm, il pacchetto completo.&lt;/p&gt;
&lt;h2&gt;Parte 1: lasciate che l&apos;agente legga la produzione&lt;/h2&gt;
&lt;h3&gt;Setup&lt;/h3&gt;
&lt;p&gt;Cloudflare pubblica skill ufficiali per Claude Code — moduli di guida contestuale per Workers, Durable Objects, wrangler, l&apos;Agents SDK e altro. Seguono una filosofia retrieval-first: invece di fidarsi di quello che il modello ha memorizzato sulla piattaforma nel 2024, la skill gli dice di andare a controllare.&lt;/p&gt;
&lt;p&gt;:::tip
Installare le skill richiede due comandi dentro Claude Code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/plugin marketplace add cloudflare/skills
/plugin install cloudflare@cloudflare
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;:::&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;cloudflare/skills&quot;}&lt;/p&gt;
&lt;p&gt;Poi c&apos;è la parte che ha dato al mio agente occhi veri sulla produzione: il &lt;strong&gt;server MCP Workers Observability&lt;/strong&gt;. Un solo comando:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;claude mcp add cloudflare-observability --transport http https://observability.mcp.cloudflare.com/mcp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Autenticatevi via &lt;code&gt;/mcp&lt;/code&gt; (esegue un suo flow OAuth verso il vostro account Cloudflare), e il vostro agente può ora interrogare ogni riga di log emessa dai vostri Workers negli ultimi sette giorni: filtri, ricerche full-text, group-by, calcoli di percentili. Non &lt;code&gt;wrangler tail&lt;/code&gt; sperando che il bug si ripresenti — telemetria di produzione &lt;em&gt;storica&lt;/em&gt;, interrogabile in forma strutturata.&lt;/p&gt;
&lt;h3&gt;La storia di guerra&lt;/h3&gt;
&lt;p&gt;Ecco cosa mi ha convinto. Il nostro flow OAuth per collegare l&apos;account exchange di un utente ha iniziato a fallire in produzione con:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;OAuth completion failed: &amp;lt;Exchange&amp;gt; API error: Temporary lockout
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;HTTP 400, connessione segnalata come fallita. Solo che… la API key sull&apos;exchange &lt;em&gt;era stata creata&lt;/em&gt;, con gli scope corretti. L&apos;utente la vedeva nel proprio account. Qualcosa dichiarava un fallimento su un successo.&lt;/p&gt;
&lt;p&gt;Il me di una volta avrebbe passato la serata nella dashboard: filtrare per URL, strizzare gli occhi sui timestamp, aprire quindici log, correlare a mano. Invece ho incollato una singola riga di log di esempio in Claude Code e gli ho chiesto di indagare.&lt;/p&gt;
&lt;p&gt;Quello che ha fatto, in autonomia, è la parte interessante:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prima ha letto il codice, ancora prima di toccare i log.&lt;/strong&gt; Ha rintracciato il punto esatto del throw: la nostra callback creava la API key, poi chiamava immediatamente l&apos;endpoint privato dei balance dell&apos;exchange come step di &quot;verifica&quot; — e trattava &lt;em&gt;qualsiasi&lt;/em&gt; errore come fatale. Il wallet non veniva mai persistito. La chiave esisteva sull&apos;exchange; noi la buttavamo via e dicevamo all&apos;utente che era andata male.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Poi è andato sui log per testare l&apos;ipotesi.&lt;/strong&gt; Il mio log di esempio aveva uno ULID come ID. L&apos;agente ne ha decodificato il timestamp (gli ULID incorporano i millisecondi — sinceramente non lo sapevo), ha ottenuto il momento esatto del fallimento e ha interrogato una finestra intorno a esso:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;view&quot;: &quot;events&quot;,
  &quot;timeframe&quot;: { &quot;from&quot;: &quot;…T10:30:00Z&quot;, &quot;to&quot;: &quot;…T12:10:00Z&quot; },
  &quot;parameters&quot;: {
    &quot;filters&quot;: [
      { &quot;key&quot;: &quot;$metadata.service&quot;, &quot;operation&quot;: &quot;eq&quot;, &quot;value&quot;: &quot;workers-prod&quot; },
      { &quot;key&quot;: &quot;$metadata.level&quot;,   &quot;operation&quot;: &quot;eq&quot;, &quot;value&quot;: &quot;error&quot; }
    ],
    &quot;needle&quot;: { &quot;value&quot;: &quot;lockout&quot; }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Poi ha allargato lo sguardo e ha raggruppato.&lt;/strong&gt; Invece di fissare i singoli eventi, ha eseguito un conteggio raggruppato per &lt;code&gt;$metadata.trigger&lt;/code&gt; sull&apos;intera settimana. Il risultato era la pistola fumante: l&apos;errore &quot;Temporary lockout&quot; non era affatto un problema di OAuth. Compariva in &lt;em&gt;quattro sottosistemi scollegati&lt;/em&gt; — l&apos;endpoint di refresh dei balance, un endpoint per gli indirizzi di deposito, un cron job, un alarm di un Durable Object che faceva polling sui prelievi. Era uno stato di throttling a livello di account lato exchange, preesistente ancora prima che la callback OAuth venisse eseguita. Una API key nuova di zecca e perfettamente valida era entrata in una stanza chiusa a chiave.&lt;/p&gt;
&lt;p&gt;La timeline ricostruita sembrava la lavagna di un detective:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;11:39  burst of &quot;Invalid key&quot; errors    (a stored wallet with a dead key, hammered by balance refresh)
11:45  cron job hits &quot;Temporary lockout&quot;  ← account already locked, before any OAuth
11:51  OAuth connect: key created OK → balance verification → &quot;Temporary lockout&quot; → 400
11:56  user retries → 500 &quot;Missing idempotency key&quot;   ← a *second*, unrelated bug
11:57  user retries → 500
11:57  user retries → 500
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Strada facendo ha trovato due bug bonus di cui non gli avevo chiesto nulla: il percorso di retry restituiva 500 perché mancava un cookie e l&apos;error handler non copriva il caso (quindi il widget non riceveva nemmeno il messaggio di errore), e un cron &lt;code&gt;* * * * *&lt;/code&gt; stava inondando i log con centinaia di warning innocui al minuto — cosa che pesa più di prima, perché il rumore nei log ora degrada anche le query &lt;em&gt;dell&apos;agente&lt;/em&gt;, non solo le mie.&lt;/p&gt;
&lt;p&gt;La root cause finale si è rivelata ancora migliore: l&apos;exchange applica un cooldown di sicurezza di ~15 minuti sulle chiamate API private ogni volta che un account si connette da un nuovo dispositivo o IP — che è &lt;em&gt;letteralmente ciò che è una connect OAuth&lt;/em&gt;. Il nostro design &quot;verifica sincrona subito dopo la creazione&quot; era strutturalmente destinato a fallire alle prime connessioni. Il fix non era la retry logic; era persistere subito la chiave e rimandare il check dei balance a dopo il cooldown.&lt;/p&gt;
&lt;p&gt;Non ho mai aperto la dashboard di Cloudflare. L&apos;agente ha formulato ipotesi dal codice, le ha testate contro la telemetria di produzione, e le ha riviste. È lo scultore instancabile di antirez — con gli occhi.&lt;/p&gt;
&lt;h2&gt;Trappole imparate sul campo&lt;/h2&gt;
&lt;p&gt;Tre cose che vi morderanno, così non devono farlo:&lt;/p&gt;
&lt;p&gt;:::caution
&lt;strong&gt;Il vostro login wrangler non può interrogare l&apos;API di observability.&lt;/strong&gt; Prima di installare il server MCP, il mio agente ha provato l&apos;endpoint REST direttamente con il token OAuth di &lt;code&gt;wrangler login&lt;/code&gt; e ha ricevuto un secco &lt;code&gt;code: 10000, Authentication error&lt;/code&gt;. È il modo confuso di Cloudflare per dire &quot;token valido, permesso mancante&quot;: il token di wrangler porta solo gli scope che wrangler richiede (&lt;code&gt;workers:write&lt;/code&gt;, &lt;code&gt;workers_tail:read&lt;/code&gt;, …), e l&apos;endpoint di query della telemetria ha bisogno di &lt;strong&gt;Workers Observability: Read&lt;/strong&gt;. Il server MCP aggira il problema alla radice eseguendo il proprio flow OAuth con gli scope giusti. Se invece volete accesso raw via &lt;code&gt;curl&lt;/code&gt;, create un API token dedicato.
:::&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I server MCP aggiunti a metà sessione richiedono una riconnessione.&lt;/strong&gt; &lt;code&gt;claude mcp add&lt;/code&gt; aggiorna la configurazione, ma una sessione di Claude Code già in esecuzione non vedrà i tool del nuovo server finché non eseguite &lt;code&gt;/mcp&lt;/code&gt; in &lt;em&gt;quella&lt;/em&gt; sessione (o la riavviate). Ci ho perso dieci minuti di confusione.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;L&apos;igiene dei log ora è performance dell&apos;agente.&lt;/strong&gt; Una ricerca full-text su un servizio rumoroso restituisce il rumore. La mia prima query &quot;mostrami tutto quello che è successo intorno al fallimento&quot; è tornata al 100% fatta di warning del cron. Se volete che gli agenti facciano debugging dai vostri log, trattate lo spam nei log come un bug con un costo reale.&lt;/p&gt;
&lt;h2&gt;Parte 2: il TDD local-first è l&apos;altro occhio dell&apos;agente&lt;/h2&gt;
&lt;p&gt;La vista sulla produzione vi dice cosa è andato storto. Il secondo loop — quello che rende l&apos;agente &lt;em&gt;produttivo&lt;/em&gt; e non solo diagnostico — è una test suite che può eseguire da solo, che risponde con sincerità, in pochi secondi.&lt;/p&gt;
&lt;p&gt;La svolta su Cloudflare è &lt;a href=&quot;https://developers.cloudflare.com/workers/testing/vitest-integration/&quot;&gt;&lt;code&gt;@cloudflare/vitest-pool-workers&lt;/code&gt;&lt;/a&gt;: i vostri test non girano in Node con API di piattaforma mockate — girano dentro &lt;strong&gt;workerd&lt;/strong&gt;, il runtime reale dei Workers, avviato da Miniflare &lt;em&gt;a partire dal vostro vero &lt;code&gt;wrangler.jsonc&lt;/code&gt;&lt;/em&gt;. Durable Objects, il loro storage SQLite, R2, D1, KV, rate limiter: tutte implementazioni reali, tutte locali, tutte in-process.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export default defineWorkersConfig({
  test: {
    sequence: { concurrent: false },
    poolOptions: {
      workers: {
        isolatedStorage: false,
        wrangler: { configPath: &apos;./wrangler.jsonc&apos; },  // ← the whole platform, in-process
        moduleRules: [{ type: &apos;Text&apos;, include: [&apos;**/*.sql&apos;] }],
      },
    },
  },
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ecco cosa rende possibile, in pratica, nel mio codebase.&lt;/p&gt;
&lt;h3&gt;Il database nei vostri test &lt;em&gt;è&lt;/em&gt; il database di produzione&lt;/h3&gt;
&lt;p&gt;Ogni tenant nel mio sistema è un Durable Object il cui SQLite in &lt;code&gt;ctx.storage&lt;/code&gt; è gestito da drizzle-orm. Le migrazioni girano nel costruttore del DO:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { drizzle } from &apos;drizzle-orm/durable-sqlite&apos;;
import { migrate } from &apos;drizzle-orm/durable-sqlite/migrator&apos;;
import migrations from &apos;../generated-migrations&apos;;

constructor(ctx: DurableObjectState, env: Env) {
  this.db = drizzle(ctx.storage, { schema: tenantSchema });
  ctx.blockConcurrencyWhile(() =&amp;gt; migrate(this.db, migrations));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Poiché vitest avvia la stessa classe DO sotto Miniflare, il database di test locale ha &lt;em&gt;esattamente&lt;/em&gt; lo schema di produzione — stesse migrazioni, stesso engine, niente &quot;mock in salsa SQLite del nostro Postgres&quot;. (Un dettaglio scomodo: la sandbox dei Workers non può leggere file dal disco, quindi un piccolo build step genera i file di migrazione &lt;code&gt;.sql&lt;/code&gt; come modulo JS di stringhe prima che la suite parta. Brutto, ma efficace.)&lt;/p&gt;
&lt;h3&gt;Asserzioni white-box con &lt;code&gt;runInDurableObject&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;cloudflare:test&lt;/code&gt; espone una scappatoia magica: entrare &lt;em&gt;dentro&lt;/em&gt; un&apos;istanza di Durable Object ed eseguire asserzioni sul suo stato privato.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const identities = await runInDurableObject(orgDb, async (instance: TenantDurableObject) =&amp;gt; {
  const db = (instance as any).db;
  return db.select().from(cexIdentities).all();
});
expect(identities).toHaveLength(0);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;È la differenza tra &quot;l&apos;endpoint ha risposto 200&quot; e &quot;la riga è davvero arrivata, con il secret cifrato at rest&quot;. La mia suite lo usa in 46 file di test.&lt;/p&gt;
&lt;h3&gt;Le API di terze parti diventano asserzioni rigide&lt;/h3&gt;
&lt;p&gt;La parte più spaventosa di un&apos;integrazione con un exchange sono le chiamate in uscita — la parte che gli agenti adorano allucinare. &lt;code&gt;fetchMock&lt;/code&gt; di &lt;code&gt;cloudflare:test&lt;/code&gt; la trasforma in un contratto:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;beforeEach(() =&amp;gt; {
  fetchMock.activate();
  fetchMock.disableNetConnect();   // any unmocked outbound call = test failure
});

fetchMock.get(&apos;https://api.exchange.example&apos;)
  .intercept({ method: &apos;POST&apos;, path: &apos;/oauth/token&apos; })
  .reply(200, oauthTokenSuccessFixture);

// …run the flow…

fetchMock.assertNoPendingInterceptors();  // every expected call actually happened
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;disableNetConnect()&lt;/code&gt; significa che l&apos;agente &lt;em&gt;non può&lt;/em&gt; testare per sbaglio contro la rete vera, e una chiamata API extra allucinata fallisce rumorosamente invece di funzionare-più-o-meno in silenzio. &lt;code&gt;assertNoPendingInterceptors()&lt;/code&gt; significa che anche una chiamata &lt;em&gt;mancante&lt;/em&gt; fallisce. Il mock non è uno stub; è una spec.&lt;/p&gt;
&lt;h3&gt;Il loop d&apos;oro&lt;/h3&gt;
&lt;p&gt;Messo tutto insieme, un solo test esercita l&apos;intera verticale: mock dei tre endpoint dell&apos;exchange → invocazione della vera route Hono → asserzioni sulla risposta HTTP, sul contratto dei mock &lt;em&gt;e&lt;/em&gt; sullo stato SQLite del Durable Object:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;it(&apos;completes OAuth → API key → balance → wallet storage&apos;, async () =&amp;gt; {
  fetchMock.get(EXCHANGE).intercept({ path: &apos;/oauth/token&apos;, method: &apos;POST&apos; }).reply(200, tokenFixture);
  fetchMock.get(EXCHANGE).intercept({ path: &apos;/oauth/api-key&apos;, method: &apos;POST&apos; }).reply(200, keyFixture);
  fetchMock.get(EXCHANGE).intercept({ path: &apos;/private/Balance&apos;, method: &apos;POST&apos; }).reply(200, balanceFixture);

  const response = await app.request(callbackUrl, { headers }, env);

  expect(response.status).toBe(200);
  fetchMock.assertNoPendingInterceptors();

  const wallet = await runInDurableObject(orgDb, (i: TenantDurableObject) =&amp;gt; i.getWallet(&apos;wallet-123&apos;));
  expect(wallet).toMatchObject({ exchange: &apos;exchange&apos;, type: &apos;long-living&apos; });
  expect(wallet!.apiSecret).not.toBe(keyFixture.result.secret); // encrypted at rest
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Perché questo conta &lt;em&gt;specificamente per gli agenti&lt;/em&gt;? Torniamo allo scultore:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;La velocità alimenta la tenacia.&lt;/strong&gt; &lt;code&gt;npx vitest run test/oauth2/callback.test.ts&lt;/code&gt; dà all&apos;agente un verdetto rosso/verde sull&apos;intero stack in pochi secondi. Ogni sasso lanciato viene valutato all&apos;istante. Cinquanta iterazioni costano minuti, non giorni.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Il determinismo mantiene il feedback sincero.&lt;/strong&gt; Niente staging flaky, niente drift di ambienti condivisi, niente &quot;sulla mia macchina funzionava&quot;. Lo stato di Miniflare viene azzerato all&apos;inizio di ogni run.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Il rigore cattura le allucinazioni.&lt;/strong&gt; La combinazione &lt;code&gt;disableNetConnect&lt;/code&gt; + &lt;code&gt;assertNoPendingInterceptors&lt;/code&gt; è un dispositivo anti-allucinazione: l&apos;agente non può inventarsi un&apos;interazione API che &quot;probabilmente esiste&quot; — il contratto è eseguibile.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;È self-serve.&lt;/strong&gt; L&apos;agente non mi chiede di cliccare in una UI per verificare. Scrive il test che fallisce, lo fa passare, e mi mostra l&apos;output. Il TDD è sempre stato una disciplina di feedback loop; gli agenti sono semplicemente i primi sviluppatori abbastanza tenaci da sfruttarlo fino in fondo.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(Parentesi di onestà: essere così local-first su una piattaforma giovane ha dei costi. Al momento vado in produzione con fork community patchati di drizzle-orm e better-auth per far comportare bene gli adapter. Tassa da early adopter.)&lt;/p&gt;
&lt;h2&gt;Il 100x onesto&lt;/h2&gt;
&lt;p&gt;&quot;100x&quot; è un&apos;affermazione grossa, quindi lasciatemela collocare con precisione. Non è velocità di battitura. È il prodotto di &lt;em&gt;numero di iterazioni&lt;/em&gt; × &lt;em&gt;sincerità del feedback&lt;/em&gt;, e in pratica è questo:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Io, a mano&lt;/th&gt;
&lt;th&gt;Agente con gli occhi&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&quot;Perché questo 400 in prod?&quot;&lt;/td&gt;
&lt;td&gt;30–60 min di speleologia nella dashboard, se va bene&lt;/td&gt;
&lt;td&gt;Un prompt; l&apos;agente correla codice + una settimana di log, restituisce una timeline e due bug bonus&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&quot;Ho appena rotto il flusso dei prelievi?&quot;&lt;/td&gt;
&lt;td&gt;Deploy su staging, click manuali nel widget&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vitest run&lt;/code&gt; — verdetto full-stack in secondi, stato del DO incluso&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&quot;Chiamiamo l&apos;API dell&apos;exchange correttamente?&quot;&lt;/td&gt;
&lt;td&gt;Rileggere la loro documentazione, sperare&lt;/td&gt;
&lt;td&gt;&lt;code&gt;assertNoPendingInterceptors()&lt;/code&gt; — il contratto è un test&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&quot;Questa API di piattaforma ha ancora la forma che ricordo?&quot;&lt;/td&gt;
&lt;td&gt;Cambiare tab verso i docs&lt;/td&gt;
&lt;td&gt;La skill Cloudflare recupera i docs attuali invece di fidarsi dei dati di training&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;L&apos;agente è sempre stato tenace. È sempre stato veloce. Non erano mai quelli il collo di bottiglia — lo era la vista. Cablate una telemetria di produzione che può interrogare e un mondo locale che può simulare, e l&apos;operaio instancabile davanti al marmo finalmente guarda dove atterra ogni sasso.&lt;/p&gt;
&lt;p&gt;Adesso scolpisce.&lt;/p&gt;
&lt;h2&gt;Crediti e link&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Salvatore Sanfilippo (antirez), &lt;a href=&quot;https://youtu.be/TJ6ruN-o0PA&quot;&gt;&lt;em&gt;Il trucco decisivo (davvero) per lavorare coi coding agent&lt;/em&gt;&lt;/a&gt; — la metafora dello scultore cieco che ha ispirato questo post. Grazie.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/cloudflare/skills&quot;&gt;cloudflare/skills&lt;/a&gt; — le Agent Skills ufficiali per Claude Code e altri agenti.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.cloudflare.com/agent-setup/claude-code/&quot;&gt;Guida Cloudflare all&apos;agent setup per Claude Code&lt;/a&gt; — skill + server MCP, incluso l&apos;&lt;a href=&quot;https://observability.mcp.cloudflare.com/mcp&quot;&gt;Observability MCP server&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.cloudflare.com/workers/testing/vitest-integration/&quot;&gt;Integrazione Vitest per Workers&lt;/a&gt; — &lt;code&gt;@cloudflare/vitest-pool-workers&lt;/code&gt;, &lt;code&gt;runInDurableObject&lt;/code&gt;, &lt;code&gt;fetchMock&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Florian Sabani</author></item></channel></rss>