Agent-almanac conduct-empirical-wire-capture
git clone https://github.com/pjt222/agent-almanac
T=$(mktemp -d) && git clone --depth=1 https://github.com/pjt222/agent-almanac "$T" && mkdir -p ~/.claude/skills && cp -r "$T/i18n/de/skills/conduct-empirical-wire-capture" ~/.claude/skills/pjt222-agent-almanac-conduct-empirical-wire-capture-43f8d1 && rm -rf "$T"
i18n/de/skills/conduct-empirical-wire-capture/SKILL.mdConduct Empirical Wire Capture
Einen reproduzierbaren Wire-Capture-Harness für den ausgehenden HTTP-Verkehr und die Telemetrie eines CLI-Werkzeugs einrichten und dabei jedes Observability-Ziel dem kostengünstigsten Kanal zuordnen, der es erfasst.
Geltungsbereich und Ethik
Vor der Konfiguration jeglicher Erfassung lesen.
- Wire Capture ist ausschließlich für eigene Anfragen gegen das eigene Konto auf der eigenen Maschine gedacht. Das Erfassen des Datenverkehrs anderer Nutzer ist Exfiltration, keine Forschung, und liegt außerhalb des Geltungsbereichs.
- In rohen Wire-Ausgaben tauchen fast immer Zugangsdaten auf. Redaktion zum Zeitpunkt der Erfassung durchführen (Schritt 6) — niemals nach dem Motto „erst erfassen, später redigieren".
- Erfassung ist Beobachtung, keine Modifikation. Erfasste Payloads nicht dazu nutzen, serverseitige Rate-Limits zu umgehen, die Sitzung eines anderen Nutzers zu replayen oder eine dunkel ausgerollte Fähigkeit ohne Autorisierung zu aktivieren.
- Das Ergebnis dieses Skills ist ein internes Artefakt. Die öffentliche Veröffentlichung von Wire-Befunden läuft über
(Phase 5 des übergeordneten Leitfadens), nicht über diesen Skill.redact-for-public-disclosure
Wann verwenden
- Ein statischer Befund (ein Flag, eine Endpunkt-Referenz, ein Telemetrie-Ereignisname) benötigt eine Laufzeitbestätigung, dass er tatsächlich ausgelöst wird.
- Eine Payload-Form wird für eine Client-Neuimplementierung, eine Tracing-Instrumentierung oder einen versionsübergreifenden Diff benötigt.
- Eine Dark-vs-Live-Unterscheidung erfordert die Beobachtung dessen, was das Binary tatsächlich sendet — nicht dessen, was das Bundle nahelegt.
- Ein Verhalten hat sich zwischen Versionen stillschweigend geändert und ein reproduzierbares Artefakt wird benötigt, um gegen zukünftige Versionen zu vergleichen.
Diesen Skill nicht verwenden für: Versions-Baselining (dafür
monitor-binary-version-baselines), Flag-Zustandsprüfung (dafür probe-feature-flag-state) oder das Vorbereiten redigierter Artefakte zur öffentlichen Veröffentlichung (dafür redact-for-public-disclosure).
Eingaben
- Erforderlich: Ein CLI-Harness-Binary, das lokal gegen das eigene Konto ausgeführt werden kann.
- Erforderlich: Eine konkrete Frage, die beantwortet werden soll (z. B. „feuert Endpunkt X bei Ereignis Y?", „wie sieht die Payload-Form für Telemetrie-Ereignis Z aus?"). Eine Erfassung ohne Fragestellung erzeugt ein Log, das niemand liest.
- Optional: Statische Befunde aus vorangegangenen Phasen (Marker-Katalog, Kandidaten-Flag-Liste, verdächtige Endpunkte), die die Erfassungsziele eingrenzen.
- Optional: Ein privater Arbeitsbereich-Pfad für Erfassungsartefakte. Standard ist
— muss in./captures/
stehen..gitignore
Vorgehen
Schritt 1: Zuerst die Observability-Tabelle aufbauen
Bevor irgendeine Erfassung konfiguriert wird, die zu beantwortenden Fragen auflisten und jede einem Erfassungskanal zuordnen. Eine Zeile pro Ziel.
| target | observable via | blocker |
|---|---|---|
| Outbound HTTP to endpoint X | verbose-fetch stderr | TUI noise pollutes terminal |
| Telemetry event Y on user action | hook-driven subprocess | requires harness hook surface |
| Token-refresh handshake | outbound HTTP proxy | cert trust required |
| Scheduled-task lifecycle event | long-running session capture | wallclock alignment |
| Local config mutation | on-disk state diff | none — cheapest channel |
Gängige Kanäle, kostengünstigster zuerst:
- Mutation der Zustandsdatei auf Platte — wenn der Harness seinen Zustand auf einen bekannten Pfad schreibt, ist
zwischen Snapshots kostenlos.diff - Transkriptdatei — wenn der Harness ohnehin ein Sitzungstranskript schreibt, dieses direkt parsen. Keine Instrumentierung nötig.
- Verbose-Fetch-stderr — vom Bundler bereitgestellte Umgebungsvariable (z. B. Buns
) leitet jeden Fetch an stderr. Laut, erfasst aber jeden Fetch.BUN_CONFIG_VERBOSE_FETCH=curl - Hook-getriebener Subprozess — wenn der Harness Lifecycle-Hooks exponiert (
,UserPromptSubmit
usw.), für jedes Ereignis einen kurzen Erfassungs-Subprozess starten.Stop - Langlaufende Sitzungserfassung — ein Prozess über die gesamte Sitzung, mit Wallclock versehen. Für Sequenzen verwenden.
- Ausgehender HTTP-Proxy — saubere Trennung, erfordert aber CA-Zertifikatsvertrauen und bricht, wenn der Harness Zertifikate pinnt.
Den kostengünstigsten Kanal wählen, der das Ziel erfasst. Eine Erfassung mit 3 Zielen, die eine konkrete Frage beantwortet, schlägt eine Erfassung mit 20 Zielen, die keine beantwortet.
Expected: eine Observability-Tabelle mit einer Zeile pro Frage, jeweils mit Kanal und bekannten Blockern annotiert. Ziele ohne tragfähigen Kanal werden als „außerhalb des Geltungsbereichs dieser Sitzung" gekennzeichnet.
On failure: landet jedes Ziel in der Proxy-Spalte, ist die Tabelle zu ambitioniert. Auf die ein oder zwei wertvollsten Fragen reduzieren und für diese nochmals günstigere Kanäle prüfen.
Schritt 2: Einen verwerflichen Arbeitsbereich vorbereiten
Wire Capture verschmutzt Terminals, hinterlässt Dateien an unerwarteten Orten und kann Zugangsdaten in Logs lecken.
mkdir -p captures/$(date -u +%Y-%m-%dT%H-%M-%S) cd captures/$(date -u +%Y-%m-%dT%H-%M-%S) echo 'captures/' >> ../../.gitignore git check-ignore captures/ || echo "WARNING: captures/ not git-ignored"
Sicherstellen, dass die Erfassungssitzung nicht die primäre Arbeitssitzung ist — Verbose-Fetch und TUI-Rendering stören sich gegenseitig.
Expected: ein zeitgestempeltes Erfassungsverzeichnis, git-ignoriert, getrennt von der Arbeitssitzung.
On failure: meldet
git check-ignore das Verzeichnis als nicht ignoriert, die .gitignore korrigieren, bevor ein Erfassungsbefehl ausgeführt wird. Nicht mit gefährdeten Zugangsdaten fortfahren.
Schritt 3: Hook-getriebene Erfassung für Einzelereignis-Ziele
Wenn das Ziel ein diskretes Ereignis ist (ein Tool-Aufruf, eine Prompt-Einreichung, ein Sitzungsstopp), die Hook-Oberfläche des Harness nutzen. Für jedes Ereignis einen kurzlebigen Erfassungs-Subprozess starten; nicht in-process verweilen.
Das Muster (synthetisches Beispiel):
# Hook script, registered with the harness's hook config. # Invoked once per event; writes one JSONL line; exits. #!/usr/bin/env bash set -euo pipefail TS=$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ) EVENT="${1:-unknown}" PAYLOAD=$(jq -c --arg ts "$TS" --arg ev "$EVENT" \ '{ts:$ts, source:"hook", target:$ev, payload:.}' < /dev/stdin) echo "$PAYLOAD" >> "$CAPTURE_DIR/events.jsonl"
Warum Subprozess pro Ereignis:
- Kein Tokenzustand, keine Sitzungskopplung — jeder Aufruf ist unabhängig.
- Das Fehlschlagen einer Erfassung kontaminiert die nächste nicht.
- Der Subprozess-Overhead ist akzeptabel, weil Ereignisse selten sind (pro Nutzeraktion, nicht pro Byte).
Expected: eine JSONL-Zeile pro ausgelöstem Ereignis in
events.jsonl, jede wohlgeformt und per jq parsebar.
On failure: meldet
jq Parse-Fehler, enthält die Payload unescapte Steuerzeichen oder Binärdaten — stattdessen durch jq -R (raw input) leiten und das Payload-Feld base64-kodieren.
Schritt 4: Langlaufende Sitzungserfassung für sequentiellen Zustand
Wenn das Ziel eine Sequenz ist (mehrstufiger Handshake, Lifecycle geplanter Aufgaben, Retry/Backoff-Zustandsautomat), einen Erfassungsprozess über die gesamte Sitzung, mit Wallclock versehen.
# Run the harness with verbose-fetch routed to a tee-d log. BUN_CONFIG_VERBOSE_FETCH=curl harness-cli run-task 2> >( while IFS= read -r line; do printf '%s\t%s\n' "$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)" "$line" done >> "$CAPTURE_DIR/session.tsv" )
Das Wallclock-Präfix macht die Reihenfolge eindeutig, wenn mehrere Erfassungen gleichzeitig laufen. TSV (tab-getrennt) ist bewusst gewählt — es übersteht Shells, die JSON-Quoting auf stderr verstümmeln.
TSV erst nach Sitzungsende (Schritt 5) nach JSONL konvertieren, nicht währenddessen.
Expected: ein TSV-Log mit monoton steigenden Zeitstempeln, eine stderr-Zeile pro Reihe.
On failure: laufen Zeitstempel rückwärts, puffert der Harness stderr — mit
stdbuf -oL -eL oder dem Line-Buffer-Flag des Bundlers neu ausführen.
Schritt 5: Auf JSONL normalisieren
JSONL ist das Artefaktformat: ein JSON-Objekt pro Zeile, Felder
timestamp, source, target, payload. Diff-freundlich, per jq filterbar und stabil über Editor-Reloads hinweg.
# Parse the TSV from Step 4 into JSONL. awk -F'\t' '{ printf "{\"timestamp\":\"%s\",\"source\":\"verbose-fetch\",\"target\":\"%s\",\"payload\":%s}\n", $1, "session", $2 }' < session.tsv | jq -c . > session.jsonl
Prüfen, ob jede Zeile parst:
while IFS= read -r line; do echo "$line" | jq -e . > /dev/null || echo "BAD LINE: $line" done < session.jsonl
Typische Filter-Verwendung:
# Show only requests to a specific endpoint pattern. jq -c 'select(.payload | tostring | test("/api/v1/example"))' session.jsonl # Show timing between consecutive captures. jq -r '.timestamp' session.jsonl | sort | uniq -c
Expected: jede Zeile von
*.jsonl parst mit jq -e .; keine BAD LINE-Warnungen.
On failure: scheitern einzelne Zeilen an der Validierung, enthielt die Quell-TSV eingebettete Tabs in der Payload — Schritt 4 mit einem anderen Trennzeichen neu ausführen oder das zweite Feld base64-kodieren.
Schritt 6: Redaktion zum Erfassungszeitpunkt
Auth-Header, Sitzungs-IDs, Bearer-Tokens und PII vor dem Schreiben auf Platte entfernen. Die
events.jsonl- und session.jsonl-Dateien sollen beim ersten Schreibvorgang kein einziges Geheimnis enthalten.
# Stream the raw capture through a redactor before persisting. redact() { sed -E \ -e 's/(authorization:[[:space:]]*Bearer[[:space:]]+)[A-Za-z0-9._-]+/\1<REDACTED>/gi' \ -e 's/(x-api-key:[[:space:]]*)[A-Za-z0-9._-]+/\1<REDACTED>/gi' \ -e 's/(cookie:[[:space:]]*)[^;]+/\1<REDACTED>/gi' \ -e 's/("password"[[:space:]]*:[[:space:]]*)"[^"]*"/\1"<REDACTED>"/g' \ -e 's/("token"[[:space:]]*:[[:space:]]*)"[^"]*"/\1"<REDACTED>"/g' } cat raw-capture.txt | redact > session.tsv
Nach der Erfassung verifizieren, dass nichts durchgerutscht ist:
# Patterns that must not appear in any *.jsonl file. grep -Ei 'bearer [A-Za-z0-9]{20,}|sk-[A-Za-z0-9]{20,}|ghp_[A-Za-z0-9]{20,}' captures/ \ && { echo "LEAK DETECTED"; exit 1; } \ || echo "redaction clean"
Das Muster „erst erfassen, dann redigieren" lässt immer etwas durchsickern. Das einzig sichere Muster ist „redigiert beim Erfassen". Wird ein nicht redigiertes Token in einem finalisierten Artefakt entdeckt, die gesamte Erfassung als kompromittiert behandeln — löschen, die Zugangsdaten rotieren und neu ausführen.
Expected: die
LEAK DETECTED-Prüfung endet mit Exitcode 0 (keine Treffer). grep nach bekannten Zugangsdaten-Präfixen liefert nichts.
On failure: findet die Leck-Prüfung einen Treffer, die Datei nicht in-place editieren. Das gesamte Erfassungsverzeichnis löschen, die Redaktor-Regex um die geleckte Musterkategorie erweitern und ab Schritt 3 oder 4 neu ausführen.
Schritt 7: Antwortkategorien vor dem Aufzeichnen klassifizieren
HTTP-Statuscodes tragen in verschiedenen Kontexten unterschiedliches semantisches Gewicht. Vor dem Aufzeichnen klassifizieren, damit nachgelagerte
jq-Filter auf Intention und nicht auf Rohcodes operieren.
| Observed status | Channel context | Classification |
|---|---|---|
| 200 / 201 | Any | success |
| 401 on token-refresh endpoint | Handshake | expected handshake step |
| 401 on data endpoint | After auth | auth failure (real) |
| 404 on lazy-loaded resource | First fetch | expected miss |
| 404 on documented endpoint | After feature gate | gate-induced absence |
| 429 | Any | rate-limit (back off; do not retry tight) |
| 5xx | Any | server failure (record, do not assume) |
Ein
class-Feld zum Erfassungszeitpunkt hinzufügen:
jq -c '. + {class: ( if (.payload.status == 401 and (.target | test("token|refresh"))) then "handshake" elif (.payload.status >= 200 and .payload.status < 300) then "success" elif (.payload.status == 401) then "auth-fail" elif (.payload.status == 429) then "rate-limit" elif (.payload.status >= 500) then "server-fail" else "other" end)}' session.jsonl > session.classified.jsonl
Ein 401 auf einem Token-Refresh-Kanal ist kein Fehler — es ist die erste Hälfte eines Handshakes. Handshake-Schritte fälschlich als Fehler zu klassifizieren produziert falsch-positive Befunde, die die Aufmerksamkeit der Reviewer verschwenden.
Expected: jede Zeile in
*.classified.jsonl hat ein class-Feld mit einem bekannten Wert.
On failure: erzeugt die Klassifizierung viele
other-Einträge, ist die obige Tabelle für diesen Harness unvollständig — vor weiterer Analyse um eine Zeile pro wiederkehrendem other-Muster erweitern.
Schritt 8: Das Erfassungs-Manifest persistieren
Ein Erfassungslauf ist nur dann reproduzierbar, wenn die Eingaben neben den Ausgaben festgehalten sind. Ein Manifest schreiben:
cat > capture-manifest.json <<EOF { "captured_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)", "harness_version": "$(harness-cli --version 2>/dev/null || echo unknown)", "channel": "verbose-fetch", "question": "Does endpoint X fire on event Y?", "targets": ["endpoint-X", "event-Y"], "files": ["session.jsonl", "session.classified.jsonl"], "redaction_check": "passed" } EOF
Das Manifest ist das, was die Erfassung gegen künftige Versionen diff-fähig macht.
Expected:
capture-manifest.json existiert, parst mit jq und listet jede Artefaktdatei im Erfassungsverzeichnis auf.
On failure: hat der Harness kein Versions-Flag, stattdessen den
sha256sum des Binaries festhalten. Ein nicht identifiziertes Binary erzeugt nicht vergleichbare Erfassungen.
Validierung
- Observability-Tabelle vor jedem Erfassungsbefehl erstellt
- Erfassungsverzeichnis ist git-ignoriert und zeitgestempelt
- Jede
-Datei parst zeilenweise mit*.jsonljq -e . - Redaktions-Leckprüfung liefert keine Treffer für bekannte Zugangsdaten-Präfixe
- Jedes erfasste Ereignis hat ein
-Feld mit bekanntem Wertclass -
hält Harness-Version (oder sha256), Kanal und Fragestellung festcapture-manifest.json - Das Erfassungsverzeichnis enthält nur die in Schritt 1 aufgezählten Ziele (kein beiläufiger Verkehr anderer Apps)
Häufige Fallstricke
- Erst erfassen, später fragen: ein Log, das niemand liest, ist verschwendeter Speicherplatz und verschwendete Aufmerksamkeit. Erst die Observability-Tabelle bauen; nur das erfassen, was eine konkrete Frage beantwortet.
- Zuerst zu
greifen: ein ausgehender Proxy ist der invasivste Kanal. Er erfordert Zertifikatsvertrauen, bricht bei Certificate Pinning und verschmutzt die Umgebung des Harness. Nur einsetzen, wenn On-Disk-, Transkript-, Verbose-Fetch- und Hook-Kanäle allesamt blockiert sind.mitmproxy - Erfassen in der primären Arbeitssitzung: Verbose-Fetch-stderr blutet ins TUI-Rendering und kann Fragmente anderer Arbeit in die Erfassung lecken. Stets eine verwerfliche Shell verwenden.
- „Wir redigieren später": jedes „erst erfasste, dann redigierte" Artefakt hat mindestens einmal Zugangsdaten geleckt. Zum Erfassungszeitpunkt redigieren — oder gar nicht erfassen.
- 4xx pauschal als Fehler behandeln: ein 401 auf einem Token-Refresh-Kanal ist ein Handshake-Schritt, kein Fehler. Antwortkategorien pro Kanalkontext klassifizieren (Schritt 7), bevor Schlüsse gezogen werden.
- Langlaufende Erfassung für Einzelereignis-Ziele: ein sitzungslanger Prozess zur Erfassung dreier diskreter Ereignisse koppelt den Tokenzustand über die Erfassungen hinweg und lässt ein schlechtes Ereignis das nächste vergiften. Für Ereignisse hook-getriebene Subprozesse; Sitzungserfassung für Sequenzen reservieren.
- Kein Manifest: eine JSONL-Datei ohne
ist nicht reproduzierbar — sie lässt sich nicht gegen das Binary des nächsten Monats diffen, wenn unbekannt ist, welche Version sie erzeugt hat.capture-manifest.json - Datenverkehr anderer Nutzer erfassen: außerhalb des Geltungsbereichs. Wire Capture gilt dem eigenen Konto auf der eigenen Maschine. Wird die Anfrage eines anderen Nutzers beiläufig aufgezeichnet, die Erfassung löschen und den Kanal enger fassen.
Verwandte Skills
— Phase 1 der übergeordneten Methodik; erzeugt die Versions-Baseline, auf die das Manifest dieses Skills verweist.monitor-binary-version-baselines
— Phasen 2–3; Wire Capture ist einer ihrer Evidenz-Zweige, und dieser Skill lehrt die Erfassungshälfte.probe-feature-flag-state
— teilt die Philosophie „JSONL über Wallclock"; hier auf ein einzelnes Binary angewandt statt auf ein Service-Mesh.instrument-distributed-tracing
— Phase 5; dieser Skill deckt nur die Erfassungszeit-Redaktion für den internen Gebrauch ab, nicht die Publikationsschwelle, die vor dem Verlassen eines privaten Arbeitsbereichs nötig ist.redact-for-public-disclosure