G.STANCUTA
Pubblicato · 2026 · 01 · 308 min di lettura

Guida l'Agente: Come Spedire Davvero Codice in Produzione con l'AI

  • ai-agents
  • developer-tools
  • workflow
  • field-notes

L'agente AI non è l'operatore. Sei tu. Ecco il modello mentale, l'architettura della memoria e la disciplina di verifica che trasformano una sessione caotica con un LLM in un ciclo di rilascio affidabile.

Tutti vogliono parlare di cosa sa fare il modello. Nessuno vuole parlare della parte che determina davvero se il codice viene rilasciato: l'operatore. Sei tu. L'agente è un esecutore molto capace, privo di memoria a lungo termine, di consapevolezza situazionale e di interesse nel fatto che la pull request funzioni. Tu hai tutte e tre le cose. Nel momento in cui te ne dimentichi, inizi a produrre spazzatura su scala invece che software.

Rilascio codice in produzione con agenti AI da abbastanza tempo da avere un sistema ripetibile. Non è magia. È disciplina applicata a un nuovo tipo di strumento.

Diagramma isometrico di un operatore umano che guida un agente AI attraverso una pipeline di task scomposti
L'operatore modella ogni passaggio. L'agente esegue.

Specifica, Non Desiderio

La qualità del tuo output è limitata dalla qualità del tuo input. Non è una metafora, è un fatto meccanico su come funzionano i modelli linguistici. Prompt vaghi producono codice vago. Un desiderio suona così: "aggiungi l'autenticazione all'app." Una specifica suona così: "implementa l'autenticazione basata su JWT usando il modello User esistente in src/models/user.ts, proteggi tutte le route sotto /api/v1/ eccetto /api/v1/auth/login e /api/v1/auth/refresh, salva il refresh token in un cookie HTTP-only, e scrivi unit test per il middleware in src/middleware/__tests__/auth.test.ts."

La differenza non è di stile. È densità di segnale. Ogni vincolo che ometti è una decisione che l'agente prende al posto tuo, e l'agente non ha idea di come sia la tua architettura, cosa abbia concordato il tuo team martedì scorso, o quale libreria di terze parti hai bandito sei mesi fa. Tu sì. Mettilo nel prompt.

Scomponi in Passi Verificabili

I task agentici lunghi falliscono al confine tra i sotto-task. L'agente perde il filo, allucinaun import, o cambia silenziosamente l'interfaccia che avrebbe dovuto preservare. La soluzione è la scomposizione: suddividi il lavoro in passi in cui ogni passo ha una condizione di uscita chiara e verificabile.

Non "costruisci la feature." Invece: (1) scrivi il data layer con tipi e test, fermati, (2) scrivi il service layer contro quei tipi, fermati, (3) collega l'HTTP handler, fermati, (4) esegui l'intera suite di test e riporta i fallimenti. Ogni stop è un checkpoint in cui ispezioni l'output prima di procedere. Sei tu l'orchestratore. Decidi tu quando il passo N è abbastanza buono per iniziare il passo N+1.

  1. 01Definisci prima il contratto sui dati (tipi, schema, fixture).
  2. 02Implementa la logica principale contro quel contratto.
  3. 03Collega il livello di integrazione (HTTP, event bus, CLI).
  4. 04Verifica in un passaggio separato con una finestra di contesto fresca.

Mantenere i passi piccoli mantiene pulita anche la finestra di contesto. Una modifica da 200 righe è revisionabile. Una da 2000 righe è un rischio.

L'Architettura Vive nella Tua Testa (e nel Markdown)

Ecco la verità cruda sugli agenti AI per il codice: non hanno memoria tra le sessioni. L'agente che ieri ha scritto il tuo middleware di autenticazione oggi non sa che esiste. Inventerà volentieri un pattern diverso, importerà una libreria in conflitto, o violerà la convenzione che hai stabilito, non perché sia negligente ma perché non gliel'hai mai detto.

È qui che i file markdown di memoria diventano la parte più importante del tuo stack. Non prompt intelligenti. Non messaggi di sistema. File markdown persistenti e versionati che vivono nel repository e vengono caricati nel contesto all'inizio di ogni sessione. L'agente li legge, e improvvisamente ha la conoscenza istituzionale che altrimenti gli mancherebbe.

Il file markdown non è documentazione per gli esseri umani. È memoria di lavoro per l'agente. Scrivilo di conseguenza.

Il pattern è semplice: un AGENTS.md alla radice del progetto, con sezioni per le decisioni architetturali, le convenzioni di denominazione, i comandi da eseguire, i pattern vietati e le insidie note. Tienilo aggiornato man mano che il codice evolve. Trattalo con la stessa disciplina che riserveresti a un README.md che influenza effettivamente il comportamento a runtime, perché nel tuo flusso di lavoro AI, lo fa.

md
# AGENTS.md — Project Memory for AI Coding Agents

## Architecture

- Monorepo: apps/web (Next.js), apps/api (Hono on Bun), packages/shared (types + utils)
- Database: Postgres via Drizzle ORM. Schema lives in packages/db/schema.ts.
- Auth: JWT in Authorization header for API, HTTP-only cookie for web client. Use the helpers in packages/shared/src/auth.ts — do NOT roll your own.
- State: Zustand stores in apps/web/src/stores/. No Redux, no Context API for app state.

## Conventions

- File naming: kebab-case for files, PascalCase for components/classes.
- All API routes return { data, error, meta } — use the ResponseEnvelope type from packages/shared.
- Services live in src/services/, handlers in src/handlers/. Services contain business logic, handlers do HTTP concerns only.
- Tests co-located: src/services/__tests__/auth-service.test.ts next to src/services/auth-service.ts.

## Commands

```bash
bun run dev          # start all apps in parallel
bun run test         # run full test suite
bun run db:migrate   # apply pending migrations
bun run typecheck    # tsc --noEmit across all packages
```

## Forbidden Patterns

- Do NOT use `any` in TypeScript. Use `unknown` and narrow.
- Do NOT import from `apps/api` in `apps/web` or vice versa. Use packages/shared.
- Do NOT use `console.log` in production code. Use the logger in packages/shared/src/logger.ts.

## Known Gotchas

- Drizzle's `db.query.*` API requires the relational schema to be passed at client init time. See packages/db/client.ts.
- Hono middleware runs in declaration order. Auth middleware must be registered before route handlers.
- The web app uses the App Router. Do not use getServerSideProps or pages/api — those are dead.

Quel file viene caricato all'inizio di ogni sessione dell'agente. L'agente conosce ora i pattern vietati, le posizioni degli helper, la convenzione di denominazione dei file di test e i comandi da eseguire. Agisce su quella conoscenza in modo affidabile perché la sta leggendo, non inferendola dalla struttura del codice.

Verifica in un Passaggio Separato

Questa è la regola che la maggior parte delle persone salta, ed è quella che costa di più. Non chiedere allo stesso contesto agente che ha scritto il codice di verificarlo. Il contesto è di parte. L'agente ha un modello di ciò che intendeva scrivere, e quel modello lo porterà a non vedere ciò che ha effettivamente scritto.

Avvia una sessione fresca. Carica l'AGENTS.md. Carica il diff o i file modificati. Dai all'agente un prompt di verifica: "Rivedi le seguenti modifiche rispetto alle convenzioni in AGENTS.md. Riporta eventuali violazioni, test mancanti, errori di tipo e bug logici. Non suggerire miglioramenti, riporta solo i fallimenti." Il contesto fresco non ha alcun legame con il lavoro precedente. Legge ciò che c'è davvero.

Schema di un ciclo di verifica a due passaggi: sessione di scrittura e sessione di verifica separata collegate da un file markdown di memoria
Il passaggio di scrittura e quello di verifica condividono un'unica fonte di verità: il file markdown di memoria.

Abbinalo a un passaggio di verifica automatizzato che l'agente può eseguire da solo. Il ciclo seguente non è brillante, è solo disciplinato:

ts
// scripts/verify-loop.ts
// Run with: bun run scripts/verify-loop.ts
// Iterates: typecheck → test → lint. Prints first failure and exits.

import {execSync} from 'child_process';

const steps = [
  {name: 'typecheck', cmd: 'bun run typecheck'},
  {name: 'test',      cmd: 'bun run test --bail'},
  {name: 'lint',      cmd: 'bun run lint'},
] as const;

for (const step of steps) {
  console.log(`\n--- ${step.name} ---`);
  try {
    execSync(step.cmd, {stdio: 'inherit'});
    console.log(`${step.name}: PASS`);
  } catch {
    console.error(`${step.name}: FAIL — stopping.`);
    process.exit(1);
  }
}

console.log('\nAll checks passed.');

L'agente esegue questo script dopo ogni modifica non banale. Se fallisce, l'agente ti riporta il fallimento. Decidi tu se iterare o fare rollback. Lo script è deterministico. L'agente non sta facendo valutazioni su se i test "passano più o meno".

Tieni l'Architettura nella Tua Testa

Il file markdown alleggerisce le convenzioni e i comandi. Non alleggerisce il giudizio architetturale. Devi ancora sapere perché esiste il service layer, perché l'auth è in un pacchetto condiviso, perché hai scelto Drizzle invece di Prisma. L'agente può seguire pattern. Non può ragionare su se i pattern siano ancora appropriati per il problema che stai risolvendo ora.

Quando un task richiede una decisione architetturale, prendila tu prima di aprire la sessione con l'agente. Scrivi la decisione nell'AGENTS.md prima di chiedere all'agente di implementarla. La sequenza è: decidi tu, documenti tu, l'agente implementa. Non: l'agente implementa, tu scopri la decisione che ha preso, e poi la accetti o la annulli.

  • Sei tu il responsabile del grafo delle dipendenze. L'agente non sa cosa costa aggiungere un nuovo pacchetto.
  • Sei tu il responsabile del modello dei dati. Le modifiche allo schema sono difficili da invertire. Non delegarle mai senza una specifica scritta.
  • Sei tu il responsabile del confine di sicurezza. L'agente implementerà qualsiasi flusso di autenticazione tu descriva, inclusi quelli errati.
  • Sei tu il responsabile del rilascio. L'agente non ha interesse nel fatto che la produzione rimanga attiva.

Il Ciclo in Pratica

Una sessione reale si presenta così. Identifichi un task. Scrivi una specifica con abbastanza vincoli affinché l'agente non abbia ambiguità su posizioni dei file, confini delle interfacce e criteri di accettazione. Carichi AGENTS.md e i file sorgente rilevanti. Dai all'agente il primo passo del lavoro scomposto. Produce un output. Lo leggi. Se è buono, passi al passo due. Quando tutti i passi sono fatti, avvii una sessione fresca per il passaggio di verifica. Il verificatore riporta i fallimenti. Reindirizzi i fallimenti al contesto dell'implementatore o li correggi tu stesso.

L'intero ciclo è forse trenta percento più lento rispetto al prompt casuale e alla speranza. Produce codice che non ti imbarazza in review e non ti sveglia alle 3 di notte.

Il cambiamento nel modello mentale è semplice: smetti di chiederti cosa sa fare il modello e inizia a chiederti cosa stai fornendo tu, come operatore. Qualità della specifica, qualità della scomposizione, qualità del file di memoria, disciplina di verifica. Queste sono le variabili che controlli. Controllale, e l'agente diventa un vero moltiplicatore di forza. Ignorale, e hai un autocomplete costoso.

Portfolio · Cartiglio
Disegnato da
G. STANCUTA
Disciplina
AI & AUTOMATION
Luogo
MORTER · SÜDTIROL
Stato
Disponibile
Lingue
IT · EN · RO · DE+
Stack
PLOI · HETZNER
Revisione
REV 2026.A
2026

© 2026 Gabriel Stancuta · jumpinotech.com — Progettato con l'AI, costruito per funzionare da solo.