Skip to content

feat: respect XDG_DATA_HOME and CLAUDE_CONFIG_DIR for path resolution - #217

Open
troian wants to merge 1 commit into
griffinmartin:mainfrom
troian:feat/xdg-data-home-support
Open

feat: respect XDG_DATA_HOME and CLAUDE_CONFIG_DIR for path resolution#217
troian wants to merge 1 commit into
griffinmartin:mainfrom
troian:feat/xdg-data-home-support

Conversation

@troian

@troian troian commented May 1, 2026

Copy link
Copy Markdown

The plugin hardcoded ~/.local/share/opencode/ and ~/.claude/ for all file paths, ignoring XDG_DATA_HOME and CLAUDE_CONFIG_DIR. This prevented running multiple OpenCode instances in parallel with different Claude accounts, since all instances shared the same claude-account-source.txt. Changes:

  • credentials.ts: getAccountStateFile() and getAuthJsonPaths() use $XDG_DATA_HOME with fallback to ~/.local/share
  • keychain.ts: readCredentialsFile() and writeBackCredentials() use $CLAUDE_CONFIG_DIR with fallback to ~/.claude
  • logger.ts: getDefaultLogPath() uses $XDG_DATA_HOME with fallback to ~/.local/share
  • Tests added for all new paths; existing tests updated to isolate env vars that now affect path resolution
  • README updated with env var docs and parallel instance usage

When unset, behavior is unchanged (same defaults as before).

Summary

Related issue

Testing

Checklist

  • PR title follows Conventional Commits (feat:, fix:, docs:, chore:, etc.)
  • make all passes locally (runs lint, build, and test)
  • Tests added or updated where applicable
  • README or docs updated where applicable

@troian

troian commented May 4, 2026

Copy link
Copy Markdown
Author

hey @griffinmartin any chance you can take a look

@griffinmartin

Copy link
Copy Markdown
Owner

@troian Sorry I've been pretty busy so haven't been testing all the open PRs as much as I have in the past. I'll get to it this week.

@markthepixel

Copy link
Copy Markdown

I have a similar issue. Running three Claude Team accounts across different project dirs via CLAUDE_CONFIG_DIR + direnv, and the account selection bleeds across all of them because claude-account-source.txt is always written to the hardcoded path.

Ended up pre-writing it from a shell wrapper before each opencode launch as a workaround, but that breaks every update.

@troian

troian commented May 22, 2026

Copy link
Copy Markdown
Author

@markthepixel do you mind trying this PR?
i have running locally since push and it's being working well.
however, it always good for somebody to give it a try

@markthepixel

Copy link
Copy Markdown

I made a chance to keep the XDG_DATA_HOME and CLAUDE_CONFIG_DIR behavior as-is, but adds OPENCODE_ACCOUNT_SOURCE_FILE as an explicit override for just the persisted account selection file.

That covers the case where someone wants one shared OpenCode db and session history, but still wants Claude account selection pinned per workspace, which is my issue

Comment thread src/credentials.ts
@troian
troian force-pushed the feat/xdg-data-home-support branch from 5c134cf to bed47d0 Compare May 28, 2026 01:55
@troian

troian commented Jun 1, 2026

Copy link
Copy Markdown
Author

@griffinmartin bump for review

@troian
troian force-pushed the feat/xdg-data-home-support branch 2 times, most recently from a96ddad to 5e10fea Compare July 17, 2026 19:40
@griffinmartin

Copy link
Copy Markdown
Owner

@greptileai

@greptile-apps

greptile-apps Bot commented Jul 25, 2026

Copy link
Copy Markdown

Greptile Summary

This PR introduces a new src/paths.ts module that centralises XDG Base Directory resolution, then threads it through credentials.ts, logger.ts, and refresh-lock.ts so every plugin-managed file (account-source marker, auth.json, debug log, and refresh lock files) respects $XDG_DATA_HOME. When unset, behaviour is identical to the previous hardcoded ~/.local/share defaults.

  • src/paths.ts: Two helpers — getDataHome() (reads XDG_DATA_HOME at call time, treating empty strings as unset per spec) and getOpencodeDataDir() (appends opencode). Resolving at call time means tests can redirect via env vars without module reloads.
  • Path wiring: credentials.ts, logger.ts, and refresh-lock.ts all replace their individual join(homedir(), ".local", "share", "opencode", …) expressions with getOpencodeDataDir(). A new OPENCODE_ACCOUNT_SOURCE_FILE escape hatch is added for pinning the account-source file to an absolute path.
  • Tests & docs: Each changed code path gains an XDG-specific test that sets and then restores XDG_DATA_HOME. Existing tests delete any ambient XDG_DATA_HOME at suite start to prevent cross-contamination. The README gains a "Parallel instances" section and updates the env-var reference table.

Confidence Score: 5/5

  • This PR is safe to merge. The change is additive: when XDG_DATA_HOME is unset, every resolved path is identical to what was hardcoded before.
  • All four files that resolve data paths are updated consistently through the single getOpencodeDataDir() helper. The helper reads at call time, so tests can redirect paths via env vars without module reloads. Each new code path has a corresponding test that also correctly cleans up env vars. Default behaviour is fully preserved when XDG_DATA_HOME is unset.
  • No files require special attention.

Important Files Changed

Filename Overview
src/paths.ts New module centralising XDG path resolution; correctly reads XDG_DATA_HOME at call time (not module-load time), handles empty-string per spec, and appends opencode for the data dir. Clean and well-commented.
src/credentials.ts Delegates getAccountStateFile() and getAuthJsonPaths() to getOpencodeDataDir() from paths.ts. Adds OPENCODE_ACCOUNT_SOURCE_FILE escape hatch. Logic is unchanged; Windows dual-write behaviour (XDG + LOCALAPPDATA) was flagged in a prior review.
src/refresh-lock.ts Replaces the hardcoded default lock dir with getOpencodeDataDir(). Env-var override (OPENCODE_CLAUDE_AUTH_REFRESH_LOCK_DIR) correctly retains higher priority. Per-instance XDG dirs mean lock files are also isolated per instance — acceptable for the documented "different accounts" use case.
src/credentials.test.ts Adds XDG_DATA_HOME tests for saveAccountSource, loadPersistedAccountSource, and syncAuthJson. Correctly deletes ambient XDG_DATA_HOME at suite start and copies paths.ts into each sandboxed temp module. Good coverage of the new code paths.
src/refresh-lock.test.ts New test suite exercises defaultLockDir() XDG resolution and verifies OPENCODE_CLAUDE_AUTH_REFRESH_LOCK_DIR keeps precedence over XDG_DATA_HOME. Env isolation via beforeEach/afterEach is correct.
README.md Adds a "Parallel instances" section with a concrete bash example and updates the env-var reference table with XDG_DATA_HOME and OPENCODE_ACCOUNT_SOURCE_FILE. Clear and accurate documentation of the new feature.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[OpenCode starts] --> B{XDG_DATA_HOME set?}
    B -- Yes --> C["getDataHome() → $XDG_DATA_HOME"]
    B -- No --> D["getDataHome() → ~/.local/share"]
    C --> E["getOpencodeDataDir() → {dataHome}/opencode"]
    D --> E

    E --> F1["claude-account-source.txt\n(credentials.ts)"]
    E --> F2["auth.json\n(credentials.ts)"]
    E --> F3["claude-auth-debug.log\n(logger.ts)"]
    E --> F4["claude-auth-refresh-*.lock\n(refresh-lock.ts)"]

    F2 --> G{platform win32?}
    G -- Yes --> H["Also write to\n%LOCALAPPDATA%/opencode/auth.json"]
    G -- No --> I[XDG path only]

    J{OPENCODE_ACCOUNT_SOURCE_FILE set?} -- Yes --> K[Use explicit path]
    J -- No --> F1

    L{OPENCODE_CLAUDE_AUTH_REFRESH_LOCK_DIR set?} -- Yes --> M[Use explicit dir]
    L -- No --> F4

    style H fill:#ffe0b2,stroke:#e65100
Loading

Reviews (2): Last reviewed commit: "feat: respect XDG_DATA_HOME and CLAUDE_C..." | Re-trigger Greptile

Comment thread src/credentials.test.ts Outdated
The plugin hardcoded ~/.local/share/opencode/ and ~/.claude/ for all
file paths, ignoring XDG_DATA_HOME and CLAUDE_CONFIG_DIR. This prevented
running multiple OpenCode instances in parallel with different Claude
accounts, since all instances shared the same claude-account-source.txt.
Changes:
- credentials.ts: getAccountStateFile() and getAuthJsonPaths() use
  $XDG_DATA_HOME with fallback to ~/.local/share
- keychain.ts: readCredentialsFile() and writeBackCredentials() use
  $CLAUDE_CONFIG_DIR with fallback to ~/.claude
- logger.ts: getDefaultLogPath() uses $XDG_DATA_HOME with fallback
  to ~/.local/share
- Tests added for all new paths; existing tests updated to isolate
  env vars that now affect path resolution
- README updated with env var docs and parallel instance usage

When unset, behavior is unchanged (same defaults as before).

Signed-off-by: Artur Troian <troian@users.noreply.github.com>
@troian
troian force-pushed the feat/xdg-data-home-support branch from 5e10fea to af0a8ad Compare August 6, 2026 15:33
@troian

troian commented Aug 6, 2026

Copy link
Copy Markdown
Author

@griffinmartin bump for review again

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants