27 KiB
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:
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 "<neue-msg>" --resume <session-id> --output-format json
lädt die existierende Session und hängt <neue-msg> 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 <msg> --resume <id> --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 <uuid> 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):
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:
{
"$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.<EventName>[].matcher + hooks.<EventName>[].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 <mcp-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):
systemmitsubtype(z. B.init,api_retry) — Metadaten, Retry-Eventsassistant— Tool-Use-Blöcke und Text-Blöcke vom Modell (Native-API-Format)user— Tool-Resultsstream_event— Partial-Streaming-Deltas (nur wenn--include-partial-messagesgesetzt 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-eventsgesetzt)
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):
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:
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:
# 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:
- Primär:
-p "<discord message>"direkt — Discord-Messages sind auf 2000 Zeichen gecappt, ARG_MAX ist kein Thema. - 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.spawnmitargv-Array (keinshell: 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:
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:
- Discord-Attachment herunterladen in
workspaces/<agent>/.inbox/<ts>-<name> - Prompt bauen:
"Der User hat ein Bild geschickt: @./.inbox/<ts>-<name>.png. Analysiere es." - 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:
# 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.mdandCLAUDE.local.mdfiles. [...] 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:
-
--bare: SkipptCLAUDE.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-pin 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-fileoder explizites Laden der Agent-CLAUDE.md selbst beisteuern. -
claudeMdExcludesim Agent-settings.local.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.
-
Workspaces außerhalb des DisClaw-Repos legen: Statt
disclaw/workspaces/z. B.~/disclaw-workspaces/<agent>/. Dann gibt es oberhalb keine Projekt-CLAUDE.md (nur User-Scope~/.claude/CLAUDE.mdund 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:
- Workspaces außerhalb des DisClaw-Repos als Default speichern
(
~/.disclaw/workspaces/<agent>/oder konfigurierbar viadisclaw.yaml workspace_root). Das eliminiert das Parent-CLAUDE.md-Problem strukturell.disclaw/workspaces/bleibt nur für Entwicklung/Tests. - Zusätzlich
--bareverwenden für alle Headless-Calls und Agent-Identity explizit via--append-system-prompt-file <workspace>/CLAUDE.mdanhängen. Das ist reproduzierbar, schnell (weniger Startup-Cost), und zukunftssicher (wird ohnehin Default für-p). Die Agent-CLAUDE.mdwird dann im-p --bare-Modus nicht via Memory-Mechanismus geladen, sondern direkt als System-Prompt-Append eingespeist. - Für Agenten, die trotzdem im DisClaw-Repo unter
workspaces/liegen müssen (z. B. Git-Tracking), zusätzlichclaudeMdExcludesimsettings.jsondes Agents setzen.
Der bisherige Plan, workspaces/<agent>/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.mdexistiert (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:
- Wenn man
spawn("claude", args)ruft, scannt Node die PATH-Einträge nach einer exakten Datei namensclaude. Da nurclaude.cmdexistiert (keine Datei ohne Extension), schlägt das fehl. Deshalb muss man explizitspawn("claude.cmd", args)oder einen absoluten Pfad übergeben. .cmd- und.bat-Dateien sind Batch-Skripte, die normalerweise nur voncmd.exeausgeführt werden können. Node.js hat dafür seit Jahren einen Work-around, aber seit Node 20.12 (CVE-2024-27980) istspawn("foo.cmd")ohneshell: trueauf 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:
- Beim Startup auflösen: Einmalig
where claude(Windows) bzw.which claude(Unix) ausführen und den absoluten Pfad zur.cmd/.shauflösen und in Config cachen. Der User kann das auch explizit überCLAUDE_PATHin.envüberschreiben. - Für
.cmdauf Windows: Statt direkt zu spawnen, suchen wir das.js-Target hinter dem.cmd(npm generiertclaude.cmdals Wrapper, dernode <path-to-cli.js>aufruft) und spawnennode cli.js args...direkt. Das umgeht sowohl CVE-2024-27980 als auch ARG_MAX-Interpretation durchcmd.exe. - 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:
# 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:
- Bei Bot-Start:
CLAUDE_PATHaus.envlesen; falls leer,where claude(Windows) /which claude(Unix) automatisch ausführen und Pfad in-memory cachen (nicht persistieren). - Auf Windows: parse den
.cmd-Wrapper einmal, extrahiere dennode <cli.js>-Call, und spawne künftig direktspawn("node", ["<cli.js>", ...args], { windowsHide: true, shell: false }). Oder verwendecross-spawnfür denselben Effekt ohne Eigenbau. - stdout als UTF-8 dekodieren (
child.stdout.setEncoding("utf8")), auf stderr separat loggen. - README/
/setup-Command: klare Fehlermeldung, wennwhere claudenichts findet, mit Hinweis aufCLAUDE_PATHim.env.
10. Session-Datei-Lebenszyklus
Antwort: Session-JSONL-Dateien liegen unter
~/.claude/projects/<project-slug>/<session-uuid>.jsonl
<project-slug> 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/<uuid>.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:
cleanupPeriodDaysSetting (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:
/resumezeigt einen Picker aller Sessions für den aktuellen cwd. Aber das ist interaktiv-only und nicht skriptbar. --resume <id-or-name>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/<slug>/ prüfen und löschen. Das ist
sauber genug, weil das Format dokumentiert ist ("Each project gets its own
memory directory at ~/.claude/projects/<project>/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:
# 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:
- In
src/agent/identity.tseine FunktioncwdToProjectSlug(absCwd: string): stringbauen, die die Transformation nachbildet. Test auf beiden Plattformen. /delete-agentlöscht: (a) Workspace-Dir, (b) DB-Row, (c)~/.claude/projects/<slug>/(mit optionalem Opt-out-Flag, falls User die Auto-Memory behalten will).- Session-Enumeration für ein Feature wie
/agent-historyparsen wir die JSONL-Dateien direkt (sind Newline-getrenntes JSON). - Setzen
cleanupPeriodDaysim Agent-settings.jsonz. 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/<agent>/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 indisclaw.yaml. In Dev-Modus./workspaces/erlaubt, aber mit Warnung. - Phase 2 (Session-Resume): CLI-Calls müssen
--bareverwenden. Agent-Identity wird per--append-system-prompt-file <ws>/CLAUDE.mdangehängt. Das macht Agent-Identität explizit und unabhängig von Parent-CLAUDE.md-Leaks. - Phase 4 (Settings-Schema):
settings.jsonpro Agent schreiben mit optionalemclaudeMdExcludesfü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.tsinitial mitcross-spawnstatt nacktemchild_process.spawnimplementieren — das ist 1 Zeile Dependency und spart 50 Zeilen Windows-Workaround-Code. - Alternative:
where claudebeim Bot-Start einmal ausführen, den.cmd-Wrapper parsen, und direktnode <cli.js>spawnen. Mehr Code, aber keine extra Dependency. Entscheidung für den Entwickler — Empfehlung:cross-spawn. /setup-Skill: Fehlermeldung wennclaudenicht 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
<ws>/.inbox/, Prompt referenziert per@./.inbox/...,allowedToolsenthältRead. 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-agenträumt~/.claude/projects/<slug>/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.