Skip to content

Commit 9c931d7

Browse files
committed
bugfix: remove CLAUDE_SESSION_ID from env file to prevent corruption
1 parent aa9462e commit 9c931d7

3 files changed

Lines changed: 19 additions & 17 deletions

File tree

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# State
22

3-
- **Status:** open
4-
- **Progress:** 0%
3+
- **Status:** closed
4+
- **Resolution:** implemented
5+
- **Progress:** 100%
56
- **Dependencies:** []
67
- **Blocks:** []
8+
- **Target Branch:** v2.1

client/src/main/java/io/github/cowwoc/cat/hooks/session/InjectEnv.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@
2626
/**
2727
* Persists Claude environment variables into CLAUDE_ENV_FILE for Bash tool invocations.
2828
* <p>
29-
* Appends {@code CLAUDE_PROJECT_DIR}, {@code CLAUDE_PLUGIN_ROOT}, and
30-
* {@code CLAUDE_SESSION_ID} to the env file so they are available in all subsequent
31-
* Bash tool calls.
29+
* Appends {@code CLAUDE_PROJECT_DIR} and {@code CLAUDE_PLUGIN_ROOT} to the env file so they are available in all
30+
* subsequent Bash tool calls. {@code CLAUDE_SESSION_ID} is injected natively by Claude Code (v2.1.77+) and must
31+
* not be written here — writing it would corrupt sibling session env files when multiple sessions run concurrently.
3232
* <p>
3333
* Only writes for new sessions (source="startup"). On resumed (source="resume") or
3434
* compacted (source="compact") sessions, the env file already has the correct content
@@ -95,10 +95,8 @@ public Result handle(HookInput input)
9595
String pluginRoot = scope.getClaudePluginRoot().toString();
9696
validateEnvValue(projectPath, "CLAUDE_PROJECT_DIR");
9797
validateEnvValue(pluginRoot, "CLAUDE_PLUGIN_ROOT");
98-
validateEnvValue(sessionId, "CLAUDE_SESSION_ID");
9998
String content = "export CLAUDE_PROJECT_DIR=\"" + projectPath + "\"\n" +
100-
"export CLAUDE_PLUGIN_ROOT=\"" + pluginRoot + "\"\n" +
101-
"export CLAUDE_SESSION_ID=\"" + sessionId + "\"\n";
99+
"export CLAUDE_PLUGIN_ROOT=\"" + pluginRoot + "\"\n";
102100

103101
try
104102
{
@@ -214,7 +212,7 @@ private String writeToResumedSessionDir(Path sessionEnvBase, Path envPath, Strin
214212
* <p>
215213
* After {@code /clear}, Claude Code's session env loader may cache files from an old session directory and not
216214
* re-read from the new session directory. Writing to all sibling directories ensures that whichever directory the
217-
* cache reads from, it gets the current {@code CLAUDE_SESSION_ID}.
215+
* cache reads from, it gets the current {@code CLAUDE_PROJECT_DIR} and {@code CLAUDE_PLUGIN_ROOT}.
218216
*
219217
* @param sessionEnvBase the parent directory containing all session-env subdirectories
220218
* @param envPath the CLAUDE_ENV_FILE path (used to identify the already-written directory)

client/src/test/java/io/github/cowwoc/cat/hooks/test/SessionStartHookTest.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,8 @@ public void injectEnvWritesToMultipleSessionDirs() throws IOException
211211
Path siblingEnvFile = siblingDir.resolve("sessionstart-hook-1.sh");
212212
requireThat(Files.exists(siblingEnvFile), "siblingEnvFileExists").isTrue();
213213
String siblingContent = Files.readString(siblingEnvFile);
214-
requireThat(siblingContent, "siblingContent").contains("CLAUDE_SESSION_ID=\"" + sessionId + "\"");
214+
requireThat(siblingContent, "siblingContent").doesNotContain("CLAUDE_SESSION_ID=");
215+
requireThat(siblingContent, "siblingContent").contains("CLAUDE_PROJECT_DIR=");
215216
}
216217
finally
217218
{
@@ -300,17 +301,18 @@ public void injectEnvSkipsAlreadyWrittenDir() throws IOException
300301
// File should exist but should not be double-written (appended twice)
301302
requireThat(Files.exists(envFile), "envFileExists").isTrue();
302303
String content = Files.readString(envFile);
303-
// Count occurrences of CLAUDE_SESSION_ID - should appear exactly once
304+
requireThat(content, "content").doesNotContain("CLAUDE_SESSION_ID=");
305+
// CLAUDE_PROJECT_DIR should appear exactly once (not duplicated by double-write)
304306
int count = 0;
305-
int idx = 0;
306-
idx = content.indexOf("CLAUDE_SESSION_ID", idx);
307-
while (idx != -1)
307+
int index = 0;
308+
index = content.indexOf("CLAUDE_PROJECT_DIR", index);
309+
while (index != -1)
308310
{
309311
++count;
310-
++idx;
311-
idx = content.indexOf("CLAUDE_SESSION_ID", idx);
312+
++index;
313+
index = content.indexOf("CLAUDE_PROJECT_DIR", index);
312314
}
313-
requireThat(count, "sessionIdOccurrences").isEqualTo(1);
315+
requireThat(count, "projectDirOccurrences").isEqualTo(1);
314316
}
315317
finally
316318
{

0 commit comments

Comments
 (0)