skill ↔ backend — due assi ortogonali
In Metnos «skill» e «backend» rispondono a due domande
diverse. Il backend dice COME si esegue un
verbo_oggetto contro un servizio. La skill dice
SE e QUALI capacità sono sbloccate, fidate e spedite.
Confonderli porta a sdoppiare gli executor; tenerli separati è quel che
permette di aggiungere un provider senza toccare il pianificatore.
| Backend / provider | Skill | |
|---|---|---|
| Risponde a | COME eseguo verbo_oggetto contro un servizio | SE / QUALI capacità sono sbloccate, fidate, spedite |
| Asse | oggetto × provider | dipendenza esterna (credenziale / backend / hardware) |
| Visibilità | invisibile all'LLM, risolto da configurazione dal resolver dei backend | visibile all'utente (abilita / disabilita, dormienza, recinto, impacchettamento) |
I due assi si toccano solo quando una skill ha un solo
provider: in quel caso github, geo, mail
sono di fatto il nome rivolto all'utente del backend di quel provider.
Divergono appena la skill ha più backend (il calendario
si serve su ICS locale, Google o CalDAV) o non ha
alcun provider esterno (le foto, il nucleo). La mappa è
molti-a-molti: un solo provider (Google Workspace) serve più
skill — posta, calendario, drive, fogli, documenti.
find_issues.
«Skill» ha finito per indicare tre cose diverse: una
classificazione di executor già nel repository, dei pacchetti veri in
repository, e codice di terzi importato. Il campo tier le unifica
sotto un modello solo. Vive in skills_catalog.py (funzione
skill_tier()) e nell'intestazione di SKILL.md.
| Tier | Cos'è | Fiducia | Dove vive | Attivazione |
|---|---|---|---|---|
| 1 — core | planner ed engine, file locali, cartelle, processi, tempo, scheduler locale, persone, credenziali, firme, proposte, gli helper dello scratchpad (filtra / ordina / raggruppa / calcola / descrivi / estrai) | massima | repository, firmato, multilingua | sempre attiva |
| 2 — first_party | capacità spedite con Metnos allo stesso standard del nucleo, ma dormienti finché manca la dipendenza: github, foto, posta, web, geo, calendario, archivio dati generico (sqldatabase), frontier, Google Workspace | massima | repository (pacchetto versionato + executor firmati) | automatica, dormiente se non configurata |
| 3 — imported | codice di terzi non auditato né vendorizzato (da agentskills.io e simili) | bassa | dati utente, con provenienza tracciata | facoltativa, recinto + rete a 7 strati |
Domani potrebbe arrivare GitLab accanto a GitHub. La domanda è: come si aggiunge un secondo provider per le stesse issue? Due strade.
Generare find_issues_github e find_issues_gitlab
e lasciare che il pianificatore scelga. Funziona dove al centro c'è un
modello frontier che disambigua leggendo la prosa. In Metnos il pianificatore
è un modello locale, che davanti a due nomi quasi
identici sviluppa un pregiudizio sul provider:
sceglie sempre lo stesso, o sbaglia. Lo
sdoppiamento rompe il routing.
find_issues, read_issues, find_pulls.
L'oggetto (issues, pulls) è l'astrazione
stabile.runtime/backends/{issues,pulls}/{github,gitlab}.py.github (PAT) e
skill gitlab (token), con dormienza indipendente — perché
la credenziale è il confine dove serve granularità («abilita
gitlab» senza toccare github)._github / _gitlab
resta per il pin esplicito dell'utente («apri la issue
su gitlab»); il default è agnostico.+1 file backend,
+1 skill (se introduce una credenziale nuova),
0 nuovi executor. È il percorso che calendario e file
hanno già preso.
provider:access dichiara il binding della skill e può essere limitata
con when al valore finale del selettore client. Solo il binding
effettivo governa insieme rete, credenziali e pin al server; nome dell'executor e
valore dell'argomento non sono fonti di permesso.
sqldatabase.
La forma astratta non è una promessa per il futuro: la skill
sqldatabase la incarna oggi. Offre tre executor canonici
— find_entries, write_entries,
delete_entries — che leggono, scrivono ed eliminano record
in archivi nominati (find_entries(store="spese", …)),
senza che la query sappia mai dove i dati vivono davvero. Sotto, due backend
intercambiabili sulla stessa base comune (SqlDatabaseBackend): uno
persistente su SQLite, uno effimero in memoria; un domani PostgreSQL si aggiunge
come sorella, senza toccare gli executor. Quale backend serva un dato archivio
si decide in un registro, alla dichiarazione dello store, mai
dalla richiesta dell’utente. La skill resta dormiente
finché nessuno store è registrato.
find_issues_github + find_issues_gitlab confondono il planner locale). A destra lo stato astratto: un solo find_issues, il resolver, due backend. La freccia è la promozione: refactoring con frontier una-tantum, poi vaglio umano. GitHub è attualmente nello stato «cotto».*_github (issue, PR, task, commenti e — da 25/6 —
file del repo: find/read/list) portano il provider nel nome. Funziona
finché il provider resta unico; appena ne arriva un secondo va astratto.
Regola generale: un provider che plausibilmente avrà fratelli
(github→gitlab/gitea, posta IMAP, calendario) va astratto da subito; uno che
resterà unico può restare cotto.
Nel modello a più provider la skill non accende e spegne l'executor: accende e spegne il backend. Questo cambia chi vede cosa.
find_issues è disponibile se
almeno uno dei suoi backend è abilitato e configurato;
diventa dormiente solo se sono spenti tutti (un AND su tutti i
backend).find_issues — cambia solo il routing. Disabilitare uno
dei due: l'altro continua a servire. Disabilitarli entrambi: l'executor diventa
dormiente.
Oggi il filtro è per pattern sul nome dell'executor
(skills_catalog): funziona solo finché il provider è
unico. Il pezzo nuovo da costruire è una mappa
skill→backend più la regola «executor dormiente = AND su
tutti i suoi backend spenti». È il primo mattone: serve appena
esiste il primo executor a più backend.
Fondere una skill mono-provider cotta (*_github) in
find_issues + backend è un'operazione
straordinaria. È ammesso un LLM frontier
una-tantum SOLO per il refactoring; rilevamento e
applicazione restano deterministici e con vaglio umano — firmare
in automatico del codice generato da un frontier romperebbe la fiducia.
| Fase | Chi | Cosa |
|---|---|---|
| QUANDO (trigger) | deterministico | all'arrivo del 2° provider — tipicamente l'import di una skill che mappa su un oggetto già coperto solo da executor provider-suffissati (*_github, riconosciuti dall'autorità di naming). Sovrapposizione di oggetto + provider diverso → «candidato a promozione». Nessun LLM per accorgersene. |
| DOVE (seam) | infrastruttura riusata | rilevamento nello strato di ammissione dell'importer; refactoring tramite l'escalation a un modello frontier in modo agentico; atterraggio nella pagina admin delle modifiche come modifica di tipo promote_provider, niente applicazione automatica; applicazione che scrive i file, ri-firma (§7.10), registra skill↔backend e filtro per-backend (§4). |
| COME (pipeline) | frontier solo in mezzo | rileva (det.) → il frontier genera {executor canonico + backends/<obj>/{p1,p2}.py + mappa skill→backend} → la modifica viene proposta → vaglio umano → applica + firma + verifica con i 7 strati di ammissione + smoke. |
MCP e il contratto executor risolvono problemi diversi. MCP permette a un client di scoprire e invocare strumenti esposti da un server, negoziando versione e capacità. Metnos deve invece stabilire che cosa significa una capacità per il pianificatore, quale autorità possiede e come si verifica il risultato.
Il contratto citato qui non è una convenzione implicita: è definito dal Metnos Executor Standard versionato. Un backend MCP deve rispettarlo come un backend locale o remoto.
| Aspetto | MCP fornisce | Metnos deve conservare |
|---|---|---|
| identità | nome del tool entro un server | nome canonico verbo_oggetto, indipendente dal fornitore |
| contratto | schema JSON degli argomenti; schema del risultato facoltativo | forma vettoriale, semantica degli errori e postcondizione osservabile |
| autorità | connessione e autorizzazione verso il server | capacità, sandbox, mandato credenziale e consenso per l'azione |
| ciclo di vita | negoziazione, chiamata, annullamento e chiusura | limiti, audit, idempotenza, procedura inversa e recupero |
| catalogo | può segnalare tool aggiunti o modificati | ammissione esplicita e sospensione quando cambia lo schema |
mcp_executor(server, tool, args) introdurrebbe un secondo
linguaggio e aggirerebbe i controlli per singola azione, quindi non appartiene
al contratto pubblico.
Un tool esterno potrà diventare il backend di un executor esistente, un executor proxy ristretto oppure restare in quarantena. La trasformazione in executor nativo sarà una promozione verificata e sottoposta a vaglio, non una riscrittura automatica di codice remoto.
| Per capire… | Leggi |
|---|---|
| come si importa una skill di terzi e la si trasforma in executor firmati | skill importer |
| il recinto a strati in cui gli executor importati eseguono | sandbox |
| i controlli prima di ogni azione rischiosa | vaglio |
| cos'è un executor e com'è fatto | executor |
| l'altro asse di sostituibilità: come si sceglie e si cambia il modello (LLM, embedding, VLM) dietro le capacità, editando un TOML invece del codice | virtualizzazione dei modelli |
Metnos — skill ↔ backend, due assi ortogonali