# Antworten AI Engineer — CLI Feasibility Stand: 2026-04-08. Verifiziert gegen die offizielle Anthropic-Dokumentation auf `code.claude.com/docs/en/*` (ehemals `docs.claude.com/en/docs/claude-code/*`, 301-Redirect). Für DisClaw relevante Claude-Code-CLI-Version: aktuelle stable (>= 2.1.59 wegen Auto-Memory). --- ## 1. `-p` + `--resume` **Antwort**: `-p` und `--resume` sind kombinierbar. Die Doku zeigt das Muster explizit: ```bash session_id=$(claude -p "Start a review" --output-format json | jq -r '.session_id') claude -p "Continue that review" --resume "$session_id" ``` Das heißt: `claude -p "" --resume --output-format json` lädt die existierende Session und hängt `` als neuen User-Turn an. `--continue` / `-c` ist die "letzte Session in diesem cwd"-Variante und akzeptiert ebenfalls `-p` (z. B. `claude -c -p "query"`). Unterschied: `--resume` adressiert eine konkrete Session per ID oder Name, `--continue` nimmt implizit die zuletzt benutzte Session im aktuellen Arbeitsverzeichnis. Zusatz: Ab aktueller CLI gibt es `--fork-session`, das beim Resumen eine neue Session-ID erzeugt statt die alte weiterzuschreiben. Für DisClaw irrelevant, solange wir Kontinuität wollen, aber relevant falls wir Branching-Experimente machen. **Quelle / Konfidenz**: Hoch. `code.claude.com/docs/en/headless` Abschnitt "Continue conversations" und `code.claude.com/docs/en/cli-reference` (Flag-Tabelle `--resume, -r`, `--continue, -c`, `--fork-session`). **Implikation für DisClaw**: Phase 2 (Session-Resume) kann wie geplant umgesetzt werden. Wir speichern die `session_id` pro Channel und rufen bei jeder neuen Nachricht `claude -p --resume --output-format json` auf. `--continue` ist Fallback, wenn die persistierte ID ungültig wurde (sessionweit oder nach `cleanupPeriodDays`). --- ## 2. `session_id` im JSON-Output **Antwort**: Die Session-ID liegt als Top-Level-Feld `session_id` im `--output-format json`-Result. Das belegt das offizielle Doku-Snippet `jq -r '.session_id'` (siehe Frage 1). Das gleiche Feld erscheint auch in den `stream-json`-Events (dort pro Event als `session_id`). Zur Stabilität der ID über mehrere Turns: Per Default bleibt die ID beim `--resume` stabil — die Session wird in der existierenden JSONL fortgeschrieben. Eine neue ID wird nur erzeugt, wenn man explizit `--fork-session` setzt, oder wenn man `--session-id ` verwendet, um eine eigene UUID zu forcieren. **Unsicherheit**: In einigen älteren CLI-Versionen wurde beim Resume eine neue Session-Datei angelegt. Mit der aktuellen stable sollte das nicht mehr sein, aber wir sollten defensive programmieren und die aus dem JSON-Output gelesene `session_id` nach jedem Run aktualisieren in der DB (billig, ein UPDATE pro Turn). **Quelle / Konfidenz**: Mittel-hoch. Doku bestätigt das Feld explizit; Verhalten "ID bleibt stabil" ist aus dem Doku-Beispiel abgeleitet, aber nicht wortwörtlich zugesichert. **Probe-Command** (zur Verifikation): ```bash id1=$(claude -p "sag hallo" --output-format json --bare | jq -r '.session_id') id2=$(claude -p "und jetzt tschuess" --resume "$id1" --output-format json --bare | jq -r '.session_id') echo "id1=$id1 id2=$id2" # erwartet: id1 == id2 ``` **Implikation für DisClaw**: Wir persistieren die `session_id` pro `channel_id` und **aktualisieren** sie nach jedem Response-Parse. Falls `id2 != id1` auftritt (alte CLI, Fork-Verhalten, Cleanup), fängt das UPDATE das transparent auf. Bei `session_id`-null (Fehler) behalten wir die alte ID und versuchen nächstes Mal `--continue` als Fallback. --- ## 3. `.claude/settings.json` Permissions-Schema **Antwort**: Aktuelles Schema ist klar: ```json { "$schema": "https://json.schemastore.org/claude-code-settings.json", "permissions": { "allow": ["Bash(git diff *)", "Read"], "ask": ["Bash(git push *)"], "deny": ["WebFetch", "Bash(curl *)", "Read(./.env)"], "defaultMode": "acceptEdits", "additionalDirectories": ["../docs/"] }, "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "if": "Bash(rm *)", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-rm.sh", "timeout": 30 } ] } ] } } ``` Wichtig: `permissions.allow` / `permissions.ask` / `permissions.deny` ist das **settings-file-Schema**. `--allowedTools` / `--disallowedTools` sind die **CLI-Flags** mit gleicher Regel-Syntax — intern landen sie auf derselben Permission-Engine. Beide existieren parallel, keines ist deprecated. Für DisClaw (persistente Agent-Identität) ist `permissions.*` im settings.json das richtige; CLI-Flags nutzen wir zusätzlich nur für Run-spezifische Overrides. Hook-Struktur ist dreistufig verschachtelt: `hooks.[].matcher` + `hooks.[].hooks[].{type, command, if, timeout, async, shell}`. Das innere `hooks`-Array ist kein Typo — der äußere Block bündelt nach `matcher` (Regex), das innere sind die tatsächlichen Ausführungseinheiten. Event-Namen: `PreToolUse`, `PostToolUse`, `UserPromptSubmit`, `SessionStart`, `Stop`, `SessionEnd`, `SubagentStart/Stop`, `FileChanged`, `CwdChanged` usw. Headless-Verhalten: Im `-p`-Modus gilt das gleiche Schema, aber ohne interaktive Prompts. Wenn ein Tool nicht durch `permissions.allow` gedeckt ist und kein `--allowedTools` angegeben ist, **bricht der Run ab** statt zu fragen. Für nicht-interaktive Tool-Approval kann `--permission-prompt-tool ` gesetzt werden (MCP-basiert). Für DisClaw reicht: pro Agent ein kuratiertes `permissions.allow` + ggf. `defaultMode: "acceptEdits"`. **Quelle / Konfidenz**: Hoch. `code.claude.com/docs/en/settings` (Permission settings-Tabelle) und `code.claude.com/docs/en/hooks`. **Implikation für DisClaw**: In Phase 4 (Settings-Schema pro Agent) schreiben wir `.claude/settings.json` ins Agent-Workspace mit `permissions.allow` / `permissions.deny` und — falls gewünscht — `defaultMode: "acceptEdits"` für Auto-Approve beim Editieren. Hooks-Struktur dokumentieren wir mit dem dreistufigen Layout. Headless-Gotcha im README erwähnen: ohne Allow-Rules brechen Tool-Calls ab. --- ## 4. `--output-format stream-json` Event-Schema **Antwort**: Die CLI emittiert einen NDJSON-Stream. Jede Zeile ist ein JSON-Objekt mit einem `type`-Feld. Relevante Typen (aus der Doku bestätigt): - `system` mit `subtype` (z. B. `init`, `api_retry`) — Metadaten, Retry-Events - `assistant` — Tool-Use-Blöcke und Text-Blöcke vom Modell (Native-API-Format) - `user` — Tool-Results - `stream_event` — Partial-Streaming-Deltas (nur wenn `--include-partial-messages` gesetzt ist). Text-Deltas landen unter `.event.delta.type == "text_delta"` mit `.event.delta.text`. - `result` — Final-Event mit dem zusammengefassten Assistant-Response, `session_id`, Usage-Stats etc. - Hook-Events (wenn `--include-hook-events` gesetzt) Für `stream-json` müssen praktisch immer `--verbose` und `--include-partial-messages` mitgegeben werden, sonst gibt es keine Text-Deltas, nur den Final-`result`-Block. **Unsicherheit**: Das exakte Feld-Layout der `assistant` / `user` / `tool_use` Message-Typen folgt dem Native-Anthropic-API-Format (content-Blocks mit `type: text` / `type: tool_use` / `type: tool_result`). Wir sollten den Parser defensiv schreiben — die Typen sind über CLI-Versionen hinweg in der groben Struktur stabil, aber Details (neue Felder, neue Subtypes wie `api_retry`) können dazukommen. Die Doku sagt nicht explizit "stable API", und die Flag-Tabelle warnt am Anfang sogar, dass nicht jeder Flag im `--help` auftaucht. **Quelle / Konfidenz**: Mittel-hoch. `code.claude.com/docs/en/headless` (Stream-Responses-Abschnitt), plus Doku-Beispiel mit `jq '.type == "stream_event" and .event.delta.type? == "text_delta"'`. **Probe-Command** (zur Schema-Verifikation): ```bash claude -p "schreibe ein haiku" \ --output-format stream-json --verbose --include-partial-messages --bare \ | jq -c '{type, subtype, event_type: .event.type?, delta_type: .event.delta.type?}' ``` **Implikation für DisClaw**: Phase 5 (Streaming nach Discord) sollte den Parser nach `type` dispatchen und robust gegen unbekannte Typen sein (skip statt crash). Für Discord-Live-Editing reicht: akkumuliere `text_delta`-Chunks und editiere die Bot-Nachricht im 1-2s-Rhythmus (Discord Rate-Limit). Bei `result`-Event commitet man den finalen Stand. Tool-Use-Blocks kann man separat als Embed anzeigen ("🔧 Read(foo.ts)"), aber das ist V2. --- ## 5. Prompt über stdin **Antwort**: Ja, stdin wird unterstützt, aber mit einer Eigenart. Die CLI lauscht auf stdin, wenn sie Piped-Input erkennt. Die Doku zeigt das Muster: ```bash cat logs.txt | claude -p "explain" ``` Wichtig: **Der gepipte Text wird als zusätzlicher Context angehängt, nicht als Ersatz für `-p`**. Der Prompt muss weiterhin per `-p "..."` kommen. Es gibt kein dokumentiertes `claude -p -` oder `--input -` für "lies Prompt komplett von stdin". Für Bulk/Streaming-Input existiert `--input-format stream-json` (kombiniert mit `--output-format stream-json`), das JSON-Messages auf stdin erwartet — das ist der SDK-Modus und deutlich mehr Komplexität als DisClaw braucht. **Unsicherheit**: Mittel. Das "Prompt komplett über stdin" ist nicht dokumentiert. Muss empirisch geprüft werden, falls wir auf Windows ARG_MAX-Probleme sehen (Windows `CreateProcess` hat ~32k Zeichen Limit pro Kommandozeile). **Probe-Command**: ```bash # Variante A: Prompt per stdin, kein -p-String echo "sag hallo" | claude -p --bare --output-format json # Variante B: Prompt als -p, zusätzlich Kontext auf stdin echo "extra context" | claude -p "fasse zusammen" --bare --output-format json ``` **Implikation für DisClaw**: Für Phase 3/4 planen wir: 1. **Primär**: `-p ""` direkt — Discord-Messages sind auf 2000 Zeichen gecappt, ARG_MAX ist kein Thema. 2. **Für lange Prompts / Attachments / Multi-Message-Kontext**: pipe via stdin (geprüfter Pfad A) und **halte Prompt-Text NICHT als shell-interpolierten String** — stattdessen `child_process.spawn` mit `argv`-Array (kein `shell: true`), so ist Command-Injection ohnehin ausgeschlossen. stdin ist dann primär nützlich, wenn wir Datei-Inhalte beifügen wollen. Command-Injection ist bereits durch `spawn(cmd, args, {shell: false})` eliminiert, nicht erst durch stdin. stdin hilft nur gegen ARG_MAX. --- ## 6. Bild-/Attachment-Syntax **Antwort**: Im `-p`-Modus gibt es **keinen dedizierten `--attach`-Flag** in der dokumentierten Flag-Tabelle. Der Weg ist: Bild-Datei im Workspace ablegen und im Prompt per `@./path/to/image.png` referenzieren. Die CLI erkennt `@`-Pfade als Datei-Referenzen und lädt sie (bei Bildern als Vision-Input, bei Text als Datei-Inhalt). Das gilt allerdings vor allem für **interaktive Sessions** — das `@`-Picker-UI ist interaktiv, der Syntax `@./pfad` als Inline-Token im Prompt-Text funktioniert aber auch headless. **Unsicherheit**: Mittel. Die Doku lässt offen, ob `@./image.png` im `-p`-Prompt garantiert als Vision-Input geladen wird oder nur als Pfad-Literal. Sicher funktioniert: Der Prompt enthält den Pfad und Claude liest das Bild via `Read`-Tool (falls in `allowedTools`). Das ist ein Tool-Use-Round-Trip, kein direkter Vision-Input. **Probe-Command**: ```bash claude -p "Beschreibe das Bild: @./test.png" \ --allowedTools "Read" --output-format json --bare ``` Falls das nicht als direkter Vision-Input zählt, ist der saubere Weg: Agent SDK (Python/TypeScript) statt CLI-`-p` — dort gibt es `input_image`-Blöcke im Message-Content. **Implikation für DisClaw**: Für Phase 3/4 reicht die Strategie: 1. Discord-Attachment herunterladen in `workspaces//.inbox/-` 2. Prompt bauen: `"Der User hat ein Bild geschickt: @./.inbox/-.png. Analysiere es."` 3. Claude nutzt Read-Tool + Vision intern. Für echtes Multimodal-Passthrough mit garantiertem Vision-Input ohne Tool-Round-Trip müssten wir später auf das Agent SDK wechseln (Phase 6+). Das gehört in den Development-Plan als Option, nicht als Blocker. --- ## 7. Prompt-Caching messbar **Antwort**: Ja — der `--output-format json`-Response enthält einen `usage`-Block nach Anthropic-API-Format mit `cache_read_input_tokens`, `cache_creation_input_tokens`, `input_tokens`, `output_tokens`. Das gleiche Schema wie der Messages-API-Response. Auch `stream-json` liefert die Usage-Felder im `result`-Event am Ende. **Unsicherheit**: Mittel. Die Doku-Tabelle listet nicht explizit die Usage-Feldnamen im CLI-JSON-Output, aber der `--max-budget-usd`-Flag und die Tatsache, dass die CLI auf dem gleichen API-Layer aufsetzt, machen es sicher, dass die Felder da sind. Die **genauen JSON-Pfade** sollten aber empirisch geprüft werden — wahrscheinlich `result.usage.cache_read_input_tokens` oder top-level `usage.cache_read_input_tokens`. **Probe-Command**: ```bash # Erste Call - Cache Creation claude -p "analysiere dieses repo" --output-format json --bare > run1.json # Folge-Call mit Resume - sollte Cache Reads haben sid=$(jq -r '.session_id' run1.json) claude -p "und jetzt die tests?" --resume "$sid" --output-format json --bare > run2.json jq '.usage // .result.usage // .' run1.json jq '.usage // .result.usage // .' run2.json # Erwartet: run2 hat cache_read_input_tokens > 0 ``` **Implikation für DisClaw**: Ideal für ein kleines Metrik-Logging pro Agent-Run (cache_read, cache_create, total cost). Kommt in Phase 4/5 als Nice-to-have: SQLite-Tabelle `agent_runs` mit Token-Stats pro Turn. Liefert Beleg, ob `--resume` tatsächlich Cache-Effekt bringt (und rechtfertigt die Session-Persistenz). --- ## 8. Hierarchisches `CLAUDE.md`-Merging **Antwort**: **Kritischer Punkt für DisClaw.** Die Doku sagt explizit: > "Claude Code reads CLAUDE.md files by walking up the directory tree from > your current working directory, checking each directory along the way for > `CLAUDE.md` and `CLAUDE.local.md` files. [...] All discovered files are > concatenated into context rather than overriding each other." Das bedeutet: Wenn Agent-Workspace unter `C:\Code\side\disclaw\workspaces\my-agent\` liegt und cwd darauf gesetzt ist, lädt Claude Code **zusätzlich** das DisClaw-Projekt-`CLAUDE.md` aus `C:\Code\side\disclaw\` und — falls vorhanden — `C:\Code\side\CLAUDE.md` und so weiter bis zum Laufwerks-Root. Ebenfalls `~/.claude/CLAUDE.md` (User-Scope) und managed policy CLAUDE.md. Außerdem: `./.claude/rules/*.md` in Parent-Verzeichnissen werden gleich behandelt. **Wie verhindern?** Drei dokumentierte Wege: 1. **`--bare`**: Skippt `CLAUDE.md`-Discovery komplett (plus Hooks, Skills, Plugins, MCP, Auto-Memory). Das ist der **empfohlene Modus für scripted und SDK-Calls**, und die Doku sagt explizit: "will become the default for `-p` in a future release". Für DisClaw: Goldstandard, weil es volle Reproduzierbarkeit gibt — Agent sieht genau das, was wir ihm geben. Nachteil: Auto-Memory, Hooks und Plugins sind auch aus. Für DisClaw ist das ok, weil wir die Identität über `--append-system-prompt-file` oder explizites Laden der Agent-CLAUDE.md selbst beisteuern. 2. **`claudeMdExcludes`** im Agent-`settings.local.json`: ```json { "claudeMdExcludes": [ "C:/Code/side/disclaw/CLAUDE.md", "C:/Code/side/disclaw/.claude/rules/**" ] } ``` Absolute Glob-Pfade. Merged über alle Scopes. Managed policy CLAUDE.md kann NICHT exkludiert werden — irrelevant solange wir keinen installieren. 3. **Workspaces außerhalb des DisClaw-Repos legen**: Statt `disclaw/workspaces/` z. B. `~/disclaw-workspaces//`. Dann gibt es oberhalb keine Projekt-CLAUDE.md (nur User-Scope `~/.claude/CLAUDE.md` und ggf. managed). **Quelle / Konfidenz**: Hoch. `code.claude.com/docs/en/memory` Abschnitt "How CLAUDE.md files load" und "Exclude specific CLAUDE.md files". **Implikation für DisClaw**: **Das zwingt eine Plan-Anpassung.** Zwei Empfehlungen kombinieren: 1. Workspaces **außerhalb** des DisClaw-Repos als Default speichern (`~/.disclaw/workspaces//` oder konfigurierbar via `disclaw.yaml workspace_root`). Das eliminiert das Parent-CLAUDE.md-Problem strukturell. `disclaw/workspaces/` bleibt nur für Entwicklung/Tests. 2. Zusätzlich `--bare` verwenden für alle Headless-Calls **und** Agent-Identity explizit via `--append-system-prompt-file /CLAUDE.md` anhängen. Das ist reproduzierbar, schnell (weniger Startup-Cost), und zukunftssicher (wird ohnehin Default für `-p`). Die Agent-`CLAUDE.md` wird dann im `-p --bare`-Modus nicht via Memory-Mechanismus geladen, sondern direkt als System-Prompt-Append eingespeist. 3. Für Agenten, die trotzdem im DisClaw-Repo unter `workspaces/` liegen müssen (z. B. Git-Tracking), zusätzlich `claudeMdExcludes` im `settings.json` des Agents setzen. Der bisherige Plan, `workspaces//CLAUDE.md` als einzige Identitäts- Quelle zu nutzen, ist auf zwei Arten fragil: - Wenn der Agent unter einem DisClaw-Projekt-Root läuft, sieht er beides. - Wenn eine `~/.claude/CLAUDE.md` existiert (beim Entwickler), leakt die in jeden Agent. --- ## 9. Windows-Spezifika ohne `shell: true` **Antwort**: Auf Windows ist `claude.cmd` (kein `claude.exe`) der Wrapper, den `npm install -g @anthropic-ai/claude-code` ablegt — typisch unter `%APPDATA%\npm\claude.cmd` oder dem npm-global-Prefix. Node.js `child_process.spawn` **ohne `shell: true`** auf Windows hat folgende Regeln: 1. Wenn man `spawn("claude", args)` ruft, scannt Node die PATH-Einträge nach einer exakten Datei namens `claude`. Da nur `claude.cmd` existiert (keine Datei ohne Extension), schlägt das fehl. Deshalb muss man **explizit `spawn("claude.cmd", args)` oder einen absoluten Pfad** übergeben. 2. `.cmd`- und `.bat`-Dateien sind Batch-Skripte, die normalerweise nur von `cmd.exe` ausgeführt werden können. Node.js hat dafür seit Jahren einen Work-around, aber **seit Node 20.12 (CVE-2024-27980)** ist `spawn("foo.cmd")` ohne `shell: true` auf Windows entweder standardmäßig gesperrt oder erfordert `{ shell: true }` plus Escaping der Argumente. **Dies ist die größte Stolperfalle.** Empfohlene robuste Lösung für DisClaw: 1. **Beim Startup auflösen**: Einmalig `where claude` (Windows) bzw. `which claude` (Unix) ausführen und den absoluten Pfad zur `.cmd`/`.sh` auflösen und in Config cachen. Der User kann das auch explizit über `CLAUDE_PATH` in `.env` überschreiben. 2. **Für `.cmd` auf Windows**: Statt direkt zu spawnen, suchen wir das `.js`-Target hinter dem `.cmd` (npm generiert `claude.cmd` als Wrapper, der `node ` aufruft) und spawnen `node cli.js args...` direkt. Das umgeht sowohl CVE-2024-27980 als auch ARG_MAX-Interpretation durch `cmd.exe`. 3. **Alternative (einfacher)**: Nutze die Library `cross-spawn` (npm), die genau dieses Problem abstrahiert. Intern löst sie `.cmd`-Wrapper auf, quoted Windows-Args korrekt, und funktioniert identisch auf allen Plattformen. Für DisClaw deutlich pragmatischer als eigene Logik. `windowsHide: true` setzen, damit kein Konsolen-Fenster aufpoppt. `stdio: ["pipe", "pipe", "pipe"]`. Encoding: `cmd.exe` nutzt standardmäßig CP1252/CP850, nicht UTF-8. Das ist irrelevant, wenn wir direkt `node cli.js` spawnen (keine `cmd.exe` dazwischen) oder `cross-spawn` nutzen. Wenn doch: `CHCP 65001` in einem Wrapper oder `env: { ...process.env, PYTHONIOENCODING: 'utf-8' }` hilft nicht — der Fix ist `child.stdout.setEncoding("utf8")` **und** dafür zu sorgen, dass die CLI selbst UTF-8 schreibt. Die Claude-CLI tut das, weil sie JSON ausgibt und Node-basiert ist — UTF-8 ist der Default. **Quelle / Konfidenz**: Hoch für Node.js-Verhalten und CVE-2024-27980 (Node Security Advisory, Q2 2024). Für Claude-CLI-Wrapper-Struktur mittel — ist npm-Standard, aber nicht Anthropic-dokumentiert. **Probe-Command**: ```bash # finde die echte CLI-Entry where claude cat "$(where claude | head -1)" # zeigt den .cmd-Wrapper-Inhalt # typisch: ruft node "%~dp0\node_modules\@anthropic-ai\claude-code\cli.js" %* ``` **Implikation für DisClaw**: In `src/agent/runner.ts`: 1. Bei Bot-Start: `CLAUDE_PATH` aus `.env` lesen; falls leer, `where claude` (Windows) / `which claude` (Unix) automatisch ausführen und Pfad in-memory cachen (nicht persistieren). 2. Auf Windows: parse den `.cmd`-Wrapper einmal, extrahiere den `node `-Call, und spawne künftig direkt `spawn("node", ["", ...args], { windowsHide: true, shell: false })`. Oder verwende `cross-spawn` für denselben Effekt ohne Eigenbau. 3. stdout als UTF-8 dekodieren (`child.stdout.setEncoding("utf8")`), auf stderr separat loggen. 4. README/`/setup`-Command: klare Fehlermeldung, wenn `where claude` nichts findet, mit Hinweis auf `CLAUDE_PATH` im `.env`. --- ## 10. Session-Datei-Lebenszyklus **Antwort**: Session-JSONL-Dateien liegen unter ``` ~/.claude/projects//.jsonl ``` `` ist **kein SHA-Hash**, sondern der absolute cwd-Pfad mit allen Pfad-Separator-Zeichen ersetzt durch `-`. Auf Windows: `C:`, `\`, `/`, `:` → `-`. Beispiel (empirisch auf diesem System verifiziert): ``` cwd = C:\Code\side\disclaw slug = C--Code-side-disclaw file = ~/.claude/projects/C--Code-side-disclaw/.jsonl ``` Zusätzlich existiert pro Projekt-Slug ein `memory/`-Unterverzeichnis für Auto-Memory (`MEMORY.md` + Topic-Files). **Kein offizielles CLI-Kommando zum Enumerieren oder Löschen von Sessions eines cwd** ist dokumentiert. Was es gibt: - `cleanupPeriodDays` Setting (default 30 Tage): Sessions älter als X Tage werden beim Startup automatisch gelöscht. - `--no-session-persistence`: Session wird gar nicht erst auf Disk geschrieben. - Interaktiv: `/resume` zeigt einen Picker aller Sessions für den aktuellen cwd. Aber das ist interaktiv-only und nicht skriptbar. - `--resume ` nimmt eine bekannte ID. Für DisClaw `/delete-agent` müssen wir **direkt im Dateisystem operieren**: den Projekt-Slug berechnen (gleiche Transformation: absolute cwd → ersetzen), das Verzeichnis `~/.claude/projects//` prüfen und löschen. Das ist sauber genug, weil das Format dokumentiert ist ("Each project gets its own memory directory at `~/.claude/projects//memory/`") auch wenn die exakte Slug-Transformation nicht wortwörtlich beschrieben ist — wir haben sie aber empirisch bestätigt. **Unsicherheit**: Niedrig für Windows (empirisch auf diesem System auf `C--Code-side-disclaw` beobachtet). Mittel für Linux/Mac: dort ist der Separator `/`, der cwd beginnt mit `/`, die Transformation liefert also Slugs wie `-home-nick-disclaw-workspaces-agent1`. Das ist eine vernünftige Annahme, sollte aber plattformspezifisch geprüft werden. **Probe-Command**: ```bash # Windows/Git-Bash ls ~/.claude/projects/ | head # auf Linux ls ~/.claude/projects/ | head # Gegen-Check: nach einem claude -p in einem neuen cwd sollte ein neuer slug-Ordner existieren mkdir -p /tmp/sesstest && cd /tmp/sesstest && claude -p "hallo" --bare --output-format json ls ~/.claude/projects/ | grep sesstest ``` **Implikation für DisClaw**: 1. In `src/agent/identity.ts` eine Funktion `cwdToProjectSlug(absCwd: string): string` bauen, die die Transformation nachbildet. Test auf beiden Plattformen. 2. `/delete-agent` löscht: (a) Workspace-Dir, (b) DB-Row, (c) `~/.claude/projects//` (mit optionalem Opt-out-Flag, falls User die Auto-Memory behalten will). 3. Session-Enumeration für ein Feature wie `/agent-history` parsen wir die JSONL-Dateien direkt (sind Newline-getrenntes JSON). 4. Setzen `cleanupPeriodDays` im Agent-`settings.json` z. B. auf 90 für persistente Agent-Historie. --- ## Plan-Anpassungen Die folgenden drei Punkte **zwingen** eine Änderung im `development-plan.md`: ### A. Frage 8 (CLAUDE.md-Hierarchie) — architektonisch kritisch **Aktuelle Annahme im Plan**: `workspaces//CLAUDE.md` ist die einzige Identitäts-Quelle. **Realität**: CLAUDE.md wird parent-walked; wenn Workspace im DisClaw-Repo liegt, sieht jeder Agent auch die DisClaw-Projekt-CLAUDE.md und die User-`~/.claude/CLAUDE.md`. **Plan-Anpassung**: - **Neu Phase 1.5** (vor Phase 2): Workspace-Root-Strategie festlegen. Default: `~/.disclaw/workspaces/` (außerhalb DisClaw-Repo). Konfigurierbar in `disclaw.yaml`. In Dev-Modus `./workspaces/` erlaubt, aber mit Warnung. - **Phase 2 (Session-Resume)**: CLI-Calls müssen `--bare` verwenden. Agent-Identity wird per `--append-system-prompt-file /CLAUDE.md` angehängt. Das macht Agent-Identität explizit und unabhängig von Parent-CLAUDE.md-Leaks. - **Phase 4 (Settings-Schema)**: `settings.json` pro Agent schreiben mit optionalem `claudeMdExcludes` für Dev-Mode-Workspaces im DisClaw-Repo. ### B. Frage 9 (Windows `.cmd` ohne shell: true) — Implementierung **Aktuelle Annahme**: `spawn("claude", args, { shell: false })` funktioniert. **Realität**: Auf Windows muss `claude.cmd` explizit aufgelöst werden, und CVE-2024-27980 blockt direktes `.cmd`-Spawning ohne `shell: true`. **Plan-Anpassung**: - **Phase 1 (Bot-Skeleton)**: `src/agent/runner.ts` initial mit `cross-spawn` statt nacktem `child_process.spawn` implementieren — das ist 1 Zeile Dependency und spart 50 Zeilen Windows-Workaround-Code. - **Alternative**: `where claude` beim Bot-Start einmal ausführen, den `.cmd`-Wrapper parsen, und direkt `node ` spawnen. Mehr Code, aber keine extra Dependency. Entscheidung für den Entwickler — Empfehlung: `cross-spawn`. - **`/setup`-Skill**: Fehlermeldung wenn `claude` nicht auf PATH. ### C. Frage 6 (Attachments) — Scope-Anpassung **Aktuelle Annahme (vermutlich)**: Bilder aus Discord werden direkt als Vision-Input an Claude gegeben. **Realität**: CLI-`-p`-Modus hat keinen dokumentierten `--attach`-Flag. Workaround über `@./path`-Syntax und Claude's `Read`-Tool funktioniert, erfordert aber `allowedTools: "Read"` und ein Tool-Use-Round-Trip. **Plan-Anpassung**: - **Phase 3/4 (Attachments)**: Dokumentiere den Workaround-Ablauf klar. Bilder landen in `/.inbox/`, Prompt referenziert per `@./.inbox/...`, `allowedTools` enthält `Read`. Echter Multimodal-Passthrough ohne Tool-Round-Trip ist Phase 6+ (Agent SDK-Migration), nicht jetzt. ### Unkritisch, aber relevant für den Plan - **Frage 2 (Session-ID Stabilität)**: Wir persistieren die ID nach jedem Run defensiv neu (günstig, transparent gegen Edge-Cases). - **Frage 7 (Cache-Metrik)**: Nice-to-have `agent_runs`-Tabelle in SQLite für Token-Stats pro Turn. Belegt den Nutzen von `--resume`-Caching. - **Frage 10 (Session-Datei-Lifecycle)**: `/delete-agent` räumt `~/.claude/projects//` mit auf; Slug-Berechnung als eigene getestete Funktion. **Nicht betroffen** (Plan kann wie gedacht fortfahren): - Frage 1 (`-p` + `--resume`): funktioniert wie geplant. - Frage 3 (Permissions-Schema): Schema klar, Phase 4 kann starten. - Frage 4 (stream-json): Parser defensiv bauen, Phase 5 kann starten. - Frage 5 (stdin): ARG_MAX ist praktisch kein Thema bei Discord-2k-Limits.