Blog

Codex CLI, structured JSON outputs, and cron-safe AI workers

Note di ingegneria Naly: Codex CLI, JSON strutturato e worker AI sicuri per cron

Questa nota descrive come Naly trasformi Codex CLI da agente di coding da terminale in un worker di produzione deterministico combinando pianificazione cron, contratti JSON rigorosi e log esternalizzati. Spiega perché l'affidabilità deriva da invarianti operativi: lock, retry e validazione, mentre il modello rimane sostituibile,

June 25, 20269 sources

Abstract

Naly usa Codex CLI come piano di controllo per il lavoro IA schedulato: ogni voce cron esegue uno script versionato che avvia un task assistente delimitato con ricerca web e un contratto di output rigoroso, quindi scrive artefatti JSON validati per pubblicazione, replay e retry a valle. Questo rende il lavoro del modello simile a una pipeline operativa: stesso comando, schema esplicito, artefatti espliciti, invece di un flusso interattivo mutabile. Alla data del 2026-06-25, questa distinzione è il vantaggio di affidabilitaà per l’infrastruttura editoriale critica per la crescita.

Dove si inserisce in Naly

Naly ha già priorità GST attive su flussi di scoperta, retention e distribuzione. Questo pattern si inserisce direttamente in quello strato esecutivo:

  • I job cron invocano un singolo tsx script per caso d’uso, quindi ogni run resta dentro codice versionato, non in snippet shell ad hoc.
  • Codex CLI gestisce il ragionamento e il recupero, mentre Naly gestisce il controllo di orchestrazione: pianificazione, retry, lock e artefatti persistenti.
  • L’output strutturato alimenta i sistemi a valle basati su Next.js, React, Drizzle ORM e Neon senza ipotesi sullo schema a valle.
  • I log esterni e i metadati di run vengono scritti in NALY_LOG_ROOT, rendendo riproducibili i post-mortem indipendentemente dal buffering dell’output del processo.

La tesi è: per l’uso in produzione, la qualità degli LLM è solo mezza del sistema; i confini deterministici intorno a quell’LLM sono l’altra metà.

Meccanismo tecnico

1) Punto di ingresso worker orientato al contratto

Ogni task parte da tre input immutabili:

  • Un template di prompt codificato e l’intento del task.
  • Uno schema di risposta che deve essere validato.
  • Un envelope di run (run_id, source_query, attempt, env), persistito prima della chiamata API.

Naly invoca Codex CLI in modalità batch da cron, non in modalità interattiva. Codex è documentato come agente di coding locale e distribuito come CLI autonoma con distribuzione open-source e release attive, e può essere eseguito in un ambiente scriptato Codex CLI, repository OpenAI Codex.

2) Perché l’output strutturato è non negoziabile

Le guide di output strutturato di OpenAI descrivono l’estrazione supportata dal parser e il comportamento strict necessario per pipeline machine. In Naly, l’output del modello è trattato come artefatto intermedio, non verità finale, quindi il contratto JSON è dove viene fatta rispettare l’affidabilità:

  • campi obbligatori (headline, evidence list, confidence, citations, failure reason)
  • campi opzionali con valori predefiniti
  • confidence numerica ed enum con limiti
  • fallimenti parser espliciti esposti come errori di run, non testo autocorretto in modo silenzioso.

3) Life-cycle cron-to-agent con controllo della concorrenza

Cron esegue linee schedulate secondo i campi temporali standard a 5 campi e avvia un comando quando i campi corrispondono crontab. Per la sicurezza di produzione Naly aggiunge:

  • guardia lock (un solo run attivo per task)
  • chiave run idempotente
  • politica retry con limite e jitter
  • cattura log esterna per ogni fase
  • aggiornamento dello stato post-run nelle tabelle database gestite da Drizzle/Neon.

flock è progettato esattamente per questo pattern di guardrail: acquisire un lock, eseguire la sezione critica, uscire in modo pulito quando già lockato flock. Poiché lo stato del lock segue i file descriptor, le finestre cron sovrapposte sono esplicitamente negate invece di corrompere lo stato.

4) Perché MCP conta in questo pattern

Model Context Protocol formalizza i contratti host/client/server degli strumenti usando JSON-RPC, negoziazione capability e chiamate di tool strutturate MCP. In Naly, i confini in stile MCP riducono il coupling implicito: la ricerca web può essere rappresentata come interfaccia di tool controllata con capability esplicite invece di comportamento libero a livello shell.

Cosa dice la letteratura

Ricerche recenti mostrano che l’affidabilità non è equivalente alla semplice capacitá. Il paper AI Agent Reliability riporta gap sostanziali tra accuratezza del task e consistenza tra run, e propone dimensioni esplicite di affidabilità (consistency, robustness, predictability, safety) per la valutazione operativa Towards a Science of AI Agent Reliability. Questo supporta il design di Naly run-state-first: se una run riesce ma non può essere ripetuta con artefatti chiari, non è di livello production.

Per gli output strutturati, ToolPRM sostiene che il comportamento di tool-calling strutturato richieda supervisione esplicita e che i miglioramenti siano particolarmente forti quando si modella il processo interno di function-calling piuttosto che solo gli esiti finali ToolPRM: Fine-Grained Inference Scaling of Structured Outputs for Function Calling. Cì si allinea con il loop runner schema-first di Naly: il gate qualitativo è ai confini dell’interfaccia, non solo alla fluidità del contenuto.

Un terzo paper sulla stessa frontiera, SLOT, mostra un percorso alternativo pratico aggiungendo uno strato model-agnostic di shaping dell’output sopra gli LLM SLOT: Structuring the Output of Large Language Models. Rafforza lo stesso principio: l’affidabilità strutturale è un problema di ingegneria anche quando la qualità del modello base è alta.

Trade-off di design

  1. Schema rigido vs. portabilità del modello: gli schemi strict riducono l’ambiguità a valle ma possono aumentare il parse churn occasionale quando i provider interpretano diversamente i vincoli.
  2. Semplicità di cron vs. elasticità della coda: cron è semplice e visibile, ma workload bursty richiedono backoff lock-aware o un layer queue per evitare run sovrapposti e finestre perse.
  3. Ricerca web in-task vs. replay deterministico: la ricerca web aggiornata migliora la freschezza ma introduce volatilità delle fonti; per questo Naly salva testo query, lista sorgenti e riferimenti grezzi negli artefatti di run.
  4. Log esterni vs. log solo DB: i log filesystem sopravvivono ai riavvii dei processi e sono economici per ingestione; i log DB semplificano l’ergonomia delle query ma possono fallire i loop aperti se non sono partizionati con cura.

Failure modes

  • Schema drift: output del provider viola lo schema; la mitigazione è validazione fail-fast strict, schema version pinning e run in dead-letter.
  • Esecuzioni cron sovrapposte: scritture doppie o azioni esterne duplicate; mitigazione è advisory lock + process-exit guard.
  • Instabilità della ricerca: le risposte dello strumento a monte cambiano tra tentativi; mitigazione sono limiti di retry, ritardo esponenziale e riferimenti upstream persistiti.
  • Sorpreses di temporizzazione: differenze DST e timezone host possono influenzare la semantica di schedule; mitigazione sono policy di scheduling UTC e controlli espliciti dell’ambiente.
  • Scritture parziali silenziose: il parse ha successo ma la scrittura a valle fallisce; mitigazione è ordering di persistenza transazionale e upsert idempotenti.
  • Security/context leakage: qualunque percorso agent con capacità strumenti può estendersi troppo, quindi sono necessari confini MCP-like a minimo privilegio e assunzioni esplicite di consenso/autenticazione, soprattutto dove i percorsi di esecuzione strumenti toccano risorse di rete Note di sicurezza MCP.

Note di implementazione

  • Mantieni un comando worker per singolo business task in scripts/ e fai in modo che cron chiami solo quel punto di ingresso.
  • Memorizza l’hash del file schema nei metadati di run in modo che le attese del parser siano tracciabili dopo un upgrade del modello.
  • Imposta set -euo pipefailil comportamento in stile -euo pipefail negli script wrapper e includi sempre gli ID run nei nomi dei log.
  • Scrivi tre checkpoint nei log: started, codex_result_parsed, artifact_persisted.
  • Usa NALY_LOG_ROOT così le tracce runtime non inquinino lo stato del repository e sopravvivano ai contesti di riavvio.
  • Persisti attempt, exit_code, retry_reason, e validation_errors per permettere a GST e ai dashboard di audit di separare infrastruttura instabile da regressioni modello autentiche.

Riferimenti

Sources