← Indice documentazione Guida all'architettura › executor

Metnos

executor — capire come è fatto
Guida introduttiva

Un executor è un'unità operativa con argomenti, effetti, capacità e profilo di isolamento dichiarati in un manifest firmato. Il sistema mantiene distinta la provenienza degli executor distribuiti, generati e importati; il catalogo generato fornisce conteggi, domini e stato corrente senza duplicarli in questa pagina.

Chiedi a Metnos con una richiesta come quella di questo esempio: «Cerca nella cartella Documenti tutti i PDF che contengono la parola contratto». Metnos può comporre più executor: uno trova i file, un altro ne legge il contenuto e un terzo filtra i risultati. L'utente descrive il risultato voluto; non deve conoscere i nomi degli executor.

Indice

  1. Cos'è un executor (in trenta secondi)
  2. Come distinguere gli executor: luogo, elaborazione e parallelismo
  3. Anatomia: manifest, firma e implementazione
  4. Il manifesto: il biglietto da visita
  5. Il recinto: cosa può fare e cosa no
  6. La vita di un executor
  7. Le quattro origini: a mano, generato, importato, di sistema
  8. Quattro esempi concreti
  9. Per andare più a fondo

1. Cos'è un executor (in trenta secondi)

Un executor è una piccola unità operativa specializzata che fa una cosa sola: legge la posta, cerca un file, ottiene l'ora, manda un messaggio. Quelli eseguiti come sottoprocesso hanno una propria cartella; quelli interni al processo conservano lo stesso contratto logico.

Pensa a una cassetta degli attrezzi. Ogni attrezzo è semplice e riconoscibile: il cacciavite stringe le viti, il martello batte i chiodi. Nessuno chiederebbe al cacciavite di battere un chiodo. In Metnos è lo stesso: ogni executor è un attrezzo con un compito chiaro. Quando l'utente chiede qualcosa, il pianificatore sceglie l'attrezzo giusto e lo usa.

Tre aspetti indipendenti

Le parole locale, remoto, intelligente e parallelo non descrivono quattro famiglie alternative: indicano aspetti diversi dello stesso executor. Uno stesso executor può, per esempio, essere deterministico, eseguibile anche su un dispositivo associato e restare seriale.

1. Luogo di esecuzioneDove può essere eseguito
Serverscope = "server": viene eseguito solo sul server Metnos. Dispositivo associatoscope = "device": viene eseguito su un dispositivo riconosciuto e associato. Server o dispositivoscope = "any" con device_ok = true: parte dal server e può essere assegnato al dispositivo indicato nella richiesta.
2. Modalità di elaborazioneCome svolge l'azione
DeterministicoEsegue codice, regole o un algoritmo senza usare un modello linguistico. Con LLMAffida una parte dell'azione a un modello linguistico, mantenendo lo stesso contratto, limiti e controlli. Con agentePuò svolgere un ciclo interno, delimitato, di osservazione e proposta. Questa modalità viene dichiarata esplicitamente, mai dedotta dal nome.
3. ParallelismoSe può essere eseguito insieme ad altri
Serialeparallelism_class = 0: è la scelta prudente predefinita. Eseguibile in paralleloLe classi 1–3 sono una dichiarazione esplicita: lo scheduler centrale valuta ogni esecuzione in base a equivalenza verificata, effetto, risorsa e limiti. Stessa risorsa, invocazioni in codaLe invocazioni che non sono di sola lettura e usano la stessa chiave di concorrenza restano seriali.

Come leggere questa carta. Il luogo di esecuzione non concede nuovi permessi; la modalità di elaborazione non concede nuova autorità; il parallelismo non è una promessa di velocità. Sono fatti dichiarati dal contratto e applicati dal runtime. Per il protocollo tra server e PC vedi gli executor remoti; per gli executor con un ciclo interno di ragionamento vedi gli executor intelligenti.

get_processes

Server o dispositivo · deterministico · seriale.

find_files

Server o dispositivo · deterministico · classe 3 verificata.

act_sites

Server · con agente · seriale.

argomenti {tz: "Europe/Rome"} get_now una cosa sola: restituisce data e ora manifesto firma risultato 2026-05-06 16:45 cosa chiedo l'attrezzo che esegue cosa ricevo
Un executor è una scatola con un compito preciso, un contratto in entrata e uno in uscita.

Le tre cose che lo definiscono sono:

Perché gli executor sono piccoli

Più compiti riunisce uno strumento, più diventa difficile verificarne contratto, autorizzazioni ed effetti. Separare la cancellazione dei file dall'invio di posta rende ogni passaggio leggibile e controllabile. Quando Metnos compone più executor, il piano e ciascuna esecuzione conservano i propri controlli.

2. Anatomia: manifest, firma e implementazione

Gli executor distribuiti nel catalogo principale usano normalmente una cartella piatta con quattro file. Il contratto, però, non impone il numero quattro: il manifest può elencare più file di codice e gli executor interni al processo conservano il contratto firmato separato dall'implementazione.

get_processes/ manifest.toml il biglietto da visita: nome, cosa fa, argomenti, esempi, schema dell'output manifest.toml.sig la firma crittografica del biglietto da visita: dimostra chi l'ha scritto get_processes.py il codice vero e proprio: una funzione invoke(args) che esegue il compito manifest.lang_state.json stato di traduzione (multilingua): solo se ci sono descrizioni in più lingue struttura comune del catalogo distribuito
La struttura usata dagli executor distribuiti: manifest, firma, entry point e stato delle traduzioni. Il manifest resta la fonte autorevole per i file di codice firmati.

Per un executor attivo eseguito come sottoprocesso, manifest, firma e codice formano il nucleo. Il codice fa il lavoro; il manifest permette al pianificatore di valutarne il contratto; la verifica crittografica rileva modifiche successive alla firma.

FileCosa contieneChi lo legge
manifest.tomlNome, descrizione, argomenti, esempi, schema dell'output, capacità dichiarate e policy di esecuzioneil pianificatore (per scegliere), il loader (per caricare)
manifest.toml.sigFirma Ed25519 dei byte del manifest; il manifest contiene anche l'impronta dei file di codiceil loader, durante l'ammissione al catalogo
<entrypoint>.pyIl punto d'ingresso del sottoprocesso; altri file possono essere dichiarati in [code].filesil runtime, quando l'executor viene invocato
manifest.lang_state.jsonImpronte delle descrizioni per linguagli strumenti che mantengono allineate le traduzioni

Il loader non deduce il contratto dalla forma della cartella: legge il manifest, verifica standard, firma e impronta del codice, controlla l'entry point e soltanto allora ammette l'executor. I contratti degli executor interni al processo si trovano in runtime/builtin_executor_contracts/ e subiscono la stessa verifica crittografica.

3. Il manifesto: il biglietto da visita

Il manifesto è un file in formato TOML. Lo apri con un editor di testo e ci capisci qualcosa anche senza essere un programmatore. Dichiara tutto quello che il pianificatore deve sapere: come si chiama l'executor, cosa fa, che argomenti accetta, come è fatto il risultato, qualche esempio per orientarsi.

name = "get_now" version = "0.2.0" affinity = ["time", "ora", "data", "now", "what time"] [description] en = "SCOPE: gets the current date and time..." [args.properties.timezone] type = "string" default = "Europe/Rome" [output] schema_inline = "{ ok: bool,... }" [code] files = ["get_now.py"] digest = "sha256:788db417..." [[capabilities]] name = "time:read" identity routing terms help the prefilter retrieve the tool purpose SCOPE / PATTERN / NOT / OUT arguments type, default, description result shape what the tool returns, field by field code + fingerprint the digest changes when code changes capabilities requested authority
Un estratto del manifest corrente di get_now, abbreviato per facilitarne la lettura. Mostra alcuni campi rappresentativi, non lo schema completo.

A proposito di affinity. È intenzionalmente una lista indipendente dalla lingua di hint canonici per l'instradamento, non prosa mostrata all'utente. Il validatore multilingue ne controlla struttura e sovrapposizioni; il riconoscimento del linguaggio naturale appartiene invece al lessico di detection versionato, con copertura e politica di revisione esplicite. Vedi Lingua e internazionalizzazione.

Cosa c'è di importante

Tre cose meritano un secondo sguardo, perché sono quelle su cui si regge l'intero sistema.

L'impronta del codice (digest): è un'impronta crittografica calcolata sui byte del file .py. Se qualcuno modifica anche solo una virgola nel codice senza ricalcolare l'impronta, il loader rifiuta l'executor. Il manifesto e il codice sono legati come un certificato e il documento che certifica.

La forma del risultato (output.schema_inline): dichiara campo per campo cosa restituisce l'executor. Serve a chi compone catene di executor (il pianificatore non vola alla cieca: legge lo schema e sa cosa aspettarsi al passo successivo) e a chi genera codice in automatico.

Quando un dato non deve essere attenuato dalla prosa generata, l'executor può restituire anche una authoritative_presentation con un ambito semantico chiuso: per esempio un conteggio esatto o un insieme di duplicati verificati. Il runtime usa questi frammenti soltanto se coprono tutti i passi produttivi del turno; negli altri casi conserva il normale compositore finale. Il limite di visualizzazione resta così distinto dal lavoro svolto: un frammento può dichiarare completa una scansione solo se l'executor attesta anche la completezza della sorgente. Il frammento sostituisce il normale avviso di troncamento soltanto quando questa composizione integrale riesce per l'intero turno: un passo coperto non può nascondere il limite di una pipeline che, nel suo insieme, non è coperta.

Gli identificativi possono inoltre richiedere un contesto di origine dichiarato nel manifest. Una lista può proiettare entries[*].uid tramite from_entries_key; proprietà scalari come account e cartella di origine possono dichiarare un from_entries_required condizionale. La proiezione accetta questi valori soltanto se tutte le righe concordano. Una chiamata diretta deve fornire esplicitamente lo stesso contesto applicabile; se manca, il punto unico di invocazione la rifiuta prima di qualunque effetto.

I permessi (capabilities): non è il manifesto a stabilire cosa l'executor può fare. Il manifesto dichiara di cosa avrebbe bisogno per funzionare; poi il sistema decide se concedere quei permessi e con che vincoli. Vedi sandbox.

[[capabilities]]
name = "provider:access"
hint = ["google-workspace"]
when = { arg = "client", values = ["google_workspace"] }

Per un backend remoto la clausola when restringe la dichiarazione alla singola invocazione. Solo quando il valore finale di client corrisponde, lo stesso binding abilita rete, home delle credenziali in lettura-scrittura e collocazione sul server. Un valore arbitrario in client non concede nulla.

Una sola politica di esecuzione

Ogni invocazione passa da uno scheduler centrale del runtime. Se la sezione [execution] manca, è incompleta o non è valida, il loader sceglie sempre la modalità seriale. Il parallelismo è quindi una proprietà opt-in del contratto firmato, ammessa soltanto dopo test ripetuti di equivalenza fra esecuzione seriale e concorrente.

ClasseSignificato portabileComportamento
0Nessun threadResta sul thread del chiamante.
1ModerataUsa una quota contenuta del pool centrale.
2AltaRichiede più concorrenza, entro i limiti della risorsa.
3MassimaÈ comunque limitata da hardware, backend e tetti globali.

All'avvio il runtime osserva le CPU visibili e il limite operativo max_workers, e stabilisce un solo tetto per l'istanza. La classe firmata è una riduzione di quel tetto, non un numero fisso di thread: il singolo executor può soltanto ridurre l'assegnazione in base alla quantità di lavoro o al profilo di I/O. Applica nello stesso punto code limitate, backpressure, pool per risorsa e metriche, senza cambiare argomenti, risultati, ordine causale, permessi o criteri di successo. Un executor non di sola lettura può dichiarare una classe positiva, ma deve anche fornire un'identità di concorrenza verificabile; invocazioni sulla stessa identità restano seriali.

Gli executor che usano un LLM seguono la stessa regola. All'avvio, framework e hardware determinano il tetto della risorsa LLM: un backend a singolo slot degrada a classe 0, mentre un backend con batching può ammettere più richieste. Non esistono pool concorrenti indipendenti nascosti nei singoli executor.

Le ricerche ricorsive sul filesystem usano un visitor comune: le directory formano una coda dinamica, i worker liberi prendono il prossimo ramo e i risultati vengono riordinati prima di applicare un limite. Per esempio, la ricerca dei duplicati confronta prima dimensione e campioni, poi calcola SHA-256 completo sui soli candidati; il limite di visualizzazione non riduce l'insieme confrontato.

Perché il contratto usa TOML

Il manifest deve poter essere letto, commentato e aggiornato durante una revisione. TOML conserva questa leggibilità senza rinunciare a una struttura che il loader può convalidare in modo rigoroso.

4. Il recinto: cosa può fare e cosa no

Il manifest dichiara le capacità massime richieste dall'executor. Prima dell'invocazione il runtime controlla gli argomenti concreti, risolve le sole risorse necessarie e applica i controlli di identità, Vaglio e policy. La sandbox è un ulteriore livello di contenimento; non concede autorizzazioni e non sostituisce quei controlli.

LivelloComportamento corrente sul server
Contrattocapabilities, collocazione, piattaforme e politica di esecuzione provengono dal manifest firmato.
Controlli applicativiGli argomenti possono restringere un ambito firmato, mai ampliarlo; identità, consenso e destinazione vengono verificati prima del sottoprocesso.
Bubblewrap attivoCodice e runtime sono in sola lettura, /tmp è privato, le risorse dati sono montate con l'accesso necessario e la rete viene separata quando nessuna capacità la richiede.
Bubblewrap assente o disabilitatoIl server fallisce chiuso prima del registro di annullamento e del sottoprocesso. Soltanto il broker undo vincolato ai byte esatti usa il percorso diretto.

La rete è attualmente binaria: quando serve, il processo eredita la rete dell'host; non viene applicata una lista di domini. Alcune radici di sistema, fra cui /etc, sono visibili in sola lettura. Per montaggi, eccezioni, declassamenti e differenze fra Linux, Windows e macOS, vedi la guida alla sandbox.

5. La vita di un executor

Il campo lifecycle separa i candidati dagli executor disponibili al pianificatore. Una distribuzione può caricare una generazione esatta già ammessa, ma nessuna generazione nuova o modificata diventa active soltanto perché la sua sorgente è stata revisionata. Ogni origine attraversa lo stesso confine Executor Birth prima dell'attivazione.

StatoSignificatoÈ in pool?
proposedMetadati di triage senza file di codice; se dichiara codice, il loader lo rifiuta.No; visibile soltanto alle superfici di lavoro e audit.
synthesizedCandidato con codice. Quando la verifica delle firme è attiva deve già superare firma, impronta ed entry point, ma non è ancora ammesso al composer.No; disponibile al percorso Synt.
activeContratto ammesso e visibile al pianificatore.Sì, salvo disabilitazione o dormienza per prerequisiti mancanti.
deprecatedEscluso dalle nuove composizioni; resta indicizzato in forma compatta per diagnosi e sostituzione.No.
archivedEscluso dal catalogo operativo; lo stato resta nel registro di durata.No.

L'invecchiamento automatico per inattività riguarda soltanto gli executor generati da Synt: dopo 30 giorni senza uso diventano deprecated e, dopo altri 14 giorni in quello stato, archived. Gli executor curati a mano, quelli importati come skill e i nomi protetti non vengono ritirati per il solo fatto di essere usati di rado. Le soglie sono configurabili e il ripristino richiede un'azione esplicita.

Il solo confine di nascita

Executor Birth acquisisce una fotografia privata del candidato completo, assegna identità stabili ai byte esatti e al contesto di ammissione e applica tutti i controlli obbligatori di struttura, politica, localizzazione, instradamento e prova. Una revisione prodotta da un modello o importata riceve anche una revisione semantica indipendente; dove la politica lo richiede serve un'approvazione umana legata al candidato esatto. Un controllo obbligatorio fallito o indisponibile interrompe la transizione.

Soltanto il confine di commit Birth può consegnare un candidato ammesso al deposito immutabile dei contratti. Rilegge quindi manifest e codice pubblicati prima di esporre la generazione come attiva, in preesercizio o in quarantena. Una firma isolata, una directory copiata o il riavvio di un servizio non possono rendere operativi byte modificati. Gli aggiornamenti del manutentore usano runtime/stack_reconcile.py deploy --executor <name> --sign; il flag di compatibilità consegna il candidato a Executor Birth e non seleziona il precedente pubblicatore diretto.

Durante la transizione, l'inventario e il primo caricamento del catalogo usano lo stesso insieme di chiavi pubbliche autore già autenticato da Birth. In esercizio, il lettore usa le autorità del contesto Birth installato; un processo amministrativo separato le verifica dalla catena corrente. Nel deposito chiuso, chiavi mancanti o un contesto non valido interrompono la lettura: la vecchia directory delle chiavi non viene consultata come ripiego.

Il servizio legge la catena firmata senza aprire il file privato con cui root coordina le scritture; ne verifica comunque i metadati esatti. Il controllo amministrativo verifica anche il byte marcatore. I controlli d'avvio possono riusare l'analisi pura di un solo insieme identico di percorsi e byte nello stesso processo, mai le verifiche dei file, delle firme o dei servizi vivi. Anche gli import dichiarati possono riusare l'analisi sintattica; la loro risoluzione sul filesystem viene sempre ripetuta. Lo stesso riuso limitato si applica al lettore dei servizi: le osservazioni prima e dopo la lettura restano indipendenti e vive, senza ripetere l'analisi sintattica degli stessi byte. Il riuso rispetta anche gli esatti limiti di analisi. Le analisi delle operazioni su file e dei comandi esterni si applicano soltanto alle chiamate pertinenti, senza cambiare la classificazione delle autorità. Gli arresti per segnale sono letti nel formato nativo di systemd, senza modificare il comando firmato o considerarli un successo.

Ogni modulo Python dei servizi viene risolto dalla directory di lavoro indicata nel catalogo firmato. Il servizio delle attività lunghe usa la sottocartella runtime; non dipende dai percorsi ereditati dalla sessione di sviluppo. Una prova controlla questo vincolo per tutti gli avvii Python dichiarati.

Prima di rendere obbligatoria la nuova distribuzione, la transizione lega i byte autenticati del candidato alle ricevute durevoli. Non richiede in anticipo l'archivio che viene pubblicato soltanto dopo il certificato, ma rifiuta un archivio già presente e incoerente. Il catalogo delle ricevute dei contratti e quello dei servizi hanno identità distinte: entrambi vengono controllati, senza usare l'uno come prova dell'altro o anticipare la pubblicazione.

Il controllo della struttura dei servizi lega anche i percorsi scrivibili alla directory personale firmata dell'account. Cambiare questa directory non cambia la struttura ammessa: restano esatti i percorsi relativi per dati e stato. Percorsi aggiuntivi o diversi sono rifiutati, anche con impronte ricalcolate.

Per le dipendenze di codice tra executor, il processo principale seleziona soltanto le chiavi pubbliche che hanno autenticato i contratti richiesti. Nella sandbox Linux queste chiavi sono esposte in un montaggio privato di sola lettura, separato dai percorsi di configurazione; senza dipendenze il montaggio resta vuoto. Il processo figlio non può aggiungere chiavi o sostituire il montaggio creando un nuovo ambiente di isolamento. Le scritture esplicitamente consentite e la directory temporanea restano disponibili.

La distribuzione Linux include nell'ambiente Python gestito anche il driver Playwright e conserva i permessi di esecuzione dei programmi forniti dai pacchetti; i browser restano risorse installate separatamente. Dopo la transizione, la verifica di disponibilità osserva le unità e l'ambito indicati dal catalogo firmato corrente, senza modificare servizi o ampliare i comandi di controllo. Un catalogo non valido interrompe la verifica: non viene sostituito silenziosamente con la configurazione precedente.

Il catalogo firmato avvia HTTP con METNOS_ENGINE=v3, senza ereditare aggiunte arbitrarie alle unità (.service.d) o all'ambiente di avvio. Le impostazioni private restano nel file esistente $METNOS_USER_CONFIG/runtime.toml: default_account nella sezione [mail] è una stringa non vuota, con valore predefinito metnos_system; nightly_enabled in [telos] è un booleano, predefinito false. METNOS_DEFAULT_MAIL_ACCOUNT e METNOS_TELOS_NIGHTLY prevalgono sui rispettivi valori nel file; per Telos soltanto il valore esatto 1 nell'ambiente abilita l'attività notturna.

HTTP risolve una sola volta il conto SMTP dopo la verifica Birth e prima dell'avvio dei processi di lavoro: gli executor ereditano il nome risolto, senza ricevere il file privato, mentre un conto esplicito nell'invocazione continua a prevalere. Un conto predefinito vuoto o di tipo errato e un'impostazione Telos non booleana nel file vengono rifiutati, senza scegliere silenziosamente un altro valore. Questa precedenza non autorizza modifiche alle unità firmate né inserisce valori personali nel catalogo pubblico.

La configurazione dei servizi viene firmata prima dell'avvio dei timer. I collegamenti automatici di attivazione e ordinamento di un preciso timer firmato possono comparire al caricamento o all'avvio senza richiedere una nuova firma. Anche i valori equivalenti di un controllo di vitalità non configurato e disattivato hanno una sola rappresentazione. Per un controllo configurato, il valore iniziale di systemd è ammesso solo se la stessa osservazione prova che il servizio è inattivo, senza processi principali o di controllo e mai avviato. Il valore firmato resta canonico; dopo l'avvio un controllo disabilitato o diverso viene rifiutato. Attivatori inattesi, nuove dipendenze e modifiche ai valori esplicitamente dichiarati restano soggetti alla verifica rigorosa.

6. Le quattro origini: a mano, generato, importato, di sistema

Tutti gli executor espongono lo stesso contratto logico, ma nascono in quattro modi diversi. La distinzione non è cosmetica: cambia chi li scrive, dove vivono e quale provenienza viene registrata.

Scritti a mano

L'autore li compone con pazienza. Sono il nucleo stabile, il seed da cui parte tutto.

Cartella: executors/ nell'installazione.

Esempi: get_now, find_files, read_messages, send_messages.

Stretti, robusti, rivisti più volte.

Generati al volo

Quando il catalogo non copre una richiesta, il Synt compone un nuovo executor con cinque passi (nome, contratto, prove, descrizione, codice).

Cartella: ~/.local/share/metnos/executors/

Esempio: un candidato ristretto preparato, su richiesta governata, quando il catalogo non copre una capacità necessaria.

Tenuti separati: non possono mai fare ombra ai seed scritti a mano.

Importati da skill esterna

Una skill pubblica descrive l'uso di un servizio terzo. Il parser e la mappatura deterministica nel vocabolario chiuso la convertono in uno o più executor Metnos.

Cartella: ~/.local/share/metnos/executors/skills/

Esempi: read_events, set_events, delete_events (da una skill calendario).

Stessi controlli di un generato: niente trattamento di favore per il fatto di venire da fuori.

Di sistema (builtin)

Servizi interni eseguiti nel processo. L'implementazione vive nel runtime e il contratto firmato resta separato.

Contratti: runtime/builtin_executor_contracts/

Esempi: admin, create_tasks, list_skills, describe_images.

Servizi del sistema, non attrezzi normali.

Precedenza del catalogo curato

Un executor generato o importato non può usare il nome di un executor scritto a mano. L'ammissione rifiuta la collisione; se questa viene rilevata durante il caricamento, il catalogo conserva l'executor curato e sposta la cartella sintetizzata in un'area temporanea recuperabile. Una generazione o una skill di terzi non può quindi sostituire silenziosamente il nucleo del catalogo.

Perché l'origine importata esiste

Una libreria di terzi ha tipicamente una sua documentazione testuale che spiega come si usa: «per leggere il calendario chiama gws calendar list; per creare un evento usa --summary e --start». Lo standard agentskills.io ha codificato questa documentazione in un formato preciso (un file Markdown con intestazione strutturata). L'importatore di Metnos legge quel formato, lo traduce nel vocabolario chiuso del sistema, e genera la cartella dell'executor come se fosse scritta a mano.

Il vantaggio: ogni servizio già documentato come skill (calendario di Google, posta, drive di archiviazione,...) si può portare in Metnos senza riscriverlo da capo. Lo svantaggio: bisogna fidarsi di chi ha scritto la skill (e dei suoi script di supporto). Per questo l'importatore non installa nulla in executors/: gli executor importati vivono nella directory dati separata, sotto sorveglianza, e passano comunque dal vaglio prima di ogni chiamata.

Un dettaglio operativo: un executor che richiede credenziali resta dormant e viene escluso dal pool finché i prerequisiti non sono disponibili. Il flusso di configurazione può raccogliere i dati con un dialogo e conservarli cifrati; non è corretto promettere che qualunque prima chiamata possa sempre proseguire da sola. Vedi la guida allo skill importer per i casi ammessi.

7. Quattro esempi concreti

Vediamo quattro executor realmente in uso, raccontati da fuori. Niente codice sorgente: solo cosa chiedi e cosa ottieni.

7.1 get_now — "che ora è?"

L'attrezzo più semplice del catalogo. Non ha argomenti obbligatori. Ritorna un dizionario con la data e l'ora correnti.

chiamata: get_now(timezone="Europe/Rome")
risposta: { ok: true,
 content: "2026-05-06T16:45:23+02:00",
 metadata: { timezone: "Europe/Rome", iso8601: "...", epoch:... } }

Niente rete, nessun file letto, nessuna scrittura. Permessi: time:read. È uno di quegli attrezzi che sembrano superflui finché non si capisce perché servono: il pianificatore non deve mai inventarsi la data dalla memoria di addestramento. Quando deve calcolare "le mail di ieri", chiama prima get_now, poi calcola "ieri" sottraendo. Così "ieri" è sempre quello vero, non quello del giorno in cui il modello è stato addestrato.

7.2 find_files — "trovami le foto"

Cerca file per nome o per modello (le classiche "estensioni"). Restituisce la lista con i metadati di base: percorso, nome, dimensione, data ultima modifica, tipo.

chiamata: find_files(base_path="/home/user/images", pattern="*.jpg")
risposta: { ok: true,
 entries: [
 {path: "/home/.../foto1.jpg", size: 2458123,...},
 {path: "/home/.../foto2.jpg", size: 1923456,...},...
 ],
 metadata: { count: 247,... } }

Il pianificatore lo usa quando deve passare la lista a un altro attrezzo: per esempio filtrare le foto più recenti, calcolare la dimensione totale, comprimere quelle più vecchie. Notare che la filtrazione non sta in find_files: l'attrezzo torna i file e basta. Se vuoi un sottoinsieme, glielo chiedi col modello, oppure passi il risultato a un altro attrezzo che filtra. Una cosa sola alla volta.

7.3 filter_lists — "trovami eventi che si sovrappongono"

Un attrezzo che mette in relazione due liste invece di una. Lo usi quando la domanda dell’utente incrocia due insiemi: «quali appuntamenti HLT si sovrappongono a quelli MNM nei prossimi tre mesi?», oppure «quali file sono presenti sia in questa cartella sia nell’altra?».

chiamata: filter_lists(op="overlap",
 from_step=2, # lista A (eventi HLT)
 with_step=3) # lista B (eventi MNM)
risposta: { ok: true,
 op: "overlap",
 entries: [...gli eventi di A che si sovrappongono ad almeno uno di B... ],
 metadata: { count_a: 4, count_b: 5, count_out: 0 } }

Le operazioni disponibili sono sei. intersect tiene solo le entries presenti in entrambe le liste (il confronto avviene su una chiave indicata, ad esempio il percorso del file). union unisce le due liste eliminando i duplicati. difference tiene le entries di A che non compaiono in B. symdiff è la differenza simmetrica (quel che c’è solo in A o solo in B). overlap è un’operazione temporale: tiene gli eventi di A che cadono in un intervallo sovrapposto a qualche evento di B, riconoscendo da solo i campi di inizio e fine. delta individua invece elementi nuovi o avanzati rispetto a una lista di riferimento e viene usato nei monitor incrementali.

Le tre primitive che lavorano sulle liste hanno ruoli complementari e ben separati: filter_entries riduce una lista applicando un predicato a un campo (where_starts_with, where_contains, where_glob, where_regex); filter_lists combina due liste con le operazioni di insieme appena viste; compute_entries calcola un singolo numero a partire da una lista (somma, media, minimo, massimo, conteggio). Le tre primitive coprono insieme la quasi totalità delle manipolazioni che servono, senza dover introdurre verbi nuovi.

7.4 send_messages — "manda un messaggio a un familiare"

Spedisce uno o più messaggi via Telegram o email. Argomento principale: una lista di messaggi, ognuno con destinatario e testo.

chiamata: send_messages(messages=[
 {to_user: "lucia", body: "Sono uscito, torno alle 7."}
 ])
risposta: { ok: true, ok_count: 1, fail_count: 0,
 results: [{to_user: "lucia", channel: "telegram", message_id: "abc123"}] }

Un attrezzo "trasformativo": modifica il mondo, manda davvero un messaggio. Per questo gli executor che cambiano qualcosa al mondo vengono trattati con più cautela: il loro manifesto dichiara le capacità mail:send e channel:out, e la destinazione viene risolta rispetto all'utente e al canale associati. L'invio è tracciato, ma non è annullabile: il manifest dichiara infatti revertible=false. I controlli devono quindi precedere la consegna. Vedi vaglio per i controlli pre-esecuzione e approval_ux per come si chiede conferma all'utente.

8. Per andare più a fondo

Questo documento è un'introduzione. Se vuoi capire i meccanismi che stanno sotto — come si firma un manifesto, come si applica il recinto, come il Synt genera il codice, come il pianificatore sceglie un attrezzo — i documenti seguenti vanno letti uno alla volta.

Per capire…Leggi
il pianificatore che sceglie l'executor giustoagent_runtime
il recinto in dettaglio (forbidden paths, deroghe, «riordina le foto»)sandbox
come il Synt compone executor nuovisynt
come si importa una skill esterna come executorskill importer
il controllo che precede l'esecuzione di azioni rischiosevaglio
come l'utente vede e approva le azioniapproval_ux
la memoria che le esecuzioni lasciano dietro di sémnest e mnestoma
il dialogo con il mondo (Telegram, web, voce)channel
quali modelli (LLM, embedding, VLM) muovono gli executor e come si cambiano da un TOMLvirtualizzazione dei modelli
l'osservabilità (cosa è successo, perché, quando)observability

Non occorre leggere queste guide in ordine. Parti dalla domanda concreta, segui i collegamenti pertinenti e fermati quando hai raggiunto il livello di dettaglio che ti serve.


Metnos — executor, introduzione didattica