
halo-record v0.2.7
Registri runtime a prova di manomissione per agenti AI. Basati su catena di hash, senza dipendenze, verificabili da chiunque.
halo-record
Audit trail a prova di manomissione per agenti AI — Runtime Record concatenati tramite hash, resi come Runtime Report che i tuoi clienti possono verificare autonomamente.
Ogni azione compiuta dal tuo agente (chiamate a tool, chiamate a modelli, accesso ai dati, approvazioni) diventa un Runtime Record in un log append-only concatenato tramite hash; il Runtime Report è quella catena resa come pagina HTML auto-verificante. Qualsiasi parte in possesso di un checkpoint della catena può verificare che i record sottostanti non siano mai stati alterati, senza fidarsi di chi li ha prodotti — quel checkpoint è il pezzo portante: la catena da sola è a prova di manomissione contro tutti tranne che contro chi gestisce il recorder (LIMITS.md §1). Quando il team di sicurezza di un cliente chiede "cosa ha fatto il tuo agente con i nostri dati?", gli consegni un link invece di un paragrafo. Le revisioni di sicurezza pongono già domande sull'AI accanto alla checklist SOC 2 — e sempre più spesso quelle domande arrivano da ISO 42001, dagli articoli sulla conservazione dei registri dell'EU AI Act e dai questionari dei clienti stessi. Oggi un'assicurazione scritta passa ancora. La scommessa dietro questo progetto è che non durerà a lungo.
Segnalato su Help Net Security (agosto 2026).
Il formato dei record è aperto e libero da implementare. Questo pacchetto è l'implementazione di riferimento: recorder, verifier, client witness e server dei report.
Stai usando halo-record, o ci stai pensando? Dimmi chi sei e per cosa → Chi sta usando halo-record?
Verificalo tu stesso
Ti viene chiesto di inserire un recorder dentro il tuo agente. Non dovresti accettarlo sulla fiducia:
- Zero dipendenze a runtime. Solo libreria standard.
pip install halo-recordinstalla esattamente un pacchetto. - Nessuna chiamata di rete, tranne tre opt-in — l'ancoraggio a un witness (invia l'id del soggetto, un conteggio dei record e due impronte della catena — la testa e la radice della catena), la lettura dei checkpoint di un witness (invia l'id del soggetto) e il timestamp RFC 3161 (invia solo l'hash di stato di un checkpoint a una Timestamp Authority). Tutte disattivate a meno che tu non le invochi; il contenuto dei record non lascia mai la tua infrastruttura.
- Gli argomenti grezzi dei tool vengono hashati, con accanto un riepilogo redatto. Gli argomenti sono memorizzati come hash canonico più un riepilogo: il testo dell'argomento con i pattern noti di segreti e PII mascherati, limitato a 200 caratteri. Un input breve che non corrisponde ad alcun pattern appare per intero nel riepilogo; la modalità solo-hash (
summaries=False) non conserva alcun riepilogo. La redazione è best-effort (regex sui formati comuni di segreti e PII più un catch-all basato sull'entropia): considerala difesa in profondità, non una garanzia. I campi di esito che fornisci oltre asummaryvengono sigillati così come sono (LIMITS §13). - Abbastanza piccolo da poter essere verificato. ~5.300 righe di Python (righe di codice, escludendo righe vuote e commenti). Leggile tutte in un pomeriggio.
- Apache-2.0.
- La documentazione è di prim'ordine. LIMITS.md (cosa la catena non può dimostrare), PRIVACY.md (cosa contengono i record e cosa lascia la tua macchina), RETENTION.md (operare sotto una policy di conservazione) e REVIEWERS.md — il controllo indipendente in quattro comandi più un formato di citazione per i risultati della revisione.
Cosa dimostra ciascun livello — la distinzione portante in questo progetto (LIMITS.md §1): una catena che tieni tu stesso dimostra che i record non sono stati modificati, rispetto a una testa che qualcuno già possiede; solo i checkpoint detenuti al di fuori dell'operatore dimostrano che nessuno è stato rimosso; e nessun hash dimostra che ogni azione sia stata catturata.
| Affermazione | Catena auto-detentua | + Checkpoint esterni | + Cattura fidata |
|---|---|---|---|
| Rilevare modifiche a un artefatto stabilito | ✔ | ✔ | ✔ |
| Rilevare la riscrittura della storia consolidata | — | ✔ | ✔ |
| Rilevare checkpoint mancanti/in ritardo | — | ✔ (cadenza concordata) | ✔ |
| Dimostrare che ogni azione è stata registrata | — | — | dipende dal confine di cattura |
Vedine uno prima di installare: un Runtime Report di esempio — dati fittizi, catena reale, e si ri-verifica da solo nel tuo browser mentre guardi.
Demo in 60 secondi
Nessun agente richiesto. Con uv, niente da installare:``` uvx --from halo-record halo demo --serve
o nel modo classico:```
pip install halo-record
halo demo --serve
Either one scaffolds a fictional support-agent vendor with two customers, witnesses the chains (with a local witness file standing in for one outside the operator — see LIMITS.md §1), serves their gated Runtime Reports, and opens the operator console in your browser. Then try the tamper test: delete a line from one of the .jsonl files and reload. The report catches it.
Record your own agent
One line at the boundary:```python from halo_record import trace
agent = trace(run_my_agent, profile="my-agent", log="audit.jsonl") # wraps your entrypoint; records the run boundary to ./audit.jsonl — add record_call() or a framework adapter at each tool boundary to capture individual calls
Anche uno shim di comodità `from halo import ...` viene fornito — ma il nome `halo` su PyPI appartiene a un pacchetto terminal-spinner non correlato, e se quel pacchetto è installato vince l'import. `halo_record` è inequivocabile, quindi gli esempi lo usano.
Senza `log=`, i record vanno in `~/.halo/my-agent.jsonl` (una catena per agente). Il wrapper sigilla il confine di esecuzione; l'evidenza risiede nei record per chiamata. Catturali con un adattatore di framework (matrice sotto) — o esplicitamente, il che mostra anche come si collegano le deleghe:```python
from halo_record import Recorder, record_call
rec = Recorder("audit.jsonl")
with record_call(rec, "crm.lookup", {"account": "acct-9"}) as call: # one sealed record per tool call
call.result = crm.lookup("acct-9")
with record_call(rec, "payments.refund", {"amount": 120},
parent_id=rec.last_record_id()) as call: # child links to the action that spawned it
call.result = payments.refund(120)
Poi genera il report:``` halo report audit.jsonl -o report.html # one chain -> self-verifying HTML halo serve ./records --port 8721 # all tenants, gated per customer
Il quickstart termina quando stai guardando il Runtime Report del tuo agente in un browser. Se hai ottenuto un file JSONL e nessun report, qualcosa non va: apri una issue.
### Il blocco di verifica
Se un guardrail o un livello di policy ha controllato l'azione, il suo verdetto può viaggiare sul record — un blocco opzionale che registra ciò che il gate ha deciso, sigillato nella catena di hash come ogni altro campo:```python
from halo_record import build
build("tool_call", "security", tool="payments.refund",
verification={"status": "allowed", "verifier": "gate/1.2",
"policy_ref": "sha256:1f3a...",
"checked_at": "2026-08-01T12:00:00Z"})
che si sigilla nel record come:```json "verification": {"status": "allowed", "verifier": "gate/1.2", "policy_ref": "sha256:1f3a...", "checked_at": "2026-08-01T12:00:00Z"}
`record_call(...)` accetta la stessa keyword `verification=`. `status` è obbligatorio all'interno del blocco; `verifier`, `policy_ref` e `checked_at` sono opzionali. Cosa significa ogni stato:
| Stato | Cosa riporta il gate | L'azione è stata eseguita? |
|---|---|---|
| `allowed` | ha permesso l'azione | sì — l'azione è proceduta |
| `blocked` | ha negato l'azione | determinato dall'integrazione, non da questo campo — un record può comunque riportare un esito, e un blocco di per sé non prova la mancata esecuzione |
| `modified` | ha alterato l'azione prima dell'esecuzione — `action.input` descrive l'azione **così come eseguita**, dopo la modifica | sì, nella forma alterata |
| `unverified` | è stato eseguito (o consultato) ma non ha prodotto alcuna determinazione — distinto da un blocco assente, che significa che non è stata avanzata alcuna pretesa di verifica | sì — l'azione è proceduta senza un verdetto |
Il blocco è fornito dal codice di integrazione dell'operatore e registra ciò che esso riporta che il gate abbia detto — la stessa postura di fiducia di `principal` (vedi [LIMITS](https://github.com/bkuan001/halo-record/blob/main/LIMITS.md#11-verification-status-is-the-gates-report-not-halos-finding)). La sigillatura prova che lo stato non è stato modificato a posteriori; non prova che il controllo sia avvenuto, che il verdetto fosse corretto, o che un'azione bloccata non sia stata eseguita. Questa non è una verifica indipendente.
Affinché `policy_ref` sia utilizzabile come prova, usa un hash del contenuto del ruleset e conserva l'artefatto del ruleset — un'etichetta non risolvibile rende il campo decorativo.
## Connettiti a ciò che già esegui
| Catturato al confine | Acquisito dalla telemetria esistente |
|---|---|
| Recorder nativo (`from halo_record import trace`) | Span OpenTelemetry GenAI |
| Intercettore MCP | Callback LiteLLM |
| Callback LangChain / LangGraph | Esportazione Langfuse |
| Hook OpenAI Agents SDK | Qualsiasi log di gateway / reverse-proxy |
| Hook Claude Agent SDK | Hook `PostToolUse` di Claude Code e Codex CLI (si attivano dopo l'esecuzione dello strumento) |
Gli adattatori di framework e i percorsi di acquisizione marcano ogni record con un tag `source`, così il report divulga come ogni elemento di prova è stato raccolto. I record catturati e quelli acquisiti risiedono nella stessa catena.
Per LangChain / LangGraph, è un callback handler:```python
from halo_record import Recorder
from halo_record.integrations.langchain import HaloCallbackHandler
recorder = Recorder("audit.jsonl")
result = my_chain.invoke(inputs, config={"callbacks": [HaloCallbackHandler(recorder)]}) # every tool call becomes a record
Per MCP, una chiamata racchiude la sessione client — e poi qualsiasi agente che utilizza MCP emette record per ogni chiamata di strumento, indipendentemente dal framework che lo guida:```python from halo_record.integrations.mcp import instrument_client_session
instrument_client_session(session, Recorder("audit.jsonl"), server="stripe") # every session.call_tool() is now recorded
Per i log di gateway o proxy (Cloudflare AI Gateway, Portkey, nginx davanti al modello), mappare una riga di log nella catena — esplicitamente contrassegnata come acquisita, non catturata al confine:```python
from halo_record.integrations.gateway import record_log
record_log(Recorder("audit.jsonl"), {"tool": "gen_ai:gpt-4o", "model": "gpt-4o", "status": 200, "subject": "acme-corp"})
Qualsiasi cosa che emetta span OpenTelemetry GenAI (CrewAI, LlamaIndex e la maggior parte dei framework agent con strumentazione OTel) finisce nella catena attraverso l'adattatore OTel, e il pacchetto TypeScript fornisce adattatori nativi per il Vercel AI SDK e l'ecosistema agent JS. Manca un adattatore per il tuo stack? Apri una issue. La maggior parte degli adattatori è di circa un centinaio di righe.
Registra il tuo coding agent (Claude Code o Codex)
Claude Code attiva un hook PostToolUse dopo ogni chiamata a uno strumento. Puntalo a halo hook e ogni azione — scritture di file, comandi shell, chiamate a connettori MCP — diventa un record in una catena locale. Nessuna modifica al codice; una voce nelle impostazioni:```json
{
"hooks": {
"PostToolUse": [
{"matcher": "*", "hooks": [{"type": "command", "command": "halo hook"}]}
]
}
}
Aggiungilo a `~/.claude/settings.json` e i record finiscono in `~/.halo/audit.jsonl` (sovrascrivibile con `$HALO_LOG`). Gli strumenti di pura orchestrazione che non toccano dati, rete o stato esterno vengono saltati — la catena registra le azioni sui confini di fiducia, non il pensiero. Imposta `HALO_HASH_ONLY=1` per registrare gli hash dei contenuti senza riepiloghi. Imposta `HALO_AGENT_VERSION` (e facoltativamente `HALO_AGENT_MODEL`) per associare ogni record alla build dell'agente che l'ha prodotto — quando un auditor chiede informazioni sulla versione in esecuzione in una determinata finestra, l'export risponde per colonna invece che a memoria.
Codex CLI fornisce gli stessi hook del ciclo di vita con la stessa forma degli eventi (gli hook sono attivi per impostazione predefinita). Aggiungi questo a `~/.codex/hooks.json` e i comandi shell di Codex, le modifiche di `apply_patch` e le chiamate MCP finiscono nella stessa catena:```json
{
"hooks": {
"PostToolUse": [
{"matcher": ".*", "hooks": [{"type": "command", "command": "halo hook"}]}
]
}
}
L'hook distingue i due dall'evento stesso (Codex aggiunge turn_id e model) ed etichetta ogni record come claude-code o codex; imposta HALO_HOOK_AGENT per forzarne uno. Entrambi appartengono al tier ingerito: un hook PostToolUse viene attivato dopo l'esecuzione dello strumento, quindi il record viene costruito da ciò che l'harness riporta.
Se hai bisogno che il report risponda alla domanda "sotto quali regole è avvenuta questa esecuzione?", imposta HALO_AUTHORITY_FILE su uno snapshot JSON dell'autorità effettiva per la sessione. Mantienilo sicuro per la privacy: hash e ref, non prompt grezzi, testo di policy privato, segreti o schemi di strumenti completi — i formati di segreti noti vengono mascherati al momento del seal, ma hash e ref passano inalterati e il testo libero non viene rilevato (vedi LIMITS §6). Riusa uno snapshot_id solo finché l'autorità sottostante rimane invariata; record consecutivi con lo stesso id e contenuto invariato vengono compattati — un id riutilizzato su contenuto modificato viene memorizzato per intero, con un avviso.```json
{
"snapshot_id": "auth_2026_07_08T1100Z",
"captured_at": "2026-07-08T11:00:00Z",
"scope": "session",
"workspace": {"path_hash": "sha256:...", "git_commit": "abc1234"},
"refs": [
{"kind": "project_rules", "id": "CLAUDE.md", "hash": "sha256:...", "loaded": true, "truncated": false},
{"kind": "mcp_tool_registry", "id": "filesystem", "hash": "sha256:..."}
],
"omissions": [{"kind": "private_policy", "reason": "customer_secret", "hash": "sha256:..."}],
"stale_if": ["project_rules_hash_changed", "mcp_tool_registry_hash_changed"]
}
## Installazione
### Requisiti
- Python 3.8+
- pip (gestore di pacchetti Python)
### Installazione da PyPI
```bash
pip install pyxam
Installazione da sorgente
git clone https://github.com/example/pyxam.git
cd pyxam
pip install -e .
Installazione con Docker
docker pull example/pyxam:latest
docker run -it example/pyxam --help
Utilizzo
Utilizzo di base
from pyxam import Xam
# Inizializza il client
client = Xam(api_key="your-api-key")
# Esegui una scansione
result = client.scan(target="example.com")
print(result)
Utilizzo da riga di comando
pyxam scan --target example.com --output results.json
Opzioni di configurazione
| Opzione | Descrizione | Valore predefinito |
|---|---|---|
--target | L'URL o l'indirizzo IP di destinazione | Nessuno |
--output | Il percorso del file di output | results.json |
--verbose | Abilita l'output dettagliato | False |
--timeout | Timeout della richiesta in secondi | 30 |
Esempi
Scansione di un singolo target
from pyxam import Xam
client = Xam()
result = client.scan(target="https://example.com")
print(f"Trovate {len(result.vulnerabilities)} vulnerabilità")
Scansione di più target
targets = ["example.com", "test.com", "demo.com"]
for target in targets:
result = client.scan(target=target)
print(f"{target}: {result.status}")
Licenza
Questo progetto è distribuito sotto la licenza MIT. Consulta il file LICENSE per i dettagli.```sh HALO_AUTHORITY_FILE=./authority.json halo hook
Lo snapshot è sigillato nella stessa catena di hash dei record delle azioni. Un buon valore predefinito è uno snapshot a livello di sessione all'inizio, più un nuovo snapshot quando cambiano regole, Skills, hook, registri di strumenti MCP o policy di compattazione. Per mantenere snelle le sessioni lunghe, i record consecutivi con lo stesso `authority.snapshot_id` vengono compattati dopo il primo snapshot completo: i record successivi mantengono solo `{"snapshot_id": "...", "same_as_previous": true}`. Il puntatore rimane concatenato tramite hash, ma il blocco voluminoso refs/omissions/stale-if non viene ripetuto a ogni azione. (La compattazione è per processo del recorder: la cattura in stile hook che genera un processo per ogni chiamata di strumento ri-archivia il corpo completo ogni volta che lo snapshot completo precedente non è il record di coda, quindi i processi di breve durata scambiano dimensione della catena con la protezione di riutilizzo.)
Gli utenti dell'SDK allegano lo stesso blocco direttamente — `build(..., authority={...})` o `record_call(..., authority={...})`; la cattura solo-hash è la stessa superficie (`summaries=False` su uno qualsiasi di essi):```python
from halo_record import Recorder, record_call
rec = Recorder("audit.jsonl")
with record_call(rec, "crm.lookup", {"account": "acct-9"},
authority={"snapshot_id": "auth_1", "rules_hash": "sha256:..."},
summaries=False) as call: # hash-only: no summaries, no excerpts
call.result = crm.lookup("acct-9")
Poi, il solito:``` halo verify ~/.halo/audit.jsonl halo report ~/.halo/audit.jsonl -o report.html
Qualsiasi runtime di agente che espone un hook post-azione può alimentare lo stesso comando — l'hook legge un evento come JSON su stdin e aggiunge un record.
Una catena, un solo scrittore alla volta. Una catena è una lista concatenata: due scrittori che leggono la stessa testa e aggiungono entrambi la ramificheranno (due record che rivendicano lo stesso predecessore), e la verifica nominerà i record interessati. `Recorder` serializza i propri append con un lock sidecar (POSIX `flock` qui; una directory di lock nel pacchetto TypeScript), e `halo hook` aggiunge tramite `Recorder`, quindi la configurazione dell'hook sopra è coperta. Qualsiasi cosa che scriva direttamente il file della catena — un hook artigianale, worker paralleli, un log shipper — deve mantenere un lock esclusivo equivalente attraverso la sequenza read-head-then-append, oppure scrivere su catene per-processo. [LIMITS.md sezione 9](https://github.com/bkuan001/halo-record/blob/main/LIMITS.md#9-single-writer-chains) copre questo in modo completo, incluso il confine cross-linguaggio.
## Quando la registrazione fallisce
I due stili di integrazione falliscono in direzioni opposte, di proposito — scegli quello la cui modalità di fallimento puoi sopportare:
- **Gli adattatori di framework (LangChain, hook tramite callback manager) falliscono aperti.** Se un record non può essere scritto (disco pieno, permessi), l'azione dell'agente si completa normalmente e il record viene perso. L'handler LangChain stampa un avviso evidente su stderr e conta la perdita (`handler.lost_records`), ma nulla nella catena stessa può mostrare un record che non è mai stato scritto — una catena bloccata verifica comunque. I checkpoint del witness a cadenza sono ciò che rende visibile una catena bloccata: un checkpoint atteso che non arriva mai è l'allarme.
- **Il wrapper nativo `trace()` fallisce chiuso.** Se il record non può essere scritto, l'eccezione si propaga nell'azione dell'agente — nessuna prova, nessuna azione. Più rigoroso, e può interrompere il tuo agente.
Nessuno dei due default è giusto per tutti; sappi quale stai eseguendo.
## Integrità vs. completezza (leggi questa parte)
Sii preciso su ciò che ogni livello dimostra — perché sono affermazioni diverse, e le differenze sono il punto:
Una catena auto-detentua dimostra **integrità rispetto a una testa stabilita**: data una testa di catena che qualcuno già detiene, qualsiasi modifica, riordino o cancellazione nei record dietro di essa diventa rilevabile. Di per sé — prima che qualcuno esterno all'operatore abbia visto una testa — una catena dimostra coerenza interna, non storia: un operatore potrebbe eliminare un record e ri-sigillare, e il nuovo file verificherebbe. La catena diventa **storicamente impegnata** nel momento in cui la sua testa lascia il controllo dell'operatore.
Questo è il witness: una parte esterna all'operatore che detiene checkpoint periodici della catena — l'id del soggetto, un conteggio dei record, e due impronte della catena (la testa e la radice della catena); il payload esatto, e nulla di più. I checkpoint rendono rilevabile la riscrittura della storia impegnata, e un checkpoint mancato è esso stesso un evento visibile:```
halo anchor audit.jsonl witness.jsonl # anchor a checkpoint to a local witness
halo anchor audit.jsonl witness.jsonl --check # completeness verdict against it
Per time nello specifico, un timestamp RFC 3161 esterno sostituisce l'orologio auto-dichiarato del checkpoint con una prova fornita da una Timestamp Authority che l'operatore non controlla — "questa catena ha raggiunto questa testa non oltre T", verificabile da terzi senza infrastruttura ospitata. La TSA predefinita è la gratuita freetsa.org (adatta per la valutazione); punta a una TSA commerciale (DigiCert / Sectigo / la tua) con --tsa per la produzione:```
halo anchor audit.jsonl witness.jsonl --timestamp # attach a TSA time proof to the checkpoint
halo anchor audit.jsonl witness.jsonl --check # reads the token's claimed time
`--check` conferma che il token è vincolato a questo stato della catena e ne legge il tempo attestato, ma **non** convalida la firma della TSA — ciò è deliberatamente lasciato a uno strumento standard affinché un revisore non debba fidarsi di alcun nostro codice. Per verificare il tempo in modo indipendente (questo è ciò che si consegna a un revisore di sicurezza):```
# tsa.token_b64 lives in the witness log; decode the latest one to a standard .tsr file
python3 -c 'import json,base64; cps=[json.loads(l) for l in open("witness.jsonl") if l.strip()]; t=[c["tsa"] for c in cps if c.get("tsa")][-1]; open("token.tsr","wb").write(base64.b64decode(t["token_b64"])); print(t["digest"])'
curl -s -o tsa-ca.pem https://freetsa.org/files/cacert.pem # CA for the default TSA (a commercial TSA publishes its own)
openssl ts -verify -digest <the digest printed above> -in token.tsr -CAfile tsa-ca.pem # → "Verification: OK"
Un altro confine, detto chiaramente: né la catena né il witness dimostrano che ogni azione nel mondo reale sia passata attraverso il registratore. Questa è la completezza di cattura — una proprietà di dove si colloca il registratore nello stack (strumentazione nativa, hook, ingestione tramite gateway), non di un hash qualsiasi. I record portano un tag source esattamente per questo motivo. La tabella delle affermazioni sotto "Check it yourself" in cima a questa pagina è il riepilogo di questi tre livelli.
Chiunque può eseguire un witness. Un witness che esegui tu stesso impegna la storia verso di te; impegnarla verso il tuo cliente richiede un witness di cui abbia motivo di fidarsi. Il protocollo è aperto in entrambi i casi.
Un witness ospitato e riconosciuto è il modo in cui questo progetto si sosterrà. Accesso anticipato: [email protected].
Dati personali nella catena
La catena è append-only: qualsiasi cosa sigillata in un record rimane lì, perché rimuoverla romperebbe la verifica per tutto ciò che segue. Gli argomenti degli strumenti sono già gestiti — memorizzati come un hash più un riepilogo redatto limitato a 200 caratteri (la modalità solo-hash non conserva alcun riepilogo).
Nota il limite in quella frase: redatto, non rimosso. LIMITS.md
la sezione 6 è esplicita sul fatto che un nome o un indirizzo postale non hanno un pattern affidabile, quindi
né l'uno né l'altro vengono rilevati e né l'uno né l'altro vengono mascherati. E subject non è l'unico campo che
contiene testo da te fornito — principal, approver, session_id, agent,
authority, data e i riepiloghi lo fanno tutti.
Il pattern che funziona: inserisci un id pseudonimo stabile nella catena e conserva la
mappatura verso qualsiasi individuo in un sistema da cui puoi cancellare. Una richiesta di cancellazione è
quindi soddisfatta eliminando la mappatura. Mantieni subject puntato all'organizzazione tenant, non a una persona:```python
from halo_record import build
build("tool_call", "privacy", subject={"id": "acme", "name": "Acme Corp"})
Nessuna impostazione impone questo — è una disciplina nel modo in cui chiami il recorder.
Rende la cancellazione gestibile; non è anonimizzazione, e non esiste ancora
una retention o una potatura integrate.
[LIMITS.md sezione 13](https://github.com/bkuan001/halo-record/blob/main/LIMITS.md#13-personal-data-and-erasure) contiene l'elenco completo dei campi,
spiega perché l'impronta dell'input memorizzata può confermare un valore indovinabile anche
dopo che la mappatura è sparita, e termina con le domande che un revisore dovrebbe porre.
Registra una chiamata al modello (la prima domanda dell'acquirente: "quale modello ha visto i miei dati?"):```python
from halo_record import record_model_call
record_model_call(rec, provider="anthropic", model="claude-sonnet-4-6",
zdr=True, purpose="draft support reply",
subject="acme") # tool=model.generate, scope=model:anthropic
Dove si colloca in uno stack di conformità
halo-record è un livello di evidenza, non una certificazione. Produce l'artefatto che i framework di valutazione continuano a richiedere con parole diverse. Una nota di ambito che governa ogni punto elencato di seguito: queste sono affermazioni di integrità sul record; la completezza rispetto all'operatore richiede un testimone esterno che detenga checkpoint (LIMITS.md §1).
- Questionari di sicurezza e revisioni SOC 2: rispondi alle sezioni AI con un Runtime Report verificabile invece che con screenshot e prosa.
- AIUC-1: produce l'evidenza di logging tamper-evident (E015.4) e i record della catena di esecuzione con eventi di autorizzazione (E015.2 — con una lacuna dichiarata: le tracce di ragionamento non vengono catturate) che il controllo Accountability E015 dello standard nomina. E015 stesso è obbligatorio; E015.2 ed E015.4 sono il suo livello supplementare: non richiesti per il superamento, quello che un fornitore adotta quando un cliente o un regolatore lo richiede. Una volta che la catena è ancorata a un testimone di cui la parte affidante ha motivo di fidarsi — un testimone gestito dall'operatore stesso non fornisce questo — si tratta di una catena continuamente testimoniata anziché ricostruita al momento dell'audit (ciò che entra nella catena è comunque limitato dalla superficie di cattura). Una mappatura delle evidenze controllo per controllo, incluso ciò che è deliberatamente fuori ambito, è in
AIUC.md. - OWASP Top 10 for Agentic Applications 2026: otto delle dieci minacce si mappano su regole di policy deterministiche sul record, due sono contrassegnate come fuori ambito con motivazioni, e il pacchetto è eseguibile. Una mappatura approssimativa della community, non un artefatto ufficiale OWASP. Vedi
OWASP.md. - AARM (CSA): produce la ricevuta d'azione tamper-evident che AARM specifica — R5, e la metà di sigillatura di R6 (l'identità è sigillata nell'hash, non autenticata crittograficamente). halo-record è il livello della ricevuta; abbinalo a un gateway di enforcement per un sistema AARM completo. Vedi
AARM.md. - Agentic Trust Controls: i record di runtime dietro i controlli di evidenza dell'ATC — logging delle azioni tamper-evident (RBM-03) e la metà del record dell'attestazione di autorità (AID-05; la metà di enforcement appartiene al gate) in un unico record concatenato. Vedi
ATC.md. - CSA AI Controls Matrix (AICM) / STAR for AI: l'evidenza del dominio LOG — record di audit generati, sigillati contro modifiche non rilevate, eventi di input e output registrati — mappata controllo per controllo in
AICM.md. Il crosswalk v1.1 di CSA stesso collega quel dominio a AIUC-1 E015. - MITRE ATLAS: la mitigazione di telemetria dell'agente (AML.M0024) implementata con una proprietà di integrità che ATLAS stesso non richiede — il log è verificabile da qualcuno esterno all'operatore. Vedi
ATLAS.md. - EU AI Act / ISO 42001 / NIST AI RMF: gli obblighi di tenuta dei registri e logging che questi framework descrivono sono la stessa classe di artefatti — mappati in modo conservativo in EU-AI-ACT.md, ISO42001.md e NIST-AI-RMF.md.
Niente di tutto questo certifica alcunché di per sé. Dà al tuo valutatore qualcosa di verificabile da esaminare. I confini — ciò che halo-record deliberatamente non fa, e cosa dire quando un revisore chiede — sono documentati in LIMITS.md.
Portare l'evidenza nella tua piattaforma GRC
La maggior parte delle piattaforme GRC (Vanta, Drata e simili) accetta file caricati come evidenza personalizzata a fronte di un controllo. L'export di halo-record è costruito per inserirsi in quel flusso:```bash halo export audit.jsonl --from 2026-06-01 --to 2026-06-30 -o evidence.csv
scope the export to the actions a control covers
halo export audit.jsonl --from 2026-06-01 --to 2026-06-30 --tool email.send --tool db.query -o evidence.csv
Questo scrive due file per la finestra di audit: il CSV (una riga per ogni azione registrata, raggruppate da sinistra a destra come *quando → cosa è successo → chi → sotto quale autorità → cosa è stato segnalato → provenienza → come verificare*, inclusa una sintesi in linguaggio semplice e redatta della chiamata e del suo risultato, la build dell'agente e il modello che ha prodotto ciascuna, l'identità per conto della quale è stata eseguita, il record che l'ha causata, la sua decisione di autorizzazione e l'ambito, e qualsiasi categoria di dati personali o flag di minaccia acquisiti) e un manifest (`evidence.csv.manifest.json`) che collega il CSV alla sua origine — l'hash di testa della catena lo collega al log verificabile da cui proviene, e `csv_sha256` è l'hash del file esportato stesso, quindi un CSV modificato dopo l'esportazione non corrisponde più al suo manifest. Restringi la popolazione con `--tool` quando un controllo copre solo determinate azioni; il manifest registra il filtro, quindi un'esportazione con ambito limitato dichiara di essere un sottoinsieme anziché essere letta come l'intera popolazione. Carica entrambi in base al tuo controllo di logging o monitoraggio; allega il Runtime Report HTML quando un revisore vuole verificare la catena autonomamente. L'esportazione rifiuta di essere eseguita su una catena che non supera la verifica.
Un'integrazione push nativa — con le prove che arrivano automaticamente nella tua piattaforma — è in programma. Il percorso file sopra funziona oggi con qualsiasi piattaforma che accetta prove caricate.
## CLI```
halo verify validate schema + hash chain (exit 1 broken, 3 empty chain; CI-friendly)
halo report render a chain as a self-verifying HTML Runtime Report
(--from/--to: a date-windowed report covering only the review period)
halo policy corroborate a chain against a declarative policy pack
(per-rule pass / violation / evidence-gap; exit 1 violated, 3 nothing in scope)
halo serve serve per-tenant reports over HTTP, access-scoped per customer
halo grant designate a report recipient (email or domain)
halo viewers list who has unlocked a gated report
halo anchor witness a chain head, or --check completeness (exit 1 incomplete, 3 unwitnessed)
halo witness-serve run a witness over HTTP: vendors anchor chain heads, viewers fetch checkpoints
halo demo scaffold the full vendor demo (record -> witness -> gated report)
halo export date-bounded evidence export: CSV + manifest tied to the chain head
halo sample emit a valid example log
halo hash canonical sha256 of a JSON value
halo hook Claude Code PostToolUse hook
Modello di integrità
Per calcolare l'hash di un record: prendere il record escludendo integrity.hash, con integrity.prev_hash impostato all'hash del record precedente; canonicalizzare con RFC 8785 (JSON Canonicalization Scheme); applicare SHA-256 ai byte. Il prev_hash del primo record è composto da 64 zeri. La verifica ricalcola ogni hash e controlla ogni collegamento. Nessun segreto richiesto; questo è il punto.
Pensi di poter manomettere una catena senza che il verificatore se ne accorga? Tentativi e risultati sono qui.
Riferimento completo dei campi: halo-record.schema.json.
TypeScript
Lo stesso recorder è disponibile per Node: halo-record-ts. Stesso formato di catena, stesso protocollo di witness. I record scritti in entrambi i linguaggi si verificano con entrambi i verificatori.
Esempi della community
trail-halo-poc — proof of concept della community che lega l'autorità principale di un record Halo alle credenziali TRAIL: un binding reciproco org–agent e concessioni di scope firmate dall'org registrate in una catena Halo, con una suite di verifica adversariale.
Contribuire
Issue, discussioni e pull request sono benvenute — consulta CONTRIBUTING.md per le regole di base (versione breve: test obbligatori, PR piccole, le modifiche allo schema vengono discusse prima).
Licenza
Apache-2.0