← Indice documentazione Fondamenti › Architettura

Metnos

Architettura — Introduzione
Versione 2.0 — giugno 2026
Riferimento: Metnos 0.1.0 (pre-1.0) — sistema in esercizio quotidiano
Formato HTML self-contained — stampabile PDF

Pubblico: chi vuole capire in 30 minuti com'è fatto Metnos e perché,
senza gergo ma senza ingenuità. Quindici capitoli, quindici diagrammi.

Indice

  1. Cos'è Metnos
  2. Le tre scommesse
  3. I concetti chiave, in sette carte
  4. L'architettura a strati
  5. Anatomia di un turno multitool
  6. Executor: vettoriali per costruzione
  7. Synt: la fabbrica degli strumenti
  8. Quattro tier, un routing deterministico
  9. La memoria che accelera
  10. I sensi: la pipeline immagini
  11. I canali: Telegram e web
  12. Sicurezza e reversibilità
  13. I principi, in otto carte
  14. Cosa NON è Metnos
  15. Dove andare dopo

1. Cos'è Metnos

Metnos è un assistente personale self-hosted con un'idea insolita al centro: invece di nascere con un catalogo fisso di strumenti, sintetizza da sé i propri executor — piccoli programmi firmati, generati al volo dentro un vocabolario chiuso — e li orchestra con un pianificatore LLM locale. Il cloud non serve né per pensare né per agire: i modelli frontier sono un consulto opzionale, non il motore.

Il nome viene da mētis (l'intelligenza astuta) + noûs (la mente). Vive su una macchina sotto il tuo controllo fisico e legale; gli parli dai canali che già usi — Telegram oppure il browser (porta 8770) — e tocca file, mail, foto, calendario, web e GitHub: solo ciò che attivi, una skill alla volta.

Metnos in un colpo d'occhio la tua macchina — dati, logica e modelli restano qui Telefono Telegram, ovunque bottoni di conferma Browser chat + dashboard admin HTTP :8770 long-poll in uscita il processo Metnos Canali daemon Telegram · server web :8770 La mente (cap. 5) intent → memoria dei piani → motore Mētis un piano intero in UNA chiamata LLM routing deterministico: stessa richiesta, stesso piano Le guardie (cap. 12) policy · vaglio (consenso) · sandbox Executor vettoriali (cap. 6) 79 firmati nel repo + sintetizzati al volo lista dentro → lista fuori backend & skill (a tua scelta) file & cartelle mail (IMAP/SMTP) foto & indici calendario web & ricerca GitHub agiscono qui LLM locale — llama-server :8080 un'unica istanza per i tier fast · middle · wise istanza di riferimento: MoE ~35B quantizzato pensa qui memoria persistente mnestoma · fast-path · cronologia undo · audit (SQLite) tier frontier (cloud, opt-in) un consulto quando richiesto — mai il motore self-hosted: nessuna dipendenza obbligata da servizi di terzi; il cloud è una porta che apri tu, non una stanza in cui abiti.
Figura 1 — Metnos in un colpo d'occhio. Il processo vive su una macchina tua: i canali ricevono, la mente pianifica con l'LLM locale, le guardie filtrano, gli executor agiscono sui backend che hai attivato. Il tier frontier è l'unica cosa fuori dal recinto — ed è opt-in.

La carta d'identità

VoceStato reale
FormaProcesso Python ≥ 3.11, microarchitettura a executor; runtime ReAct con pianificazione one-shot (motore Mētis, cap. 5).
Strumenti79 executor firmati nel repo, più quelli sintetizzati al volo dall'istanza (cap. 7) e quelli importati dietro gate (cap. 7). Tutti vettoriali: lista dentro, lista fuori.
CervelloLLM locale servito da llama-server; quattro tier astratti fast / middle / wise / frontier (cap. 8). Frontier = cloud opt-in.
CanaliTelegram (long-poll in uscita, niente porte aperte) + web su porta 8770 (chat e dashboard admin), cap. 11.
SensiPipeline immagini in-process: semantica + volti + EXIF in un indice unificato (cap. 10).
Linguai18n per costruzione: ogni stringa e prompt è dato per-lingua. IT + EN validate; altre lingue = pacchetto di traduzione drop-in (non ancora testate).
Licenza / statoAGPL-3.0; pre-1.0. Repo pubblico: github.com/brunialti/metnos — subset deterministico dell'istanza in esercizio.
Una vetrina onesta, non un prodotto rifinito. Metnos è un sistema vero, usato ogni giorno — ma costruito da una persona, per una persona, su una macchina. È condiviso perché chi si appassiona di homelab e architetture AI possa leggerlo, eseguirlo, costruirci sopra. Molte capacità esistono ma sono state esercitate poco fuori dall'istanza di riferimento.

2. Le tre scommesse

Tutto il progetto sta in tre scommesse architetturali. Sono scelte di campo, non ottimizzazioni: ciascuna rovescia un'abitudine diffusa dei framework agentici.

Tre scommesse, un sistema 1 · Vocabolario chiuso Gli strumenti non si importano a fiducia: si sintetizzano dentro una grammatica chiusa e auditata. «non fidarti del pacchetto: il pacchetto deve guadagnarsi il posto» cap. 3 · 6 · 7 2 · Locale prima Il pianificatore è un LLM sul tuo hardware. Niente giro in cloud per pensare o agire. il frontier è un consulto opzionale, non il motore cap. 8 3 · Determinismo Stessa richiesta → stesso piano, a ogni esecuzione: seed fissato, pareggi rotti da dato curato, grammar. auditabile e testabile come software, non come un prompt cap. 5 · 8 insieme: un agente riproducibile, verificabile, tuo
Figura 2 — Le tre scommesse. Ognuna rovescia un'abitudine dei framework agentici: skill importate a fiducia, cloud-first, LLM come oracolo da rilanciare a ogni turno.

Il confronto, senza sconti

Framework agentico tipicoMetnos
StrumentiScritti a mano, importati o generati free-form, poi eseguiti così come sono, con i privilegi dell'assistenteSintetizzati anch'essi a runtime — ma da un vocabolario chiuso e auditato: firmati, invecchiati, smoke-testati e vagliati prima di poter girare
SicurezzaCi si fida dell'autore del pacchettoNon ci si fida del pacchetto: il pacchetto deve superare i controlli (gate a 7 livelli, cap. 7)
LLMSpesso cloud-firstLocale prima; frontier opt-in
RoutingIl modello sceglie un tool a ogni turno — non riproducibileDeterministico per costruzione: inferenza locale a seed fissato, pareggi rotti da affinity curata (cap. 8)
OutputLibero, diverso per ogni toolUniforme: lista dentro / lista fuori, componibile fra step (cap. 6)
UndoRaro o best-effortDi prima classe: catalogo chiuso di pattern inversi, move = COPY-poi-DELETE, ok_count onesto (cap. 12)
LinguaInglese, stringhe nel codicei18n per costruzione: stringhe e prompt sono dati per-lingua
Perché il determinismo conviene. La maggior parte degli agenti tratta l'LLM come un oracolo da rilanciare: chiedi due volte, ottieni due piani diversi. Metnos fa la scommessa opposta: un pianificatore locale, vincolato a un vocabolario chiuso, può essere reso riproducibile. Così il routing si misura, si mette sotto test di regressione, si audita — come software ordinario. E si accumula: una richiesta già risolta una volta viene rieseguita da un percorso veloce senza alcuna chiamata LLM (cap. 9).

3. I concetti chiave, in sette carte

Sette parole reggono tutto il documento. Definirle adesso vi risparmia mezz'ora di confusione fra trenta righe; ognuna ha la sua pagina di microprogettazione in architecture/.

executor — una capacità eseguibile: un piccolo programma che fa una cosa sola e bene (leggere file, mandare una mail, spostare messaggi, cercare foto). Accetta liste in ingresso e produce liste in uscita, ha un manifest che lo descrive, una firma Ed25519 che lo autentica e un profilo di sandbox che lo confina. È l'unica classe di cose che agiscono nel sistema.
vocabolario chiuso — ogni executor si chiama verbo_oggetto[_qualifier[_descriptor]], componendo 23 azioni e 22 oggetti canonici più qualificatori in quattro famiglie. Non è una convenzione estetica: è il confine di ciò che il sistema può nominare — e quindi sintetizzare. Nuovi termini solo con governance esplicita (necessario · generale · comprensibile).
manifest — la carta d'identità TOML di un executor: descrizione in capitoli prescrittivi (SCOPO / PATTERN / NON / OUT), schema degli argomenti, parole di affinità, pattern di reversibilità, digest del codice. Non è documentazione per umani: è il prompt del tool, scritto perché un LLM medio lo usi bene (cap. 6).
synt — il processo che fa esistere ciò che il pool non sa ancora fare: una cascata di strategie a costo crescente che prima compone executor esistenti e solo come eccezione documentata genera codice nuovo, in cinque stadi più una verifica semantica (cap. 7). Propone; l'umano approva.
vaglio — il filtro che sta sempre prima dell'esecuzione: una guardia deterministica (percorsi vietati, comandi irrecuperabili) seguita da un giudice che pesa le operazioni in zona grigia e, sopra soglia, chiede conferma esplicita all'utente con bottoni sul canale (cap. 12).
mnest · mnestoma — il mnest è il filo che collega due executor attivati insieme: nasce dal contesto, si rinforza con l'uso, decade se non riusato. Il mnestoma è il grafo di tutti i mnest: la memoria associativa del sistema, su SQLite, curata da un processo notturno (l'ager). Dà al pianificatore l'intuizione di «quale executor di solito segue quale» (cap. 9).
skill ↔ backend — due assi ortogonali: la skill decide se un gruppo di capacità è attivo, fidato e configurato (dormiente finché manca il prerequisito); il backend decide come un'azione gira contro un servizio concreto (calendario = ICS locale oppure Google), scelto dalla configurazione — mai dall'LLM. Il pianificatore non vede mai il fornitore.

L'anatomia di un nome

Il vocabolario chiuso è l'idea più fertile del progetto: rende i nomi componibili (il pianificatore può prevedere come si chiama una capacità che non ha mai visto), filtrabili (il prefilter ragiona su verbo e oggetto) e sintetizzabili (synt non può nominare nulla fuori dalla grammatica).

Anatomia di un nome: verbo_oggetto[_qualifier[_descriptor]] find _ images _ indices _ dry-run azione 23 verbi canonici read, write, move, find, get, list, filter, send, … oggetto 22 oggetti canonici files, messages, events, images, urls, entries, … qualifier (opz.) 4 famiglie formato · modalità safety · provider descriptor (opz.) kebab-case, max 30 variante comportamentale a parità di argomenti i 5 verbi-produttori, ortogonali find = pattern / query get = id noti o snapshot read = id → contenuto list = enumera il contenitore filter = predicato su lista l'asse è l'input primario, mai un sinonimo read_messages move_files get_urls classify_entries write_files_doc find_issues_github Il vocabolario è CHIUSO: un termine nuovo entra solo se necessario, generale e comprensibile a un LLM medio. Sinonimi prima dell'estensione; escalation umana per ogni parola nuova. La grammatica decide cosa è nominabile.
Figura 3 — L'anatomia di un nome. Quattro livelli posizionali, di cui gli ultimi due opzionali; i cinque verbi-produttori si distinguono per l'input primario, così il pianificatore non deve mai scegliere fra sinonimi.

4. L'architettura a strati

Metnos è una cipolla: l'esterno parla col mondo, l'interno esegue. Ogni strato si fida solo di quello più interno e i privilegi calano scendendo verso il centro. Una richiesta — venga da un utente o da un task schedulato — li attraversa tutti, nell'ordine.

Gli strati, dall'esterno verso il centro 1 · Canali adattatori verso il mondo: daemon Telegram (pairing, bottoni) · server web :8770 (chat, admin, SSE) runtime/channels/ · metnos_http_server 2 · Runtime del turno normalizza la richiesta · scorciatoie letterali · estrazione dell'intent (verbo + oggetto + parole chiave) agent_runtime · intent_extractor 3 · Motore cognitivo — Mētis memoria dei piani (fastpath ★ · autopath) → prefilter → proposer (1 chiamata, GBNF) → validator → esecuzione recovery mirata sugli errori · terminator onesto sui vicoli ciechi — cap. 5 runtime/engine/* 4 · Guardie policy (tre livelli di autonomia) · vaglio = guardia + giudice + consenso · sandbox bubblewrap per ogni invoke policy · vaglio · sandbox 5 · Executor 79 firmati nel repo + sintetizzati al volo + importati dietro gate — tutti vettoriali, tutti col loro manifest executors/ · ~/.local/…/executors/ 6 · Backend & skill il fornitore concreto (file locali, IMAP, Google Workspace, GitHub, web…) scelto dalla configurazione, mai dall'LLM backends/ · skills 7 · Tessuti persistenti mnestoma · archivi fast-path/autopath · cronologia + blob di undo · audit append-only (tutto SQLite + filesystem) ~/.local/share/metnos/ una richiesta li attraversa in ordine privilegi e fiducia calano scendendo
Figura 4 — I sette strati reali, con i moduli che li implementano. Il motore cognitivo (strato 3) è il cuore del capitolo 5; le guardie (strato 4) stanno sempre fra il piano e l'effetto.

5. Anatomia di un turno multitool

Questo è il capitolo da leggere se ne leggete uno solo. Seguiamo una richiesta vera — «cerca le mail spam e mettile nel cestino» — dall'ingresso alla risposta: quattro strumenti concatenati, una sola chiamata al modello, ogni passaggio misurato e annotato.

5.1 La cascata, passo per passo

La regola di fondo: il modello è l'ultima risorsa, non la prima. Prima si tenta la memoria (zero LLM, millisecondi); se la richiesta è nuova, il modello viene interrogato una volta sola e gli si chiede l'intero piano; l'esecuzione che segue è pura meccanica deterministica.

Un turno, dall'ingresso alla risposta «cerca le mail spam e mettile nel cestino» scorciatoie letterali tabella chiusa: «che ora è», «dove sono», «annulla»… microsecondi ✗ nessun match → si prosegue intent_extractor — LLM tier fast, ragionamento spento verb = move object = messages kw = spam… ~0,4 s richieste composte → lista ordinata di clausole motore Mētis — un solo punto d'ingresso, ogni strato annota se ha risposto Fastpath ★ — scorciatoie approvate dall'utente impronta esatta <5 ms · somiglianza semantica <150 ms 0 LLM ✗ miss Autopath — piani appresi dai turni riusciti cerca per significato della richiesta, poi per intent esatto 0 LLM ✗ miss: richiesta nuova prefilter → il pool della clausola find_messages classify_entries filter_entries move_messages rango: verbo+oggetto » qualifier » affinity (cap +3) 0 LLM deterministico: stessa query → stesso pool, stesso ordine Proposer Mētis — tier wise, UNA chiamata propone l'intero piano: steps + collegamenti + messaggio finale N candidati adattivi, ognuno vincolato dalla grammatica GBNF verb-filter sul pool · early-stop se il primo convince · rango teleologico 1× LLM il modello sceglie DENTRO il binario: niente prosa, niente args inventati (cap. 8) Validator — controllo deterministico del piano i tool esistono? gli args sono ben formati? i riferimenti puntano a step reali? 0 LLM errore banale → 1 riproposta, mai eseguire Esecuzione deterministica — passo per passo, niente dadi 1 find_messages → 42 entries 2 classify spam / non spam 3 filter → 12 entries 4 move_messages ⚙ vaglio: consenso → ok_count=12 per ogni step: risolvi from_step e segnaposti → vaglio → invoke in sandbox → observation cap di sicurezza: max 12 step per turno · stesso executor max 3 volte di fila render del messaggio finale "Spostate ${step4.ok_count} mail nel cestino." → valori reali Autopath registra il piano riuscito la prossima volta: stessa risposta, 0 LLM (cap. 9) uno step fallisce? Recovery mirata classifica: tool sbagliato · args · input mancante ripropone escludendo il tool fallito, riesegue Terminator — vicolo cieco onesto «Non posso risolvere: X. Per procedere: Y.» registra la lacuna — mai una risposta inventata «Spostate 12 mail nel cestino.» il log annota quale strato ha risposto e i ms di ogni fase telemetria per sotto-fase: intent_ms · prefilter_ms · vaglio_ms · exec_ms — ogni turno è misurabile e confrontabile
Figura 5 — L'anatomia di un turno multitool. Le scorciatoie (0 LLM) si tentano prima; se la richiesta è nuova, il Proposer chiede al modello l'intero piano in una sola chiamata vincolata; l'esecuzione è deterministica, con il vaglio davanti all'unico passo che modifica stato. A destra, i due percorsi d'errore: recovery mirata e vicolo cieco onesto.
  1. Scorciatoie letterali. Una tabella chiusa riconosce le frasi notissime («che ora è») in microsecondi. Qui: nessun match.
  2. Intent. Una chiamata al tier fast (ragionamento spento, ~0,4 s) estrae verbo canonico, oggetto e parole chiave. Le richieste composte diventano una lista ordinata di clausole, ognuna col suo pool.
  3. Memoria dei piani. Fastpath (scorciatoie che hai approvato col bottone ★) e Autopath (piani imparati da soli) rispondono senza modello se riconoscono la richiesta. Qui: miss, è la prima volta.
  4. Prefilter. Il catalogo si riduce al pool pertinente per la clausola: match su verbo+oggetto, bonus per qualifier, e — per rompere i pareggi fra fratelli — il bonus di affinity curata (cap +3). Tutto deterministico: stessa query, stesso pool, stesso ordine.
  5. Proposer Mētis. UNA chiamata al tier wise produce l'intero piano: steps, collegamenti, messaggio finale. Genera fino a N candidati (adattivo, con early-stop), ognuno fisicamente vincolato dalla grammatica GBNF del pool; un rango teleologico sceglie il migliore.
  6. Validator. Typecheck del piano prima di eseguire: tool esistenti, args ben formati, riferimenti reali. Un errore banale costa una riproposta, non un'esecuzione sbagliata.
  7. Esecuzione. Meccanica pura: per ogni step il runtime risolve i segnaposti, passa dal vaglio, invoca in sandbox, accumula l'osservazione. Cap: 12 step per turno, stesso executor max 3 volte di fila.
  8. Chiusura. Il messaggio finale è un template riempito dai risultati veri. Se il turno riesce, Autopath lo registra: la prossima volta si salta direttamente al punto 3.

5.2 Il piano: cosa propone davvero il modello

Il Proposer non produce prosa: produce un oggetto strutturato — steps, slot da riempire (fillers), messaggio finale. Questo è il piano reale della nostra richiesta:

{
  "steps": [
    {"tool": "find_messages",
     "args": {"folder": "INBOX", "query": "is:unread"}},
    {"tool": "classify_entries",
     "args": {"from_step": 1, "dimension": "spam"}},
    {"tool": "filter_entries",
     "args": {"from_step": 2, "where_field": "spam", "where_value": "spam"}},
    {"tool": "move_messages",
     "args": {"from_step": 3, "dst_folder": "${FILLER:cestino_folder}"}}
  ],
  "fillers": {
    "cestino_folder": {
      "prompt": "Come si chiama la cartella cestino per questo account?",
      "default": "Trash",
      "tier": "fast"
    }
  },
  "final_message": "Spostate ${step4.ok_count} mail nel cestino."
}

Da notare: il modello non conosce il nome della cartella cestino dell'account — e non lo inventa. Dichiara uno slot (${FILLER:cestino_folder}) che il runtime riempirà al momento giusto con una micro-chiamata economica (con cache) o col default.

5.3 Il data piping: come i passi si parlano

SegnapostoCosa fa
from_step: NPrendi le entries prodotte dallo step N (numerazione da 1) e passale intere a questo step. Le liste viaggiano solo così: mai re-incollate nel prompt.
${stepN.field}Estrai un campo scalare dal risultato dello step N (percorsi annidati supportati). Usato soprattutto nel messaggio finale.
${FILLER:nome}Slot riempito al volo da una micro-chiamata al tier fast (con cache) o dal default dichiarato.
${RUNTIME:chiave}Contesto del turno, risolto dal runtime: actor (chi parla), lang, channel.
Il data piping: liste fra gli step, scalari nei segnaposti step 1 · find_messages folder="INBOX" query="is:unread" → entries (42 mail) step 2 · classify_entries from_step: 1 dimension="spam" → entries + campo spam step 3 · filter_entries from_step: 2 where spam == "spam" → entries (12 mail) step 4 · move_messages from_step: 3 dst=${FILLER:cestino_folder} → results, ok_count=12 entries entries entries ${FILLER:cestino_folder} slot dichiarato dal piano, riempito dal runtime: micro-chiamata tier fast (con cache) oppure default → «Trash» ${RUNTIME:actor · lang · channel} contesto del turno, iniettato dal runtime: chi sta parlando, in che lingua, da quale canale final_message — il template della risposta "Spostate ${step4.ok_count} mail nel cestino." riempito a esecuzione finita con i valori reali → «Spostate 12 mail nel cestino.» ${step4.ok_count} scalare, non lista legenda dei collegamenti from_step — liste intere fra step ${stepN.field} — un campo scalare ${FILLER:nome} — slot riempito al volo ${RUNTIME:chiave} — contesto del turno
Figura 6 — Il piano della Figura 5 visto come flusso di dati. Le liste scorrono fra gli step via from_step; gli scalari, gli slot e il contesto passano per segnaposti tipizzati che l'esecutore risolve in modo deterministico.
Quando un cap si fa sentire, lo vedi. Se un limite tronca un risultato (entries, byte, step), l'executor lo dichiara nei campi (truncated: true, used, available_total) e il runtime lo dice nella risposta — con l'offerta di allargare solo se tecnicamente possibile, e mai allargando da solo. Un parziale presentato come completo è considerato un bug, non un'ottimizzazione.

6. Executor: vettoriali per costruzione

Ogni executor accetta una lista e ritorna una lista — anche quando la lista ha zero o un elemento. Non esiste nessun *_batch: la versione batch è l'executor. È la decisione che rende i piani corti e i risultati componibili.

Un solo contratto per N = 0, 1, mille paths = [] paths = ["/tmp/x.txt"] paths = [… ×1000] lista degenere o enorme: stesso ingresso, nessun caso speciale move_files iterazione, paginazione e finestre temporali vivono DENTRO; il branching torna al planner cap espliciti: max_total, max_results, max_bytes sempre una lista, più la verità results = […] ok_count = 12 (reali, non sperati) truncated = true used = 200, available_total = 312 cap_field = "max_total" move_files_batch  non esiste — e non esisterà: la forma vettoriale è l'unica forma.
Figura 7 — Il contratto vettoriale. Zero, uno o mille elementi attraversano lo stesso codice; i cap sono argomenti espliciti e il troncamento è dichiarato nei campi, mai nascosto.

Dal contratto discendono tre convenzioni che vedrete ovunque:

Il manifest: il prompt del tool

Ogni executor porta con sé un manifest TOML. Non è documentazione di cortesia: è ciò che il pianificatore legge quando decide se e come usare lo strumento — scritto su misura per un LLM medio locale, non per un modello frontier. Frasi corte, esempi letterali, default in chiaro; la descrizione segue quattro capitoli prescrittivi:

[description]
it = "SCOPO: cerca file per pattern in directory.
      PATTERN: find_files(base_path=\"/\", patterns=[\"*.jpg\"]).
      NON: list_dirs+filter_entries; get_files (lookup ID).
      OUT: entries=[{path,name,type,mime,kind,size,mtime}]."
Il manifest alimenta quattro meccanismi diversi executors/find_files/manifest.toml name = "find_files" affinity = ["trova","cerca","search", "file","glob","pattern",…] [description] SCOPO: … PATTERN: find_files(…) NON: … OUT: entries=[{…}] per lingua (IT+EN), con tracking dello stato [args] — JSON Schema base_path (req) · patterns · recursive max_total … tipi, default, esempi reverse_pattern + capabilities es. "swap_src_dst" · fs_read · net [code] digest sha256 + firma files = ["find_files.py"] prefilter (cap. 5) l'affinity curata rompe i pareggi fra fratelli pool del Proposer (cap. 5) il modello copia la FORMA dal PATTERN, non inventa grammatica GBNF (cap. 8) lo schema args diventa il binario del decode undo (cap. 12) il pattern inverso viene da un catalogo chiuso il digest firma il codice: se il file cambia senza ri-firma, il loader scarta l'executor — niente codice alla deriva
Figura 8 — Un solo manifest, quattro consumatori: prefilter, pool del pianificatore, grammatica e undo leggono campi diversi dello stesso TOML. Il digest lega il manifest al codice firmato.

7. Synt: la fabbrica degli strumenti

Quando il pool non sa fare una cosa, il pianificatore non improvvisa codice nel mezzo del turno: passa la mano a synt, il processo che fa esistere ciò che manca. Prima prova a comporre executor esistenti; solo come eccezione documentata genera un executor nuovo — in cinque stadi, ognuno col suo contratto.

La catena di montaggio: cinque stadi + verifica ogni stadio vede solo la fetta minima di contesto; il vocabolario chiuso entra SOLO allo stadio 1 1 · NAMING nome conforme al vocabolario chiuso + revertible, critical tier middle 2 · SIGNATURE schema degli args, capabilities richieste, pattern di reversibilità tier middle 3 · TESTS 4-6 test di nascita: caso felice, lista vuota, args invalidi, edge tier middle 4 · DESCRIPTION descrizione a capitoli (SCOPO/PATTERN/NON/OUT) + parole di affinity tier middle 5 · CODE il file Python con def invoke() (+ reverse se serve) tier wise stadio 6 · verifica semantica (fail-safe) un LLM separato confronta descrizione e codice: dicono la stessa cosa? nel dubbio rifiuta: meglio perdere un buon synth che ammetterne uno fasullo firma Ed25519 + digest manifest e codice legati insieme test di nascita in sandbox i 4-6 test dello stadio 3, eseguiti davvero nel pool, accanto ai fratelli stesso contratto vettoriale, stesso manifest, stessa sandbox degli executor scritti a mano La sintesi è locale: nessun provider esterno scrive codice che girerà sulla tua macchina. E un bug in un executor sintetizzato si corregge iterando il prompt dello stadio, mai riscrivendo a mano il file generato.
Figura 9 — La pipeline di sintesi: quattro stadi procedurali sul tier medio, il codice sul tier alto, poi verifica semantica indipendente, firma e test di nascita. Il multistadio convalida dove il prompt singolo falliva.

Due inneschi, una cascata

ModoInnescoTempo
ReattivoDurante un turno: il pianificatore non trova nessun executor che soddisfi la richiesta.Sincrono — l'utente sta aspettando; prima si tenta la composizione di executor esistenti.
IntrovertivoDi notte: l'ager scorre il mnestoma e trova ricorrenze, tracce sovrapposte, famiglie con la stessa forma.Asincrono, in omeostasi: propone fusioni, generalizzazioni, specializzazioni.

In entrambi i casi vale la stessa regola: synt propone, l'umano approva. Nessuna auto-modifica senza filtro; ogni proposta arriva con motivazione, ed è reversibile.

Il gate a 7 livelli

Lo stesso imbuto vale per il codice sintetizzato e per le skill importate da fuori: nessun pacchetto si esegue sulla fiducia.

Il gate d'ammissione: sette livelli, nessuna eccezione pacchetto / synth nuovo non fidato 1 firma Ed25519+digest 2 vocabolario nome + affinity 3 aging quarantena d'uso 4 sandbox profilo dal manifest 5 smoke test esecuzione provata 6 verifier LLM descrizione vs codice 7 audit append-only executor fidato nel pool «non fidarti del pacchetto — il pacchetto deve guadagnarsi il posto» i formati di skill drop-in eseguono codice di terzi con i privilegi dell'assistente: per un agente che tocca file, mail e shell è esecuzione remota di codice per design. Metnos sceglie la sicurezza per costruzione. roadmap: mappare l'ecosistema skill pubblico DENTRO questo modello, non eseguirlo crudo
Figura 10 — Il gate a 7 livelli, identico per executor sintetizzati e importati: firma, vocabolario, quarantena d'uso, sandbox, smoke test, verifica semantica, audit. Solo in fondo all'imbuto un pacchetto diventa un executor fidato.

8. Quattro tier, un routing deterministico

I tier sono ruoli astratti, non modelli inchiodati: fast / middle / wise sono incarichi che leghi a qualunque endpoint tu abbia, frontier è l'unico opt-in cloud. Nell'istanza di riferimento i tre tier locali puntano tutti alla stessa istanza di llama-server: a cambiare sono solo i parametri per chiamata.

TierRuoloNell'istanza di riferimento
fastEstrazioni brevi e strutturate: intent, filler, classificazioni. Ragionamento spento.llama-server :8080 — MoE ~35B quantizzato, think=False, risposta corta. Obbligatorio (rete di salvataggio).
middleLavoro procedurale: stadi 1-4 della sintesi, descrizioni, giudizi.Stessa istanza, parametri di default.
wiseIl pianificatore: propone il piano intero; scrive il codice dello stadio 5.Stessa istanza. Obbligatorio: non degrada mai a fast.
frontierUn consulto esterno quando richiesto esplicitamente (es. analisi di un issue).API cloud, opt-in, con fallback gestito se la chiave non c'è.
Tier ≠ modello. Nessuna GPU o NPU è richiesta per costruzione: un endpoint su CPU, un modello che già servi, o il fallback frontier sono percorsi di prima classe. Un modello locale più debole significa pianificazione più debole, non un'installazione rotta.

Le tre serrature del determinismo

Un LLM a temperatura zero non basta a rendere il routing riproducibile: il server locale resta non-deterministico per via della decodifica speculativa col seed casuale. Metnos chiude la porta con tre serrature, una per ogni fonte di rumore:

Tier astratti a sinistra, determinismo a destra fast intent · filler · classify middle synt 1-4 · descrizioni wise piani · codice synth llama-server :8080 UNA istanza locale cambiano solo i parametri: think · num_predict frontier consulto cloud, opt-in solo se richiesto, mai il motore Serratura 1 — seed fissato a temperatura 0 il server resta non-deterministico (decodifica speculativa a seed casuale): il seed va inchiodato per env. METNOS_LLM_SEED=42 (default; -1 = casuale esplicito) Serratura 2 — pareggi rotti da dato curato fra fratelli con stesso oggetto decide l'affinity distintiva del manifest (verbi generici esclusi), mai un lancio di moneta. prefilter: bonus = min(|query ∩ affinity|, 3) Serratura 3 — grammatica come binario dal pool dello step si genera una GBNF (unione discriminata): il modello non PUÒ emettere un tool_call malformato, né mischiare il nome di un tool con gli args di un altro. stessa richiesta → stesso pool → stesso piano, a ogni esecuzione il routing si mette sotto bench e test di regressione come software ordinario soft constraint = «per favore guida a destra» · grammar = il guard-rail il primo si può ignorare, il secondo no: ogni token candidato viene filtrato contro la grammatica prima della scelta + verb-filter: il pool si restringe ai verbi compatibili con l'intent della clausola
Figura 11 — A sinistra i tier come ruoli legati a un'unica istanza locale (frontier a parte); a destra le tre serrature che rendono il routing riproducibile: seed fissato, affinity curata per i pareggi, grammatica GBNF sul decode.
Niente parser fragili. Il tool-use è nativo: il modello emette tool_calls strutturati, e la grammatica garantisce la forma a monte. Non c'è nessun parsing di JSON pescato dentro prosa — il punto debole classico degli agenti fai-da-te.

9. La memoria che accelera

Metnos non addestra modelli: niente fine-tuning, niente RLHF. Tutto ciò che impara è dato ispezionabile — piani, tracce, scorciatoie — e ogni cosa imparata si può leggere, correggere, cancellare. L'effetto pratico: più lo usi, meno chiama il modello.

Il circolo: usare → ricordare → non chiedere più turno riuscito il piano ha funzionato davvero Autopath registra piano indicizzato per significato della richiesta (embedding) richiesta simile, domani piano già pronto: riesecuzione in millisecondi, 0 LLM ★ promozione esplicita un bottone sotto la risposta promuove il piano a scorciatoia Fastpath garantita mnestoma — il grafo dei mnest (SQLite) due executor attivati insieme → un filo che si rinforza con l'uso e decade se non riusato; le lacune restano come aspirazioni l'orologio è il tempo dell'uso, non il calendario: un sistema che dorme non invecchia di notte: l'ager + le proposte di synt le sequenze multi-step molto usate (>50 volte) diventano candidate a executor sintetici; tracce sovrapposte propongono fusioni e generalizzazioni — sempre col filtro umano proposte loggate, mai auto-applicate (cap. 7) ogni turno lascia tracce imparare = accumulare dati verificabili, mai ritoccare pesi
Figura 12 — Il circolo dell'apprendimento senza addestramento: i piani riusciti diventano scorciatoie (Autopath, Fastpath ★), le co-attivazioni diventano mnest, le ricorrenze notturne diventano proposte di sintesi. Tutto è dato leggibile e reversibile.

10. I sensi: la pipeline immagini

Per cercare nelle foto, Metnos non spedisce nulla a nessuno: tre estrattori in-process trasformano ogni immagine in tre segnali — cosa si vede, chi c'è, dove e quando — fusi in un indice unificato interrogabile dal vocabolario normale.

Tre segnali da ogni foto, un indice solo una foto dell'archivio semantica — SigLIP l'immagine diventa un vettore: «tramonto al mare», «torta di compleanno», «sentiero in montagna» volti — RetinaFace + ArcFace trova i volti, li trasforma in impronte d'identità; le persone si registrano con nome solo se lo chiedi tu contesto — EXIF coordinate GPS, data e ora, fotocamera: il dove e il quando senza nessun modello indice unificato un record per foto: scena + persone + luogo + tempo costruito una volta, interrogato sempre «le foto in montagna dell'estate scorsa» find_images_indices stesso vocabolario di tutto il resto tutto in-process, sulla tua macchina: l'archivio fotografico non lascia mai casa
Figura 13 — La pipeline immagini: SigLIP per la scena, RetinaFace+ArcFace per le identità, EXIF per luogo e tempo. I tre segnali confluiscono in un indice unificato che si interroga con un executor normale del vocabolario.

La ricerca arriva dal canale come qualunque altra richiesta: il pianificatore compone find_images_indices con i criteri estratti dalla frase, e il canale mostra le anteprime inline. La costruzione dell'indice è un lavoro di fondo, incrementale e riavviabile, che si lancia con una frase («indicizza le foto in…»).

11. I canali: Telegram e web

Un canale è un adattatore: converte un'interfaccia esterna in messaggi e risposte, più una capacità opzionale — rendere bottoni per conferme e scelte. Due canali nascono con l'installazione; aggiungerne altri non tocca il nucleo.

Due porte d'ingresso, zero porte aperte verso Internet la macchina di Metnos server web — porta 8770 chat (streaming SSE) + dashboard admin daemon Telegram long-poll IN USCITA verso l'API del bot browser in LAN (o via overlay VPN tuo) chiave admin al primo accesso proposte · executor · run safety · turni · grafici HTTP :8770 API Telegram il daemon CHIEDE lui: niente porte aperte, niente IP pubblico telefono ovunque c'è rete, parli col tuo bot bottoni inline chi può parlare? solo chi è accoppiato: codici firmati Ed25519 con scadenza, livello di autorizzazione per persona un mittente sconosciuto viene scartato senza eco; le conferme del vaglio e le scelte (get_inputs) arrivano come bottoni sul canale
Figura 14 — I due canali. Il browser parla direttamente col server sulla 8770 (chat con streaming + dashboard); Telegram funziona per long-poll in uscita, quindi nessuna porta aperta né IP pubblico. In basso, il pairing che decide chi può parlare.
CanaleCosa offre
Web :8770Chat nel browser con risposta in streaming (SSE), anteprime immagini, badge di feedback; dashboard admin per proposte, executor, run, safety e turni. La stessa API risponde JSON o HTML a seconda dell'Accept. Chiave admin auto-creata al primo avvio, file con permessi 0600.
TelegramIl tuo bot personale: messaggi, foto, bottoni inline per le conferme del vaglio e per le scelte a opzioni. Accoppiamento col comando /pair e un codice firmato con scadenza.

12. Sicurezza e reversibilità

La sicurezza non è un modulo: è una catena di guardie indipendenti, e un'azione deve passarle tutte. E siccome anche la guardia migliore sbaglia, l'ultima difesa è poter tornare indietro: undo onesto, per costruzione.

La catena delle guardie — e l'undo come ultima difesa pairing chi sei? codice firmato, ruolo per persona sconosciuto = scartato policy tre livelli di autonomia: ReadOnly · Supervised · Full capability per categoria vaglio guardia: vietati e irrecuperabili; giudice + consenso coi bottoni sempre PRIMA di eseguire sandbox bubblewrap con profilo dal manifest: rete, utente, IPC isolati mai subprocess nudi firma + audit codice legato al manifest via digest; ogni azione in un registro append-only deriva = scarto silenzioso l'ultima difesa: undo di prima classe ● catalogo chiuso di pattern inversi (5): scambia src/dst · elimina i creati · ripristina dal blob · cancella per id ● ogni move è COPY → verifica → DELETE: mai una cancellazione senza copia confermata ● i contenuti sovrascritti finiscono in blob con hash sha256 nella cronologia del turno: «annulla» li rimette al loro posto ok_count onesto anche nell'undo: se dice che ha annullato 3 cose, ha annullato 3 cose le skill restano dormienti finché manca il prerequisito; disattivarne una toglie di mezzo l'intera superficie la skill di sistema (shell, sudo, pacchetti, mount) esiste — ed è per questo che ogni azione privilegiata richiede consenso esplicito, e l'intera skill si può spegnere con una frase
Figura 15 — Cinque guardie in serie (pairing, policy, vaglio, sandbox, firma+audit) e, sotto, la rete di protezione: un undo con catalogo chiuso di pattern inversi, copie verificate prima di ogni cancellazione e conteggi onesti.
Il potere c'è, ed è per questo che è imbrigliato. Metnos può davvero amministrare la macchina (shell, sudo, pacchetti, mount) — è ciò che lo rende un assistente di sistema e non un chatbot. Ma ogni azione privilegiata passa dal vaglio con conferma esplicita, gira in sandbox, finisce nell'audit; e l'intera skill di sistema si può disattivare, chiudendo Metnos fuori dal sistema operativo.

13. I principi, in otto carte

Se di questo documento doveste ricordare solo otto frasi, sono queste. Tutto il resto — codice, prompt, convenzioni — discende da qui.

1Vettoriale per costruzione. Ogni executor accetta una lista e ritorna una lista, anche degenere. La versione batch è l'executor: *_batch non esiste.
2Vocabolario chiuso, governato. Tutto ciò che agisce ha un nome componibile dentro una grammatica chiusa. Un termine nuovo entra solo se necessario, generale e comprensibile.
3Nessun fallimento silenzioso. I conteggi riflettono ciò che è successo davvero; il troncamento si dichiara, non si nasconde; un parziale presentato come completo è un bug.
4Deterministico > LLM. Dove un automa o una tabella bastano, il modello non si usa. L'LLM entra dove un parser equipotente sarebbe davvero troppo complesso — e ci entra vincolato.
5Mai una cancellazione implicita. Ogni spostamento è copia → verifica → cancellazione; mai DELETE senza COPY confermata.
6Reversibilità con motivazione. Ogni atto evolutivo (sintesi, fusione, archiviazione) è reversibile e motivato. Dire sì costa meno quando si può tornare indietro.
7i18n per costruzione. Ogni stringa e prompt rivolto all'utente è dato per-lingua: una lingua nuova è un pacchetto di traduzione, non un fork del codice.
8Comprensibilità come dovere. Se l'utente non capisce il sistema, il sistema non serve. La semplicità non è estetica: è il criterio che ha selezionato tutto il resto.

14. Cosa NON è Metnos

Metà del design sta nei no. Ogni tentazione di aggiungere un elemento di questa lista va respinta.

15. Dove andare dopo

Questo era il Livello 1: il sistema dall'alto. Il Livello 2 — la microprogettazione — ha una pagina per componente, con il dettaglio sufficiente a scriverne il codice senza inventare nulla.

microprogettazione
Indice dei componenti
Ventuno componenti canonici, una pagina ciascuno, bilingui IT+EN: il livello dove le scelte diventano contratti.
tour · 10 min
Quick Tour
Il giro veloce con gli screenshot: cosa si prova a usarlo, prima di studiarlo.
riferimento
Glossario
Ogni termine del progetto, definito una volta e linkato ovunque.
dialogo · 40 min
Dialogo sui fini e sui limiti
Le origini galileiane: teleologia, le 4 Leggi, il vaglio. Perché un agente proattivo ha bisogno di un freno.
dialogo · 45 min
Dialogo sugli executor
La fondazione tecnica: executor, mnest, mnestoma, tracce, ager, i sei principi originari.
codice
Il repository
AGPL-3.0, pre-1.0: il subset pubblico dell'istanza in esercizio, installer compreso.

Metnos — Architettura: Introduzione (v2).
mētis + noûs: l'intelligenza astuta al servizio della mente — su hardware tuo.
Documentazione bilingue IT+EN su metnos.com; codice su github.com/brunialti/metnos.