Conversation
Claude Code honours CLAUDE_CONFIG_DIR to relocate ~/.claude, which is how people keep separate accounts on one machine. Agent Flow hardcoded ~/.claude everywhere, so anything under a relocated dir was invisible. Add a single resolver the rest of the codebase can share. Because Agent Flow is a viewer rather than a client, it parses the variable as a comma-separated list — the form ccusage accepts — so one board can show several accounts instead of forcing a choice between them. Passing a single directory still works and simply scopes it to that account. Entries are tilde-expanded, resolved to absolute paths and deduplicated so a doubled entry can't attach two watchers to one directory.
Transcripts drive nearly the whole visualization — tool calls, subagents, model detection — and both watchers only ever scanned ~/.claude/projects/. A session started under a relocated config dir wrote its transcript somewhere that was never read, so it never appeared. Scan and watch projects/ under every configured root. Session ids are uuids, so collecting across roots cannot collide: the same repo open under two accounts simply yields two sets of sessions. The containment cache in SessionWatcher is now keyed by full path rather than by encoded dir name, since the same name can exist under more than one root and each copy needs its own verdict. The single CLAUDE_DIR watcher becomes one watcher per root, closed together on dispose. DISCOVERY_DIR is deliberately left pinned to ~/.claude/agent-flow. The relay writes discovery files there and hook.js reads them back, but hook.js runs as a child of Claude Code and inherits CLAUDE_CONFIG_DIR — deriving that path from the variable would send a hook from a non-default config dir looking somewhere the relay never wrote to, silently dropping its events. Both sides must agree on one env-independent location.
Hooks were only ever written to ~/.claude/settings.json. A session started under a relocated config dir reads its own settings.json, finds no Agent Flow hooks, and emits no live events — no SessionStart, no permission prompts, no Stop. Write the hook entries to settings.json under every configured root. The hook command still points at the single pinned ~/.claude/agent-flow/ hook.js, so one installed script serves every account. The already-configured checks now require *all* roots rather than any one. With `some`, a first run against ~/.claude made every later run skip setup entirely, so a config dir added afterwards would never be configured. readGlobalSettings reads the first root that exists — per-account settings can't be meaningfully merged, and that entry is ~/.claude whenever CLAUDE_CONFIG_DIR is unset, so existing behaviour is unchanged.
Uninstall cleaned ~/.claude/settings.json only, then deleted the whole ~/.claude/agent-flow/ directory. Any other config dir was left holding a hook entry pointing at the hook.js that had just been removed.
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #68.
What
Agent Flow now honours
CLAUDE_CONFIG_DIR, so sessions from a relocated Claude Code config directory are visible. Because Agent Flow is a viewer rather than a client, the variable is read as a comma-separated list — one board can show several accounts at once:Unset, behaviour is unchanged:
~/.claudealone.Why
CLAUDE_CONFIG_DIRwas read nowhere in the repo — every Claude path was a hardcodedos.homedir()/.claude. On my own machine that meant 43 of 58 transcripts were dark to the visualizer:Three independent subsystems were affected:
scripts/relay.tsandextension/src/session-watcher.tsboth scanned only~/.claude/projects. This is the big one; transcripts drive nearly the whole visualization (tool calls, subagents, model detection).scripts/setup.jsandextension/src/hooks-config.tswrote only to~/.claude/settings.json, so a session under another config dir emitted no live events at all.hook.jsit then deleted.How
A shared resolver (
extension/src/claude-home.ts) parses the variable once; the watchers and hook installers iterate over every root it returns.Two decisions worth reviewing:
The discovery directory stays pinned to
~/.claude/agent-flow/. This is the subtle part. It is a rendezvous point: the relay writes{hash}-{pid}.jsonthere andhook.jsreads it to find which relay to POST to. Buthook.jsruns as a child of Claude Code and inheritsCLAUDE_CONFIG_DIR, so an env-derived path would send a personal-account hook looking in~/.claude-personal/agent-flow/while the relay wrote to~/.claude/agent-flow/— no match, no events, and no error. It is Agent Flow's own directory rather than Claude's, so both sides must agree on one env-independent location. Keeping it fixed also means a single installedhook.jsserves every account.The "already configured" checks now require all roots, not any one. With
some, a first run against~/.claudemade every later run skip setup entirely, so a config dir added afterwards would never get configured.readGlobalSettings(used byisDisable1MContext) reads the first root that exists — per-account settings can't be meaningfully merged, and that entry is~/.claudewhenever the variable is unset, so existing behaviour is preserved.Testing
extension/test/claude-home.test.tsadds 11 unit tests for the resolver: default fallback, empty/whitespace values, single dir, comma lists with order preserved, tilde expansion, dedup, and relative-path resolution.Verified end-to-end against the built
app/dist/app.jswith transcripts planted under two temp config roots. The initialsession-listSSE snapshot the UI receives contained both sessions:scripts/setup.jswas exercised against temp config dirs to confirm it writes hooks to each one, preserves unrelated existing hooks and other settings keys, stays idempotent across repeated runs (no duplicate entries), and configures a newly added dir rather than skipping it.Full CI suite green locally: root tests 32/32, extension tests 39/39, extension typecheck, extension test typecheck, web typecheck.
Notes
The VS Code extension inherits VS Code's environment, which usually won't carry
CLAUDE_CONFIG_DIR. The plumbing is in place and honoured when it is set; exposing anagentFlow.claudeConfigDirssetting for that case would be a natural follow-up, left out here to keep this focused.