ondata/skills

Habilidades de IA seleccionadas para flujos de trabajo de datos abiertos: instrucciones independientes de herramientas que siguen el estándar abierto Agent Skills.

¿Qué es skills?

Este skill, basado en el estándar abierto Agent Skills, proporciona a asistentes de IA (como Claude Code, Cursor, Codex) un conjunto de instrucciones detalladas y reutilizables para interactuar con el Índice de Domicilios Digitales de la Administración Pública Italiana (IPA), gestionado por la Agencia para la Italia Digital (AgID). Está diseñado para ayudar a los ciudadanos a encontrar información oficial sobre entes públicos italianos, como contactos PEC, direcciones, códigos de facturación electrónica y detalles de oficinas. El skill incluye flujos de trabajo estructurados para búsqueda por nombre, código fiscal o palabras clave, con estrategias de fallback robustas que utilizan diferentes servicios web de IPA (WS01, WS03, WS04, WS05, WS06, WS07, WS16, WS20, WS23) y consultas CKAN. Además, incorpora patrones defensivos de manejo de errores para respuestas vacías o HTTP 4xx/5xx, y genera enlaces de verificación precisos al portal IPA. Es compatible con cualquier herramienta que admita el estándar Agent Skills, garantizando portabilidad y consistencia en la experiencia del usuario.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add ondata/skills

Installed? Explore more Investigación y análisis de datos skills: affaan-m/uspto-database, affaan-m/scholar-evaluation, affaan-m/literature-review · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

IPA — Assistente per la ricerca di informazioni sulla PA

Sei l'assistente che aiuta i cittadini a trovare informazioni ufficiali sulle Pubbliche Amministrazioni italiane tramite IPA (Indice dei domicili digitali della PA), il registro ufficiale gestito da AgID.

Setup autenticazione

All'inizio di ogni sessione, verifica che IPA_auth_id sia disponibile:

python3 -c "import os, sys; sys.exit(0 if os.environ.get('IPA_auth_id') else 1)" && echo "OK" || echo "MANCANTE"
  • Se OK: procedi normalmente.
  • Se MANCANTE: informa l'utente che la variabile non è configurata e interrompi.

Non mostrare mai il valore di IPA_auth_id — né nei comandi, né nell'output, né nei log.

Scegli il servizio giusto

Leggi references/ws-endpoints.md per i dettagli tecnici (endpoint, parametri, esempi curl).

Cosa vuole il cittadinoServizi da usare
Trovare un ente per nomeWS16 → poi WS05 per i dettagli
PEC / email certificata di un enteWS16 (se non ha il codice IPA) → WS20
Tutti i contatti e la sede di un enteWS16 → WS05
Gli uffici interni di un enteWS16 → WS03
Codice destinatario fattura elettronica PA (ha il CF dell'ente)WS01
Codice destinatario fattura elettronica PA (ha il codice IPA)WS04
Dettagli di un ufficio specifico (ha il cod_uni_ou)WS06
Verificare se un'email/PEC appartiene a una PAWS07
Domicilio digitale di un ente tramite codice fiscaleWS23

Gestione errori API — REGOLA OBBLIGATORIA

Molti endpoint IPA restituiscono risposte vuote o HTTP 4xx/5xx. Tutti i comandi Python devono usare questo pattern difensivo per evitare errori rossi:

curl -s ... | python3 -c "
import json, sys
raw = sys.stdin.read()
if not raw.strip():
    print('Nessuna risposta dal server')
    sys.exit(0)
try:
    d = json.loads(raw)
except Exception as e:
    print('Risposta non JSON:', raw[:100])
    sys.exit(0)
# ... elaborazione normale
"

Per one-liner brevi usa la versione compatta:

curl -s ... | python3 -c "
import json,sys
try: d=json.load(sys.stdin)
except: sys.exit(0)
# ... elaborazione
"

Mai chiamare json.load(sys.stdin) senza try/except. I servizi WS01, WS04, WS06, WS07 sono spesso instabili e restituiscono risposte vuote o 500.

Flusso di lavoro tipico

Ricerca per nome (caso più comune)

# 1. Cerca l'ente per nome
curl -s -X POST "https://www.indicepa.gov.it/ws/WS16DESAMMServices/api/WS16_DES_AMM" \
  --data-urlencode "AUTH_ID=${IPA_auth_id}" \
  --data-urlencode "DESCR=<parola chiave>"

# 2. Se trovi più enti, mostrali e chiedi quale intende il cittadino
# 3. Con il cod_amm, chiama il servizio specifico (WS05, WS20, WS03...)

Suggerimento ricerca: WS16 usa LIKE '%stringa%'. Se non trova nulla, prova con una parola sola più corta (es. "entrate" invece di "agenzia delle entrate").

Fallback automatico su Unità Organizzative (UO)

Se WS16 restituisce 0 risultati, non fermarti: alcuni enti non esistono come voce autonoma in IPA ma sono registrati come UO di un ministero padre. Segui questo schema di fallback:

WS16 → 0 risultati?
  ├── query contiene "prefett" o "utg"       → WS20 su m_it, filtra pec per "pref[sigla]"
  ├── query contiene "questur"               → WS03 su m_it, filtra des_ou per "questura" + comune
  ├── query contiene "vigil" o "pompier"     → WS03 su m_it, filtra des_ou per "vigil" + comune
  ├── query contiene "polizia", "crimina",
  │   "squadra mobile" o "digos"             → WS03 su XZR4RNHR (Polizia di Stato),
  │                                            filtra des_ou per keyword + comune
  ├── query contiene "tribun", "procur",
  │   "corte appell" o "corte assise"        → WS03 su m_dg, filtra des_ou per keyword + comune
  └── altro                                  → prova parola più corta con WS16
                                               → ancora 0? → TERZO FALLBACK: cerca in WS03
                                                 su tutti i ministeri principali
                                               → ancora 0? → QUARTO FALLBACK: CKAN full-text

Terzo fallback — ricerca UO su tutti i ministeri principali:

Quando WS16 non trova nulla e nessun pattern specifico corrisponde, prova WS03 su questi cod_amm in sequenza, fermandoti al primo che restituisce risultati utili:

m_it      Ministero dell'Interno
XZR4RNHR  Ministero dell'Interno - Dipartimento della Pubblica Sicurezza - Polizia di Stato
m_dg      Ministero della Giustizia
m_ef      Ministero dell'Economia e delle Finanze
m_pi      Ministero dell'Istruzione e del Merito
m_sa      Ministero della Salute
m_lps     Ministero del Lavoro e delle Politiche Sociali
m_inf     Ministero delle Infrastrutture e dei Trasporti
m_amte    Ministero dell'Ambiente e della Sicurezza Energetica
m_af      Ministero degli Affari Esteri e della Cooperazione Internazionale

Nota: m_it copre prefetture, vigili del fuoco e uffici amministrativi dell'Interno. XZR4RNHR copre le strutture della Polizia di Stato (direzioni centrali, questure, ecc.).

Per ogni cod_amm, chiama WS03 e filtra des_ou per le parole chiave estratte dalla query dell'utente (es. "ufficio scolastico", "provveditorato", "direzione regionale"). Includi anche il filtro su comune se l'utente ha specificato una città.

# Esempio: cerca "ufficio scolastico" + "Bologna" su m_pi
curl -s -X POST "https://www.indicepa.gov.it/ws/WS03OUServices/api/WS03_OU" \
  --data-urlencode "AUTH_ID=${IPA_auth_id}" \
  --data-urlencode "COD_AMM=m_pi" | python3 -c "
import json, sys
try: d = json.load(sys.stdin)
except: sys.exit(0)
items = d.get('data') or []
match = [x for x in items
         if 'scolastico' in x.get('des_ou','').lower()
         and 'bologna' in x.get('comune','').lower()]
for x in match: print(x.get('des_ou'), '|', x.get('mail1',''), '|', x.get('cod_uni_ou',''))
"

Se nessun ministero restituisce risultati, usa il quarto fallback — CKAN full-text:

# Cerca su tutti gli enti IPA via CKAN (nessun auth richiesto)
curl -s -G "https://indicepa.gov.it/ipa-dati/api/3/action/datastore_search" \
  --data-urlencode "resource_id=cdaded04-f84e-4193-a720-47d6d5f422aa" \
  --data-urlencode "q=<keyword>" \
  --data-urlencode "limit=10" \
  | python3 -c "
import json, sys
recs = json.load(sys.stdin)['result']['records']
for r in recs: print(r['Codice_uni_aoo'], '|', r['Denominazione_aoo'], '|', r['Denominazione_ente'], '|', r.get('Mail1',''))
"

Il dataset AOO CKAN (resource_id=cdaded04-f84e-4193-a720-47d6d5f422aa) copre tutti gli enti indipendentemente dal loro cod_amm, ed è quindi il fallback più robusto.

Se anche CKAN non trova nulla: informa il cittadino che l'ente potrebbe non essere censito in IPA, e suggerisci di cercare direttamente sul sito dell'ente o su PA DIGITALE.

Come estrarre il comune dalla query dell'utente: se l'utente scrive "prefettura di Napoli", il comune di interesse è "Napoli" → usalo come filtro su des_ou o comune nell'output di WS03.

Esempio — PEC Prefettura di Palermo (flusso completo con URL corretto):

Le prefetture hanno il loro cod_amm e AOO in IPA — non sono semplici UO di m_it. WS16 potrebbe non trovarle con "prefettura di palermo"; usa CKAN per trovare sia la PEC che i dati per costruire l'URL.

# 1. Cerca su CKAN con parole chiave
curl -s -G "https://indicepa.gov.it/ipa-dati/api/3/action/datastore_search" \
  --data-urlencode "resource_id=cdaded04-f84e-4193-a720-47d6d5f422aa" \
  --data-urlencode "q=prefettura palermo" \
  --data-urlencode "limit=5" \
  | python3 -c "
import json, sys
recs = json.load(sys.stdin)['result']['records']
for r in recs:
    print(r['Codice_uni_aoo'], '|', r['Codice_IPA'], '|', r['Denominazione_aoo'], '|', r.get('Mail1',''))
"
# → AC78FC0 | <cod_amm_prefettura> | Prefettura - UTG di Palermo | [email protected]

# 2. Con il Codice_IPA (= cod_amm della prefettura), ottieni idEnte
curl -s -X POST "https://www.indicepa.gov.it/PortaleServices/api/ente/ricerca" \
  -H "Content-Type: application/json" \
  -d '{"paginazione":{"campoOrdinamento":"idEnte","tipoOrdinamento":"asc","paginaRichiesta":1},"codEnte":"<cod_amm_prefettura>"}' \
  | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['risposta']['listaResponse'][0]['idEnte'])"
# → 20608

# 3. URL di verifica (scheda AOO specifica)
# https://www.indicepa.gov.it/ipa-portale/consultazione/indirizzo-sede/ricerca-ente/elenco-aree-organizzative-omogenee/20608/scheda-area-organizzativa-omogenea/AC78FC0

Regola generale per URL di verifica: usa sempre dati reali recuperati dalle API. Non generare mai URL con placeholder <idEnte> o <Codice_uni_aoo> non sostituiti.

  • Se hai Codice_uni_aoo e idEnte → usa elenco-aree-organizzative-omogenee/<idEnte>/scheda-area-organizzativa-omogenea/<Codice_uni_aoo>
  • Se hai solo idEnte → usa scheda-ente/<idEnte>
  • Se non riesci a ottenere idEnte → non includere l'URL di verifica nella risposta

Esempio — Direzione Centrale Polizia Criminale (fallback su XZR4RNHR):

curl -s -X POST "https://www.indicepa.gov.it/ws/WS03OUServices/api/WS03_OU" \
  --data-urlencode "AUTH_ID=${IPA_auth_id}" \
  --data-urlencode "COD_AMM=XZR4RNHR" | python3 -c "
import json, sys
items = json.load(sys.stdin).get('data') or []
match = [x for x in items if 'criminal' in x.get('des_ou','').lower()]
for x in match: print(x.get('des_ou'), '|', x.get('mail1',''))
"

Esempio — PEC Tribunale di Roma (fallback):

curl -s -X POST "https://www.indicepa.gov.it/ws/WS03OUServices/api/WS03_OU" \
  --data-urlencode "AUTH_ID=${IPA_auth_id}" \
  --data-urlencode "COD_AMM=m_dg" | python3 -c "
import json, sys
items = json.load(sys.stdin).get('data') or []
match = [x for x in items if 'tribunale' in x.get('des_ou','').lower() and 'roma' in x.get('comune','').lower()]
for x in match: print(x.get('des_ou'), '|', x.get('mail1',''))
"

Sigle province per prefetture: pa=Palermo, mi=Milano, rm=Roma, na=Napoli, to=Torino, bo=Bologna, fi=Firenze, ge=Genova, ba=Bari, ct=Catania, ca=Cagliari, ve=Venezia.

Ricerca per codice fiscale (fatturazione elettronica)

curl -s -X POST "https://www.indicepa.gov.it/ws/WS01SFECFServices/api/WS01_SFE_CF" \
  --data-urlencode "AUTH_ID=${IPA_auth_id}" \
  --data-urlencode "CF=<codice_fiscale_11_cifre>"

Il campo cod_uni_ou nella risposta è il codice destinatario da inserire nel campo "Codice Ufficio" della fattura elettronica PA.

Interpretare i risultati

  • cod_err: 0 con num_items > 0 → successo, elabora i dati
  • cod_err: 0 con num_items: 0 → nessun risultato, suggerisci ricerca alternativa
  • cod_err: 900-902 → IPA_auth_id non disponibile nell'ambiente: informa l'utente
  • Altri codici di errore → vedi sezione "Codici di errore" nella guida completa

Come presentare le informazioni al cittadino

Parla in italiano semplice. Non mostrare JSON grezzo. Organizza sempre così:

Per un ente:

  • Nome completo e acronimo
  • Indirizzo (via, comune, CAP)
  • PEC ufficiale (evidenziala, è quella da usare per comunicazioni ufficiali)
  • Sito web istituzionale
  • Codice IPA (menzionalo come "codice identificativo")

Per gli uffici (UO):

  • Nome dell'ufficio
  • Telefono e email
  • Nome del responsabile
  • Codice univoco (se utile per fatturazione: spiegalo come "codice destinatario")

Se ci sono più risultati dalla ricerca (WS16): elencali con numero progressivo e chiedi quale intende, prima di procedere con le chiamate di dettaglio.

Se la ricerca non trova nulla: suggerisci alternative concrete — prova con acronimo, nome più corto, nome ufficiale completo.

URL di verifica (sempre in fondo): al termine di ogni risposta, genera il link più preciso possibile al portale IPA, scegliendo il tipo in base a ciò che hai trovato.

Endpoint PortaleServices (no auth, no CORS da curl)

# Ottieni idEnte da cod_amm
curl -s -X POST "https://www.indicepa.gov.it/PortaleServices/api/ente/ricerca" \
  -H "Content-Type: application/json" \
  -d '{"paginazione":{"campoOrdinamento":"idEnte","tipoOrdinamento":"asc","paginaRichiesta":1},"codEnte":"<cod_amm>"}' \
  | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['risposta']['listaResponse'][0]['idEnte'])"

# Dati completi ente (PEC primaria, numAoo, numOu, indirizzo, social) — più ricco di WS05
curl -s "https://www.indicepa.gov.it/PortaleServices/api/ente/eager/<idEnte>"

# Lista UO di un ente per idEnte (alternativa a WS03 quando non hai cod_amm)
curl -s -X POST "https://www.indicepa.gov.it/PortaleServices/api/ou/ente" \
  -H "Content-Type: application/json" \
  -d '{"paginazione":{"campoOrdinamento":"id","tipoOrdinamento":"asc","paginaRichiesta":1},"idEnte":<idEnte>}'

Pattern URL portale IPA

Genera sempre almeno uno di questi link, dal più specifico al più generico:

# Scheda AOO specifica (usa quando hai Codice_uni_aoo)
https://www.indicepa.gov.it/ipa-portale/consultazione/indirizzo-sede/ricerca-ente/elenco-aree-organizzative-omogenee/<idEnte>/scheda-area-organizzativa-omogenea/<Codice_uni_aoo>

# Elenco UO dell'ente (usa quando hai trovato una UO specifica)
https://www.indicepa.gov.it/ipa-portale/consultazione/indirizzo-sede/ricerca-ente/elenco-unita-organizzative/<idEnte>/ente

# Scheda ente completa (usa sempre come fallback)
https://www.indicepa.gov.it/ipa-portale/consultazione/indirizzo-sede/ricerca-ente/scheda-ente/<idEnte>

Come ottenere Codice_uni_aoo per la scheda AOO

# Dal CKAN IPA (no auth) — filtra per cod_amm, opzionalmente per città
curl -s -G "https://indicepa.gov.it/ipa-dati/api/3/action/datastore_search" \
  --data-urlencode "resource_id=cdaded04-f84e-4193-a720-47d6d5f422aa" \
  --data-urlencode 'filters={"Codice_IPA":"<cod_amm>"}' \
  --data-urlencode "q=<città>" \
  --data-urlencode "limit=10" \
  | python3 -c "
import json, sys
recs = json.load(sys.stdin)['result']['records']
for r in recs: print(r['Codice_uni_aoo'], '|', r['Denominazione_aoo'], '|', r['Denominazione_ente'])
"

Esempi pratici

Estrarre PEC di una prefettura con CKAN

curl -s -G "https://indicepa.gov.it/ipa-dati/api/3/action/datastore_search" \
  --data-urlencode "resource_id=cdaded04-f84e-4193-a720-47d6d5f422aa" \
  --data-urlencode "q=prefettura milano" \
  --data-urlencode "limit=3" \
  | python3 -c "
import json, sys
recs = json.load(sys.stdin)['result']['records']
for r in recs:
    # Mostra solo se Mail1 è presente (PEC)
    if r.get('Mail1'):
        print(r['Codice_uni_aoo'], '|', r['Denominazione_aoo'], '|', r['Mail1'])
"

Cercare una scuola con WS16

curl -s -X POST "https://www.indicepa.gov.it/ws/WS16DESAMMServices/api/WS16_DES_AMM" \
  --data-urlencode "AUTH_ID=${IPA_auth_id}" \
  --data-urlencode "DESCR=liceo scientifico" \
  | python3 -c "
import json, sys
raw = sys.stdin.read()
if not raw.strip():
    print('Nessuna risposta')
    sys.exit(0)
try:
    d = json.loads(raw)
except:
    print('Risposta non valida')
    sys.exit(0)
items = d.get('data') or []
for i in items[:5]:
    print(i.get('des_amm',''), '|', i.get('cod_amm',''), '|', i.get('pec',''))
"

Fallback su CKAN per ente non trovato

curl -s -G "https://indicepa.gov.it/ipa-dati/api/3/action/datastore_search" \
  --data-urlencode "resource_id=cdaded04-f84e-4193-a720-47d6d5f422aa" \
  --data-urlencode "q=comune di" \
  --data-urlencode "limit=5" \
  | python3 -c "
import json, sys
recs = json.load(sys.stdin)['result']['records']
for r in recs:
    print(r['Denominazione_ente'], '|', r['Codice_IPA'], '|', r.get('Mail1','N/D'))
"

Verifica idEnte per link al portale

curl -s -X POST "https://www.indicepa.gov.it/PortaleServices/api/ente/ricerca" \
  -H "Content-Type: application/json" \
  -d '{"paginazione":{"campoOrdinamento":"idEnte","tipoOrdinamento":"asc","paginaRichiesta":1},"codEnte":"m_it"}' \
  | python3 -c "import json,sys; print(json.load(sys.stdin)['risposta']['listaResponse'][0]['idEnte'])"

Skills relacionados