Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Einreichen
ToolsExploitsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

FeedsKontaktDatenschutz© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
halo-record — Manipulationssichere Audit-Trails für KI-Agenten: hash-verkettete Runtime Records, ohne Abhängigkeiten, von jedem verifizierbar. | Kitploit
Tools/GitHubGitHub/bkuan001/halo-record
ForensikLieferkettensicherheitIncident ResponseKI-Sicherheit
GitHubbkuan001/halo-record

halo-record

Manipulationssichere Audit-Trails für KI-Agenten: hash-verkettete Runtime Records, ohne Abhängigkeiten, von jedem verifizierbar.

Repository anzeigen
636102vor 24 TagenVon Kitploit geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Webseite
Teilen
# halo-record

Manipulationssichere **Audit-Trails für KI-Agenten** — hash-verkettete Runtime Records, dargestellt als Runtime Report, den Ihre Kunden selbst überprüfen können.

Jede Aktion, die Ihre Instrumentierung erfasst (Tool-Aufrufe, Modell-Aufrufe, Datenzugriffe, Genehmigungen), wird zu einem **Runtime Record** in einem append-only, hash-verketteten Log; der **Runtime Report** ist diese Kette, dargestellt als HTML-Seite, die die Hash-Kette im Browser des Lesers neu berechnet und das Angezeigte aus den von ihr verifizierten Records rendert (für eine Prüfung, die nicht auf den Code der Seite selbst angewiesen ist, führen Sie `halo verify` auf der JSONL aus). Jede Partei, die einen Checkpoint der Kette besitzt, kann verifizieren, dass die Records bis zu diesem Checkpoint seit seiner Erstellung nicht verändert wurden, ohne demjenigen vertrauen zu müssen, der sie erzeugt hat — dieser Checkpoint ist das tragende Element: Die Kette allein ist manipulationssicher gegenüber allen außer der Partei, die den Recorder betreibt ([LIMITS.md §1](https://github.com/bkuan001/halo-record/blob/main/LIMITS.md)). Wenn das Sicherheitsteam eines Kunden fragt „Was hat Ihr Agent mit unseren Daten gemacht?", geben Sie ihm einen Link statt eines Absatzes. Sicherheitsüberprüfungen stellen bereits KI-Fragen neben der SOC-2-Checkliste — und zunehmend kommen diese Fragen aus ISO 42001, den Aufzeichnungspflicht-Artikeln des EU AI Act und den eigenen Fragebögen der Kunden. Heute besteht noch eine schriftliche Zusicherung. Die Wette hinter diesem Projekt ist, dass das nicht lange so bleiben wird.

**Vorgestellt in [Help Net Security](https://www.helpnetsecurity.com/2026/08/31/halo-record-open-source-ai-agent-audit-trail/)** (August 2026).

Das Record-Format ist offen und frei implementierbar. Dieses Paket ist die Referenzimplementierung: Recorder, Verifier, Witness-Client und Report-Server.

> **Nutzen Sie halo-record oder denken darüber nach?** Sagen Sie mir, wer Sie sind und wofür → [Who's using halo-record?](https://github.com/bkuan001/halo-record/discussions/7)

## Prüfen Sie es selbst

Ihnen wird zugemutet, einen Recorder in Ihren Agenten einzubauen. Das sollten Sie nicht einfach glauben:

- **Keine Laufzeitabhängigkeiten.** Nur Standardbibliothek. `pip install halo-record` installiert genau ein Paket.
- **Keine Netzwerkaufrufe**, außer vier optionalen — Verankerung bei einem Witness (sendet die Subject-ID, eine Record-Anzahl und zwei Ketten-Fingerabdrücke — den Head und die Chain Root), das Zurücklesen der Checkpoints eines Witness (sendet die Subject-ID), der RFC-3161-Zeitstempel (sendet nur den State-Hash eines Checkpoints an eine Timestamp Authority) und `halo serve --verify-email` (sendet einen Einmalcode und den Subject-Namen des Reports per SMTP über den in `$HALO_SMTP_HOST` konfigurierten Server an die Adresse, die ein Report-Betrachter eingibt). Alle sind deaktiviert, sofern Sie sie nicht aufrufen; keine anderen Record-Inhalte verlassen Ihre Infrastruktur.
- **Rohe Tool-Argumente werden gehasht, mit einer redigierten Zusammenfassung daneben.** Argumente werden als kanonischer Hash plus Zusammenfassung gespeichert: der Argumenttext mit maskierten bekannten Secret- und PII-Mustern, auf 200 Zeichen begrenzt. Eine kurze Eingabe, die keinem Muster entspricht, erscheint vollständig in der Zusammenfassung; der Hash-Only-Modus (`summaries=False`) behält überhaupt keine Zusammenfassung. Die Redaktion ist Best-Effort (Regex über gängige Secret- und PII-Formate plus ein Entropie-Catch-All): Betrachten Sie sie als Defense-in-Depth, nicht als Garantie. Von Ihnen gelieferte Outcome-Felder jenseits von `summary` werden mit denselben Mustern gescannt und maskiert, aber nicht auf 200 Zeichen gekürzt (LIMITS §13).
- **Klein genug zum Auditieren.** ~8.700 Zeilen Python, einschließlich des eingebetteten JavaScript und CSS der Report-Seite (Code-Zeilen, ohne Leerzeilen, Kommentare und Docstrings). In einem Tag vollständig lesbar.
- **Apache-2.0.**
- **Der Papierkram ist erstklassig.** [LIMITS.md](https://github.com/bkuan001/halo-record/blob/main/LIMITS.md) (was die Kette nicht beweisen kann), [PRIVACY.md](https://github.com/bkuan001/halo-record/blob/main/PRIVACY.md) (was Records enthalten und was Ihre Maschine verlässt), [RETENTION.md](https://github.com/bkuan001/halo-record/blob/main/RETENTION.md) (Betrieb unter einer Aufbewahrungsrichtlinie) und [REVIEWERS.md](https://github.com/bkuan001/halo-record/blob/main/REVIEWERS.md) — die unabhängige Prüfung mit vier Befehlen plus ein Zitierformat für Review-Befunde.

Was jede Ebene beweist — die tragende Unterscheidung in diesem Projekt ([LIMITS.md §1](https://github.com/bkuan001/halo-record/blob/main/LIMITS.md)): Eine Kette, die Sie selbst halten, beweist, dass Records nicht **bearbeitet** wurden, relativ zu einem Head, den jemand bereits hält; nur Checkpoints, die außerhalb des Betreibers gehalten werden, beweisen, dass keine **entfernt** wurden; und kein Hash beweist, dass jede Aktion **erfasst** wurde.

| Behauptung | Selbst gehaltene Kette | + Externe Checkpoints | + Vertrauenswürdige Erfassung |
|---|---|---|---|
| Bearbeitungen an einem etablierten Artefakt erkennen | ✔ | ✔ | ✔ |
| Umschreiben committeter Historie erkennen | — | ✔ | ✔ |
| Fehlende/verspätete Checkpoints erkennen | — | ✔ (vereinbarte Kadenz) | ✔ |
| Beweisen, dass jede Aktion aufgezeichnet wurde | — | — | hängt von der Erfassungsgrenze ab |

**Sehen Sie sich einen an, bevor Sie installieren:** [ein Beispiel-Runtime-Report](https://bkuan001.github.io/halo-record/sample-report.html) — fiktive Daten, echte Kette, und sein Skript berechnet beim Öffnen die Hash-Kette der eingebetteten Records in Ihrem Browser neu.

## 60-Sekunden-Demo

Kein Agent erforderlich. Mit [uv](https://docs.astral.sh/uv/) nichts zu installieren:

```
uvx --from halo-record halo demo --serve
```

oder auf die klassische Weise:

```
pip install halo-record
halo demo --serve
```

Entweder scaffoldet es einen fiktiven Support-Agent-Anbieter mit zwei Kunden, bezeugt die Chains (mit einer lokalen Witness-Datei als Stellvertreter für eine außerhalb des Operators — siehe [LIMITS.md §1](https://github.com/bkuan001/halo-record/blob/main/LIMITS.md)), liefert deren gated Runtime Reports aus und öffnet die Operator-Konsole in deinem Browser. Probiere dann den Tamper-Test: Lösche eine Zeile aus einer der `.jsonl`-Dateien und lade neu. Der Report erkennt es.

## Zeichne deinen eigenen Agenten auf

Eine Zeile an der Grenze:

```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
```

Ein `from halo import ...` Convenience-Shim wird ebenfalls mitgeliefert — aber der Name `halo` auf PyPI gehört zu einem unabhängigen Terminal-Spinner-Paket, und wenn dieses Paket installiert ist, gewinnt es den Import. `halo_record` ist eindeutig, daher verwenden die Beispiele es.

Ohne `log=` gehen Records nach `~/.halo/my-agent.jsonl` (eine Chain pro Agent). Der Wrapper versiegelt die Run-Grenze; die Evidenz liegt in den Per-Call-Records. Erfasse diese mit einem Framework-Adapter (Matrix unten) — oder explizit, was auch zeigt, wie Delegation verknüpft:

```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)
```

Dann den Bericht rendern:

```
halo report audit.jsonl -o report.html    # one chain -> HTML that re-verifies in the browser
halo serve ./records --port 8721          # all tenants, gated per customer
```

Wird ein Verzeichnis erstmals von 0.2.45 bereitgestellt? `halo serve` liest bei jedem Start jede frühere Gewährung erneut ein. Eine Gewährung für eine Datei, deren Datensätze keine Subjekt-ID tragen (eine einfache `Recorder`-Datei wie `agent.jsonl`), wird unter Quarantäne gestellt und bei jedem Start zusammen mit dem `halo grant`-Befehl ausgegeben, der sie neu erteilt — siehe [LIMITS.md §17, „Serving a directory first served by 0.2.45“](https://github.com/bkuan001/halo-record/blob/main/LIMITS.md#17-one-chain-file-per-subject).

Der Schnellstart endet, wenn Sie den Runtime Report Ihres eigenen Agenten in einem Browser betrachten. Wenn Sie eine JSONL-Datei und keinen Bericht erhalten haben, stimmt etwas nicht: Öffnen Sie ein Issue.

### Der Verifikationsblock

Wenn eine Guardrail- oder Policy-Schicht die Aktion geprüft hat, kann ihr Urteil auf dem Datensatz mitgeführt werden — ein optionaler Block, der festhält, was das Gate entschieden hat, und der wie jedes andere Feld in die Hash-Kette versiegelt wird:

```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"})
```

Ein Hinweis zur Benennung: Das Paket exportiert eine `record`-*Funktion* (den Decorator), die das `halo_record.record`-*Modul* auf dem Paketobjekt verdeckt. Importiere direkt vom Modulpfad, wenn du dessen Interna benötigst — `from halo_record.record import build` — statt `import halo_record.record as record`.

was sich in den Datensatz einschließt als:

```json
"verification": {"status": "allowed", "verifier": "gate/1.2", "policy_ref": "sha256:1f3a...", "checked_at": "2026-08-01T12:00:00Z"}
```

`record_call(...)` akzeptiert dasselbe `verification=`-Schlüsselwort. `status` ist innerhalb des Blocks erforderlich; `verifier`, `policy_ref` und `checked_at` sind optional. Was die einzelnen Statuswerte bedeuten:

| Status | Was das Gate meldet | Wurde die Aktion ausgeführt? |
|---|---|---|
| `allowed` | es hat die Aktion erlaubt | ja — die Aktion wurde fortgesetzt |
| `blocked` | es hat die Aktion verweigert | wird durch die Integration bestimmt, nicht durch dieses Feld — ein Datensatz kann dennoch ein Ergebnis tragen, und ein Block beweist für sich genommen keine Nichtausführung |
| `modified` | es hat die Aktion vor der Ausführung verändert — `action.input` beschreibt die Aktion **wie ausgeführt**, nach der Modifikation | ja, in der veränderten Form |
| `unverified` | es wurde ausgeführt (oder konsultiert), traf aber keine Feststellung — verschieden von einem fehlenden Block, was bedeutet, dass überhaupt keine Verifikationsaussage gemacht wurde | ja — die Aktion wurde ohne Urteil fortgesetzt |

Der Block wird vom Integration-Code des Betreibers bereitgestellt und zeichnet auf, was dieser als Aussage des Gates meldet — dieselbe Vertrauenshaltung wie bei `principal` (siehe [LIMITS](https://github.com/bkuan001/halo-record/blob/main/LIMITS.md#11-verification-status-is-the-gates-report-not-halos-finding)). Das Versiegeln beweist, dass der Status nachträglich nicht verändert wurde; es beweist nicht, dass die Prüfung stattgefunden hat, dass das Urteil korrekt war oder dass eine blockierte Aktion nicht ausgeführt wurde. Dies ist keine unabhängige Verifikation.

Damit `policy_ref` als Nachweis verwendbar ist, verwenden Sie einen Content-Hash des Regelsatzes und bewahren Sie das Regelsatz-Artefakt auf — ein nicht auflösbares Label macht das Feld dekorativ.

## Anbinden an das, was Sie bereits betreiben

| An der Grenze erfasst | Aus vorhandener Telemetrie eingespeist |
|---|---|
| Nativer Recorder (`from halo_record import trace`) | OpenTelemetry GenAI Spans |
| MCP-Interceptor | LiteLLM-Callbacks |
| LangChain / LangGraph Callback | Langfuse-Export |
| OpenAI Agents SDK Hooks | Jedes Gateway- / Reverse-Proxy-Log |
| Claude Agent SDK Hook | Claude Code und Codex CLI `PostToolUse` Hooks (werden ausgelöst, nachdem das Tool ausgeführt wurde) |

Framework-Adapter und Ingestion-Pfade versehen jeden Datensatz mit einem `source`-Tag, sodass der Bericht offenlegt, wie jeder einzelne Nachweis erhoben wurde. Erfasste und eingespeiste Datensätze liegen in derselben Kette.

Für LangChain / LangGraph ist es ein 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
```

Für MCP umschließt ein Aufruf die Client-Sitzung — und dann gibt *jeder* MCP-verwendende Agent Datensätze für jeden Tool-Aufruf aus, unabhängig davon, welches Framework ihn steuert:

```python
from mcp import Client   # mcp 2.x
from halo_record import Recorder
from halo_record.integrations.mcp import instrument_client_session

async def run(server):   # an MCPServer, a server URL, or stdio parameters
    async with Client(server) as client:
        instrument_client_session(client, Recorder("audit.jsonl"), server="stripe")
        await client.call_tool("charge", {"customer": "cus_123", "amount": 500})   # recorded
```

Jeder `call_tool()`-Aufruf auf dem umschlossenen Client wird aufgezeichnet, und ein Tool, das ein Fehlerergebnis zurückgibt, wird als `error` versiegelt (der Adapter liest sowohl `isError` als auch das mcp 2.x `is_error`). Bei mcp 1.x übergeben Sie die initialisierte `ClientSession` anstelle von `Client`; der Wrapper ist derselbe.

Für Gateway- oder Proxy-Logs (Cloudflare AI Gateway, Portkey, nginx vor dem Modell) ordnen Sie eine Log-Zeile der Kette zu — explizit als ingestiert gekennzeichnet, nicht als Boundary-erfasst:

```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"})
```

Alles, was OpenTelemetry GenAI-Spans ausgibt (CrewAI, LlamaIndex und die meisten Agent-Frameworks mit OTel-Instrumentierung), landet über den OTel-Adapter in der Chain, und das [TypeScript-Paket](https://github.com/bkuan001/halo-record-ts) liefert native Adapter für das Vercel AI SDK und das JS-Agent-Ökosystem. Fehlt ein Adapter für deinen Stack? Eröffne ein Issue. Die meisten Adapter umfassen etwa hundert Zeilen.

## Zeichne deinen Coding-Agenten auf (Claude Code oder Codex)

Claude Code feuert einen `PostToolUse`-Hook nach jedem Tool-Aufruf. Richte ihn auf `halo hook` und jede Aktion — Dateischreibvorgänge, Shell-Befehle, MCP-Connector-Aufrufe — wird zu einem Record in einer lokalen Chain. Keine Code-Änderungen; ein Eintrag in den Einstellungen:

```json
{
  "hooks": {
    "PostToolUse": [
      {"matcher": "*", "hooks": [{"type": "command", "command": "halo hook"}]}
    ]
  }
}
```

Füge das zu `~/.claude/settings.json` hinzu, und Einträge landen in `~/.halo/audit.jsonl` (überschreibbar mit `$HALO_LOG`). Reine Orchestrierungswerkzeuge, die keine Daten, Netzwerk oder externen Zustand berühren, werden übersprungen — die Kette zeichnet Vertrauensgrenzaktionen auf, nicht Denken. Setze `HALO_HASH_ONLY=1`, um Inhalts-Hashes ohne Zusammenfassungen aufzuzeichnen. Setze `HALO_AGENT_VERSION` (und optional `HALO_AGENT_MODEL`), um jeden Eintrag an den Agenten-Build zu binden, der ihn erzeugt hat — wenn ein Prüfer nach der Version fragt, die in einem bestimmten Zeitfenster lief, antwortet der Export spaltenweise statt aus dem Gedächtnis.

Codex CLI liefert dieselben Lifecycle-Hooks mit derselben Ereignisform (Hooks sind standardmäßig aktiviert). Füge dies zu `~/.codex/hooks.json` hinzu, und Codex' Shell-Befehle, `apply_patch`-Bearbeitungen und MCP-Aufrufe landen in derselben Kette:

```json
{
  "hooks": {
    "PostToolUse": [
      {"matcher": ".*", "hooks": [{"type": "command", "command": "halo hook"}]}
    ]
  }
}
```

Der Hook unterscheidet die beiden anhand des Events selbst (Codex fügt `turn_id` und `model` hinzu) und kennzeichnet jeden Datensatz als `claude-code` oder `codex`; setze `HALO_HOOK_AGENT`, um eines zu erzwingen. Beide gehören zur ingestierten Ebene: Ein `PostToolUse`-Hook wird ausgelöst, nachdem das Tool ausgeführt wurde, sodass der Datensatz aus dem aufgebaut wird, was das Harness meldet.

Wenn der Bericht die Frage beantworten soll, „unter welchen Regeln dieser Lauf stattgefunden hat?", setze `HALO_AUTHORITY_FILE` auf einen JSON-Snapshot der effektiven Authority für die Session. Halte ihn datenschutzsicher: Hashes und Refs, keine rohen Prompts, privaten Policy-Text, Secrets oder vollständigen Tool-Schemas — bekannte Secret- und personenbezogene Datenformate werden zum Versiegelungszeitpunkt maskiert, aber Hashes und Refs passieren unverändert und Freitext wird nicht erkannt (siehe LIMITS §6). Verwende eine `snapshot_id` nur so lange wieder, wie die zugrunde liegende Authority unverändert ist; aufeinanderfolgende Datensätze mit derselben ID und unverändertem Inhalt werden kompaktiert — eine wiederverwendete ID über geändertem Inhalt wird vollständig gespeichert, mit einem Hinweis.

```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"]
}
```

```sh
HALO_AUTHORITY_FILE=./authority.json halo hook
```

Der Snapshot wird in dieselbe Hash-Kette wie die Action-Datensätze eingefügt. Ein guter Standard ist ein Snapshot auf Sitzungsebene zu Beginn, plus ein neuer Snapshot, wenn sich Regeln, Skills, Hooks, MCP-Tool-Registries oder die Compaction-Richtlinie ändern. Um lange Sitzungen schlank zu halten, werden aufeinanderfolgende Datensätze mit derselben `authority.snapshot_id` nach dem ersten vollständigen Snapshot kompaktiert: spätere Datensätze behalten nur `{"snapshot_id": "...", "same_as_previous": true}`. Der Zeiger bleibt hash-verkettet, aber der umfangreiche Block aus refs/omissions/stale-if wird nicht bei jeder Aktion wiederholt. (Die Compaction erfolgt pro Recorder-Prozess: Bei hook-artiger Erfassung, die einen Prozess pro Tool-Aufruf startet, wird der vollständige Body jedes Mal neu gespeichert, wenn der vorherige vollständige Snapshot nicht der letzte Datensatz ist, sodass kurzlebige Prozesse Kettenlänge gegen den Wiederverwendungsschutz eintauschen.)

SDK-Nutzer hängen denselben Block direkt an — `build(..., authority={...})` oder `record_call(..., authority={...})`; die reine Hash-Erfassung bietet dieselbe Schnittstelle (`summaries=False` bei jedem von ihnen):

```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")
```

Dann das Übliche:

```
halo verify ~/.halo/audit.jsonl
halo report ~/.halo/audit.jsonl -o report.html
```

Jede Agent-Runtime, die einen Post-Action-Hook bereitstellt, kann denselben Befehl einspeisen — der Hook liest ein Ereignis als JSON von stdin und hängt einen Datensatz an.

Eine Chain, ein Schreiber zur Zeit. Eine Chain ist eine verkettete Liste: Zwei Schreiber, die denselben Head lesen und beide anhängen, spalten sie auf (zwei Datensätze, die denselben Vorgänger beanspruchen), und die Verifikation benennt die betroffenen Datensätze. `Recorder` serialisiert seine eigenen Anhänge mit einem Sidecar-Lock (hier POSIX `flock`; ein Lock-Verzeichnis im TypeScript-Paket), und `halo hook` hängt über `Recorder` an, sodass das obige Hook-Setup abgedeckt ist. Alles, was die Chain-Datei direkt schreibt — ein handgeschriebener Hook, parallele Worker, ein Log-Shipper — muss ein äquivalentes exklusives Lock über die Sequenz Read-Head-dann-Append halten oder in prozesseigene Chains schreiben. [LIMITS.md Abschnitt 9](https://github.com/bkuan001/halo-record/blob/main/LIMITS.md#9-single-writer-chains) behandelt dies vollständig, einschließlich der sprachübergreifenden Grenze.

## Wenn die Aufzeichnung fehlschlägt

Datensätze werden geschrieben, nachdem die Aktion ausgeführt wurde. Halo blockiert eine Aktion nicht, wenn ihr Datensatz nicht geschrieben werden kann; das Schreiben des Datensatzes vor der Aktion wird nicht angeboten.

- **Standard: Das Ergebnis der Aktion wird durchgereicht.** Wenn ein Datensatz nicht geschrieben werden kann (Festplatte voll, Berechtigungen, ein Lock-Timeout), geben `trace()`, `record_call`, `@record`, die Framework-Adapter (OpenAI Agents, LangChain, LiteLLM, OpenTelemetry), der MCP-Wrapper und `halo hook` das Ergebnis der Aktion unverändert zurück oder lösen die eigene Exception der Aktion erneut aus, falls diese fehlgeschlagen ist. Eine Warnung auf stderr benennt den fehlenden Datensatz: `halo-record: FAILED to record '<tool>' (<error>); the action ran, but its record is NOT in the evidence log. ...` (ohne nutzbares stderr geht sie an den `halo_record`-Logger). Der LangChain-Handler und der OTel-Exporter zählen Verluste ebenfalls (`lost_records`). Nichts in der Chain kann einen Datensatz zeigen, der nie geschrieben wurde, sodass die verbleibenden Datensätze weiterhin verifizieren. Ein Reviewer, der die Kadenz der Witness-Checkpoints beobachtet, sieht eine Chain, die ins Stocken geraten ist; ein einzelner fehlender Datensatz zwischen späteren zeigt sich nur in der stderr-Zeile.
- **Der Strict-Modus löst ebenfalls aus.** Übergib `strict_recording=True` (an `trace`, `record_call`, `@record`, `instrument_client_session` oder den Konstruktor eines Adapters) oder setze `HALO_STRICT_RECORDING=1`, und dieselbe stderr-Zeile wird geschrieben, dann wird der Aufzeichnungsfehler ausgelöst. Er erreicht den Aufrufer von `trace`, `record_call`, `@record`, dem MCP-Wrapper, den OpenAI-Agents-Hooks und dem LangChain-Handler (der LangChains `raise_error` setzt). Er kann den Aufrufer nicht vom OTel-Exporter oder dem LiteLLM-Logger erreichen: Diese Frameworks fangen ab und protokollieren, was ein Exporter oder Callback auslöst, sodass dort die stderr-Zeile das Signal in beiden Modi ist (LIMITS.md Abschnitt 18). Die Aktion wurde bereits ausgeführt, wenn der Fehler ausgelöst wird, sodass ein Aufrufer, der ihn als „die Aktion ist fehlgeschlagen" behandelt und erneut versucht, die Seiteneffekte der Aktion wiederholt (eine zweimal ausgezahlte Rückerstattung). Verwende den Strict-Modus nur dort, wo ein fehlender Datensatz schlimmer ist als dieses Risiko.
- `record_call` und `@record` ohne Recorder (keiner übergeben, keiner durch `trace` gebunden) lösen `RuntimeError` aus, bevor der umschlossene Code läuft.
- `@record` und `trace()` akzeptieren `async def`-Funktionen. Der Wrapper ist selbst `async def`: Er awaited die Funktion und zeichnet dann auf, was sie zurückgegeben oder ausgelöst hat (eine Cancellation wird als Fehler aufgezeichnet). `trace()` hält seinen Recorder gebunden, während der Body awaited wird, sodass ein `record_call`- oder `@record`-Tool innerhalb eines Async-Agents auf der getracten Chain landet und gleichzeitige Agents jeweils ihre eigene behalten. Eine einfache Funktion, die ein Awaitable zurückgibt, wird aufgezeichnet, wenn sie zurückkehrt. Eine Async-Generator-Funktion wird aufgezeichnet, wenn sie aufgerufen wird, mit dem Generator-Objekt als Ergebnis; was sie yielded, wird nicht aufgezeichnet.

## Integrität vs. Vollständigkeit (lies diesen Teil)

Sei präzise darüber, was jede Schicht beweist — denn es sind unterschiedliche Behauptungen, und die Unterschiede sind der Punkt:

Eine selbst gehaltene Chain beweist **Integrität relativ zu einem etablierten Head**: Gegeben ein Chain-Head, den jemand bereits hält, wird jede Bearbeitung, Umordnung oder Löschung in den Datensätzen dahinter erkennbar. Für sich genommen — bevor jemand außerhalb des Operators einen Head gesehen hat — beweist eine Chain interne Konsistenz, nicht Historie: Ein Operator könnte einen Datensatz verwerfen und neu versiegeln, und die neue Datei würde verifizieren. Die Chain wird **historisch festgeschrieben** in dem Moment, in dem ihr Head die Kontrolle des Operators verlässt.

Das ist der Witness: Eine Partei außerhalb des Operators, die periodische Checkpoints der Chain hält — die Subject-ID, eine Datensatzanzahl und zwei Chain-Fingerabdrücke (der Head und die Chain-Root); die exakte Payload und nichts anderes. Checkpoints machen das Umschreiben festgeschriebener Historie erkennbar, und ein verpasster Checkpoint ist selbst ein sichtbares Ereignis:

```
halo anchor audit.jsonl witness.jsonl           # anchor a checkpoint to a local witness
halo anchor audit.jsonl witness.jsonl --check   # completeness verdict against it
```

Für *time* speziell ersetzt ein externer RFC-3161-Zeitstempel die selbstbehauptete Uhr des Checkpoints durch einen Nachweis von einer Timestamp Authority außerhalb der Kontrolle des Betreibers — „diese Chain erreichte diesen Head nicht später als T", überprüfbar durch einen Dritten ohne gehostete Infrastruktur. Die Standard-TSA ist das kostenlose freetsa.org (für Evaluierungszwecke in Ordnung); für den Produktionseinsatz richten Sie `--tsa` auf eine TSA außerhalb der Kontrolle des Betreibers (z. B. DigiCert / Sectigo oder eine, die eine vertrauende Partei bestimmt):

```
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` bestätigt, dass das Token an diesen Chain-Zustand gebunden ist und liest dessen attestierte Zeit, aber es validiert **nicht** die Signatur der TSA — das wird bewusst einem Standardwerkzeug überlassen, damit ein Prüfer keinem Code von uns vertrauen muss. Um die Zeit unabhängig zu verifizieren (das ist es, was Sie einem Sicherheitsprüfer aushändigen):

```
# 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"
```

Eine weitere Grenze, klar ausgedrückt: Weder die Kette noch der Witness beweist, dass jede reale Aktion durch den Recorder gelaufen ist. Das ist **Capture-Vollständigkeit** — eine Eigenschaft davon, wo der Recorder im Stack sitzt (native Instrumentierung, Hooks, Gateway-Ingestion), nicht von irgendeinem Hash. Records tragen aus genau diesem Grund ein `source`-Tag. Die Claims-Tabelle unter „Check it yourself“ oben auf dieser Seite ist die Zusammenfassung dieser drei Schichten.

Jeder kann einen Witness betreiben. Ein Witness, den Sie selbst betreiben, schreibt die Historie *Ihnen* zu; sie *Ihrem Kunden* zuzuschreiben erfordert einen Witness, dem er Grund zu vertrauen hat. Das Protokoll ist in beiden Fällen offen.

Ein gehosteter, anerkannter Witness ist der Weg, wie sich dieses Projekt selbst tragen wird. Early Access: [email protected].

## Personenbezogene Daten in der Kette

Die Kette ist append-only: Alles, was in einen Record versiegelt wird, bleibt dort, weil
das Entfernen die Verifikation für alles danach brechen würde. Tool-Argumente werden
bereits behandelt — gespeichert als Hash plus eine redigierte Zusammenfassung, begrenzt auf 200 Zeichen
(hash-only-Modus behält keine Zusammenfassung; in id-Feldern maskiert er ein Token in einem bekannten Secret-
Format wie in Zusammenfassungen und ersetzt jedes andere secret-förmige Token durch `sha256:`
plus 16 Hexadezimalziffern — alle außer `subject.id`, das den Record an die Kette seines Tenants weiterleitet).

Beachten Sie die Einschränkung in diesem Satz: *redigiert*, nicht entfernt. [LIMITS.md](https://github.com/bkuan001/halo-record/blob/main/LIMITS.md)
Abschnitt 6 ist explizit, dass ein Name oder eine Postanschrift kein verlässliches Muster hat, sodass
weder das eine noch das andere erkannt und weder das eine noch das andere maskiert wird. Und `subject` ist nicht das einzige Feld, das
von Ihnen gelieferten Text trägt — `principal`, `approver`, `session_id`, `agent`,
`authority`, `data` und die Zusammenfassungen tun dies alle.

Das Muster, das funktioniert: Legen Sie eine stabile pseudonyme ID in die Kette und halten Sie die
Zuordnung zu einer Person in einem System, aus dem Sie löschen können. Eine Löschungsanfrage wird
dann durch Löschen der Zuordnung erfüllt. Lassen Sie `subject` auf die Tenant-
Organisation zeigen, nicht auf eine Person:

```python
from halo_record import build

build("tool_call", "privacy", subject={"id": "acme", "name": "Acme Corp"})
```

Keine Einstellung erzwingt dies — es ist eine Disziplin darin, wie du den Recorder aufrufst.
Es macht die Löschung handhabbar; es ist keine Anonymisierung, und es gibt noch keine
integrierte Aufbewahrung oder Bereinigung.
[LIMITS.md Abschnitt 13](https://github.com/bkuan001/halo-record/blob/main/LIMITS.md#13-personal-data-and-erasure) enthält die vollständige Feldliste,
erklärt, warum der gespeicherte Eingabe-Fingerabdruck einen erratbaren Wert bestätigen kann, selbst
nachdem die Zuordnung entfernt wurde, und endet mit Fragen, die ein Prüfer stellen sollte.

Zeichne einen Modellaufruf auf (die erste Frage des Käufers: „Welches Modell hat meine Daten gesehen?"):

```python
from halo_record import Recorder, record_model_call

rec = Recorder("audit.jsonl")
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
```

Das Modell wird außerdem als `agent.model` versiegelt und die Aufbewahrungsbedingungen als `data.zdr`,
sodass die Modellspalte und die Richtlinienregeln des Exports sie lesen können und beide
`summaries=False` überleben. Übergeben Sie `messages=`, und die Eingabe des Datensatzes trägt, wie viele
es waren — eine Anzahl, niemals deren Inhalt.

## Wo dies in einem Compliance-Stack einzuordnen ist

halo-record ist eine Evidenzschicht, keine Zertifizierung. Es erzeugt das Artefakt, das Bewertungsframeworks immer wieder mit anderen Worten einfordern. Eine Scope-Anmerkung, die jeden Punkt unten bestimmt: Dies sind Integritätsaussagen über den Datensatz; Vollständigkeit gegenüber dem Betreiber erfordert einen externen Zeugen, der Checkpoints hält ([LIMITS.md §1](https://github.com/bkuan001/halo-record/blob/main/LIMITS.md)).

- **Sicherheitsfragebögen und SOC-2-Prüfungen:** Beantworten Sie die KI-Abschnitte mit einem verifizierbaren Runtime Report statt mit Screenshots und Prosa.
- **AIUC-1:** erzeugt die manipulationssichere Logging-Evidenz (E015.4) und Ausführungsketten-Datensätze mit Autorisierungsereignissen (E015.2 — mit einer erklärten Lücke: Reasoning-Traces werden nicht erfasst), die die Accountability-Kontrolle E015 des Standards benennt. E015 selbst ist verpflichtend; E015.2 und E015.4 sind ihre ergänzende Stufe: nicht erforderlich zum Bestehen, diejenige, die ein Anbieter annimmt, wenn ein Kunde oder Regulator danach fragt. Sobald die Kette an einen Zeugen verankert ist, dem die vertrauende Partei Grund zu vertrauen hat — ein Zeuge, den der Betreiber selbst betreibt, bietet dies nicht —, ist das eine kontinuierlich bezeugte Kette statt einer, die zur Auditzeit rekonstruiert wird (was in die Kette gelangt ist, bleibt weiterhin durch die Erfassungsoberfläche begrenzt). Eine Kontrolle-für-Kontrolle-Evidenzzuordnung, einschließlich dessen, was bewusst außerhalb des Geltungsbereichs liegt, findet sich in [`AIUC.md`](https://github.com/bkuan001/halo-record/blob/main/AIUC.md).

---

[Read more](https://github.com/bkuan001/halo-record)
Tool herunterladen