Windows Client Data Paths (research for the Windows-support pass)
September 5, 2026 · View on GitHub
Status: research backing the Windows-support branch. The resulting code keeps the portable dotfile paths for
clients that use them on Windows and implements the one verified Windows-native branch: Hermes defaults to
%LOCALAPPDATA%\hermes. This doc records, with citations, where each supported client stores its session/usage
data on native Windows (not WSL), so future clientpaths.py changes can stay anchored to verified facts.
Last researched: 2026-07-01. Findings come from each tool's primary source (GitHub source code, official docs, or — for Amp — strings pulled from the shipped Windows binary). Every non-obvious claim is cited below.
Method note on os.homedir() / Path.home(): For Node.js tools, os.homedir() returns %USERPROFILE%
(e.g. C:\Users\<user>) on native Windows. For Python tools, pathlib.Path.home() resolves the same via
USERPROFILE. So any tool that simply joins the home dir with a .<name> dotfile is automatically "portable" —
its Windows path is just %USERPROFILE%\.<name>\... with no code branch needed. The interesting cases below are
the ones that do NOT do this (Hermes) or that use a Linux-only convention on Windows anyway (OpenCode).
Summary table
| Client | POSIX path (tokdash today) | Windows path | Confidence | Source URL(s) |
|---|---|---|---|---|
| OpenCode | ~/.local/share/opencode/storage/message and ~/.local/share/opencode/opencode.db | %USERPROFILE%\.local\share\opencode\storage\message and %USERPROFILE%\.local\share\opencode\opencode.db (Linux-style .local\share layout is used on Windows too — NO %APPDATA%/%LOCALAPPDATA% branch). Honors XDG_DATA_HOME even on Windows. | Verified | global.ts · database.ts · xdg-basedir index.js · issue #8235 |
| GitHub Copilot CLI | ~/.copilot/otel, ~/.copilot/session-state/*/events.jsonl | %USERPROFILE%\.copilot\otel\*.jsonl, %USERPROFILE%\.copilot\session-state\*\events.jsonl (portable dotfile). COPILOT_HOME relocates whole tree; COPILOT_OTEL_FILE_EXPORTER_PATH honored. Separate cache dir is %LOCALAPPDATA%\copilot (not session data). | Verified (dir); events.jsonl filename detail Uncertain | cli-config-dir-reference · configure-copilot-cli · install-copilot-cli |
| Gemini CLI | ~/.gemini/tmp/*/chats/session-*.json(l) | %USERPROFILE%\.gemini\tmp\*\chats\session-*.json(l) (portable dotfile via Node os.homedir(), no XDG redirect). | Verified | storage.ts · configuration docs · issue #23622 |
| Antigravity CLI | ~/.gemini/antigravity-{cli,acp,ide}/conversations/*.db (env ANTIGRAVITY_HOME, comma-separated, added to the defaults) | %USERPROFILE%\.gemini\antigravity-{cli,acp,ide}\conversations\*.db (same portable .gemini root; SQLite DBs are WAL-mode, and legacy *.pb files and the ACP kernel's *.meta sidecars are ignored). | Per home: -cli verified on POSIX (schema pinned against a real install); -acp reported, the layout quoted from the official agy_acp_server kernel's own help text; -ide unverified — asserted in passing in #72 with no citation and not seen locally. Windows paths inferred from the shared .gemini root throughout. | Local schema verification: docs/local/20260702_antigravity_usage/antigravity_gen_metadata_schema.md · issue #72 · ACP registry entry, Google Antigravity |
| Codex | ~/.codex/sessions, ~/.codex/state_5.sqlite | %USERPROFILE%\.codex\sessions, %USERPROFILE%\.codex\state_5.sqlite (portable dotfile via Rust dirs::home_dir()). CODEX_HOME overrides whole tree cross-platform. | Verified | home-dir/src/lib.rs · Codex on Windows |
| Claude Code | ~/.claude*/projects/ | %USERPROFILE%\.claude*\projects\ (portable dotfile; docs say so verbatim). CLAUDE_CONFIG_DIR overrides cross-platform. NOTE: %APPDATA%\Claude is the Claude Desktop app, not Claude Code. | Verified | claude-directory docs · env-vars docs |
| Kimi CLI | ~/.kimi (env KIMI_SHARE_DIR) | %USERPROFILE%\.kimi (portable dotfile via Python Path.home(); KIMI_SHARE_DIR honored). | Verified (path logic); native-Windows support Uncertain | share.py · kimi-cli repo |
| Pi | ~/.pi/agent/sessions (tokdash assumes env PI_AGENT_DIR, comma-separated) | %USERPROFILE%\.pi\agent\sessions (portable dotfile via Node os.homedir()). Env-var mismatch (see note): live var is PI_CODING_AGENT_DIR / PI_CODING_AGENT_SESSION_DIR, single path, no comma-list. | Verified (path logic); env-var name/comma-list premise contradicted | config.ts · docs/windows.md · settings docs |
| Hermes | ~/.hermes (env HERMES_HOME, comma-separated) | %LOCALAPPDATA%\hermes (state.db at %LOCALAPPDATA%\hermes\state.db) — this tool DOES branch to a Windows-native dir. Installer sets HERMES_HOME=%LOCALAPPDATA%\hermes. No comma-list support (single path; "profiles" is the multi-instance mechanism). | Verified | hermes-agent repo (hermes_constants.py, hermes_state.py) · Windows Native guide · configuration docs |
| Amp | ~/.amp | %USERPROFILE%\.amp (portable dotfile; env var is AMP_HOME, not AMP_DATA_HOME). | Verified (via shipped Windows binary strings) | ampcode.com/manual · @ampcode/cli-win32-x64 |
Per-client recommended clientpaths.py branch
OpenCode — HIGHEST priority; result is the surprising one
- Do NOT branch to
%APPDATA%/%LOCALAPPDATA%. OpenCode importsxdgDataunconditionally from the npmxdg-basedirpackage (xdg-basedir=env.XDG_DATA_HOME || join(os.homedir(), '.local', 'share')) with noprocess.platform === 'win32'branch anywhere. So on Windows the data root is literally%USERPROFILE%\.local\share\opencode\— the same.local\sharelayout as Linux. - Recommended branch: keep the current logic essentially as-is, but resolve
XDG_DATA_HOMEfirst, then fall back toPath.home() / ".local/share/opencode/...". On WindowsPath.home()already yields%USERPROFILE%, soPath.home() / ".local/share/opencode/storage/message"and.../opencode.dbare correct without an OS branch. The only Windows override that redirects these isXDG_DATA_HOME. - Corroboration: issue #8235 ("Config and Data directories
follow the Linux XDG standard even on windows") documents exactly this; it was stale-bot-closed, not fixed, and
current
dev-branch source still has no Windows branch. (Repo note:github.com/sst/opencodenow redirects togithub.com/anomalyco/opencode— same project, renamed org.)
GitHub Copilot CLI
- Keep
Path.home() / ".copilot" / "otel"and the~/.copilot/session-state/*/events.jsonlglob — the dotfile is portable; docs confirm~/.copilot/on Windows ($HOME/.copilot/...examples).COPILOT_OTEL_FILE_EXPORTER_PATHandCOPILOT_HOMEare honored cross-platform (tokdash already reads the former). - Watch-out: the Windows cache dir is
%LOCALAPPDATA%\copilot(overrideCOPILOT_CACHE_HOME) — that is NOT session/otel data; do not point the parser there.
Gemini CLI
- Keep
Path.home() / ".gemini"— portable dotfile.getGlobalGeminiDir()=join(os.homedir(), '.gemini')with no OS branch and no XDG redirect. No per-user.geminirelocation env var exists today (GEMINI_CLI_HOMEchanges the home base; system-levelC:\ProgramData\gemini-cli\config is separate and not what tokdash parses).
Antigravity CLI
- Keep
Path.home() / ".gemini" / "antigravity-{cli,acp,ide}" / "conversations"— Antigravity usage DBs live under the same portable.geminiroot, one sibling home per product (CLI, ACP kernel, IDE), all in the same schema. The usage parser globs only*.db, folds-wal/-shmsidecars into file signatures, and intentionally ignores legacy.pbfiles and the ACP kernel's*.metasidecars.ANTIGRAVITY_HOME(Tokdash-side, comma-separated) adds further homes without displacing the defaults. Session Explorer reads the same files. - Evidence is not uniform across the three homes.
antigravity-cliis verified against a real install;antigravity-acprests on the official kernel's quoted help text (see the registry entry above);antigravity-ideis an uncited aside in #72 and has not been seen locally. Discovery is fail-soft — a home that does not exist contributes nothing — so a wrong sibling name costs nothing but should not be cited as verified. Confirm it against an IDE install before treating it as known.
Codex
- Keep
Path.home() / ".codex"— portable dotfile via the Rustdirscrate. ✅ Implemented:clientpaths.codex_home()resolvesCODEX_HOMEfirst (works identically on Windows, any absolute path) and falls back toPath.home()/".codex"; the sessions dir andstate_5.sqliteboth derive from it. - Windows is natively supported (sandbox modes in
config.toml); the in-repodocs/install.md"WSL2 only" line is stale — the live docs site supersedes it.
Claude Code
- Keep the
Path.home().glob(".claude*")+/projectslogic — docs state verbatim that on Windows~/.clauderesolves to%USERPROFILE%\.claude. ✅ Implemented for the config/credentials dir:clientpaths.claude_config_dir()resolvesCLAUDE_CONFIG_DIRfirst (cross-platform; used by quota tracking); the usage parsers keep the.claude*glob for multi-install project discovery. - Do not confuse with
%APPDATA%\Claude\(that's Claude Desktop, a different product).
Kimi CLI
- Keep
Path.home() / ".kimi"with the existingKIMI_SHARE_DIRoverride — resolver isPath(os.getenv("KIMI_SHARE_DIR")) or Path.home()/".kimi", and PythonPath.home()yields%USERPROFILE%on Windows. Path logic is portable as-is. (Caveat: no docs/CI evidence that Kimi CLI is actually tested on native Windows — the path math is right, but Windows support is otherwise undocumented.)
Pi
- Keep
Path.home() / ".pi" / "agent" / "sessions"for the default — portable dotfile via Nodeos.homedir(), and native Windows is officially supported (Git Bash required for the shell tool). - Env-var discrepancy to resolve (not a path issue but affects the override branch): tokdash's
pi_agent_search_dirs()readsPI_AGENT_DIRas a comma-separated list. In current upstream source, the live runtime var isPI_CODING_AGENT_DIR(andPI_CODING_AGENT_SESSION_DIRfor the session dir specifically), a single path —PI_AGENT_DIRonly appears as a test constant / one-off migration script, and no comma-split logic exists anywhere upstream. This is orthogonal to Windows but should be reconciled against whichever Pi version tokdash targets before writing the branch. (If the comma-list override is kept, note Windows drive-letter paths likeD:\...don't contain commas, so splitting on,is still safe.)
Hermes — the one genuine Windows branch
- DO branch on Windows. On POSIX the DB is
~/.hermes/state.db; on native Windows Hermes uses%LOCALAPPDATA%\hermes\state.db(the installer setsHERMES_HOME=%LOCALAPPDATA%\hermes, and source branchesif sys.platform == "win32": base = %LOCALAPPDATA% (or ~/AppData/Local); return base/"hermes"). - Recommended branch: resolve
HERMES_HOMEfirst (already done); when unset, on Windows returnPath(os.environ.get("LOCALAPPDATA") or Path.home()/"AppData"/"Local") / "hermes", elsePath.home()/".hermes". - Also reconcile the comma-list: upstream
HERMES_HOMEis read as a singlePath(val)— no comma-separated multi-dir support (multi-instance is done via "profiles", not comma-lists). tokdash'shermes_search_dirs()comma-split is a tokdash-specific convenience; keep it if desired, but it does not mirror upstream behavior.
Amp
- Keep
Path.home() / ".amp"— portable dotfile; the shipped Windows binary literally doesif (process.env.AMP_HOME) return process.env.AMP_HOME; ... return join(homedir(), ".amp")and embeds%USERPROFILE%\.amp\bin\amp.bat. If an override is ever added to tokdash, the env var isAMP_HOME(notAMP_DATA_HOME). Note Amp's settings file lives separately at%USERPROFILE%\.config\amp\settings.json, which tokdash's.amp-rooted parser does not currently need.
Still unverified — needs a real Windows box to confirm
These are honest gaps. Do NOT hardcode any of the below as if verified:
-
Copilot CLI
events.jsonlfilename convention on Windows. The docs confirm the%USERPROFILE%\.copilot\session-state\directory exists on Windows, but the exact per-session*/events.jsonlfile layout was confirmed only on POSIX and inferred by analogy. Also note current builds (v0.0.342+) usesession-state/; older builds usedhistory-session-state/— verify which exists on a real Windows install. (Source: cli-config-dir-reference.) -
Kimi CLI actually running on native Windows. The path-construction code is portable (
Path.home()/".kimi"), but there are no Windows install instructions, docs, or CI evidence that Kimi CLI is supported/exercised on native Windows. The%USERPROFILE%\.kimi\sessions\<userId>\<sessionId>\wire.jsonllayout is inferred to hold on Windows but was not observed on a Windows box. -
OpenCode: no default-state Windows observation. The
%USERPROFILE%\.local\share\opencode\conclusion is from source (strong), but the one publicopencode debug pathsWindows dump found had a customizedXDG_CONFIG_HOME, so it isn't clean default-state proof. Aopencode debug pathsrun on a stock Windows install would confirm. -
Pi env-var reconciliation. Whether tokdash should read
PI_CODING_AGENT_DIR/PI_CODING_AGENT_SESSION_DIR(upstream-current) vs thePI_AGENT_DIRit reads today depends on the Pi version tokdash targets — needs a decision, not a Windows box, but flagged here because it affects the override branch. -
Hermes comma-list vs single path. The
%LOCALAPPDATA%\hermesdefault is verified; the divergence between tokdash's comma-separatedHERMES_HOMEhandling and upstream's single-path reading should be reconciled against the Hermes version tokdash targets.