Summary
Even with full XDG Base Directory Spec support (gogcli#621), gogcli's path resolution remains coupled to operator control over $XDG_*_HOME vars. In environments where the parent process can't or won't set XDG vars portably — agent sandboxes, container runtimes, CI runners — gogcli ends up with the wrong paths.
Add a gogcli-specific override layer above XDG: a primary GOG_HOME umbrella env var (matching CARGO_HOME, RUSTUP_HOME, GOPATH) and per-XDG-kind overrides (GOG_CONFIG_DIR, GOG_DATA_DIR, GOG_STATE_DIR, GOG_CACHE_DIR), plus a --home <path> global CLI flag.
Why GOG_* and not GOGCLI_*
Empirical verification at tag v0.17.0: every env var gogcli currently reads uses the GOG_* prefix — GOG_KEYRING_BACKEND, GOG_KEYRING_PASSWORD, GOG_KEYRING_SERVICE_NAME, GOG_ACCOUNT, GOG_HELP, GOG_COLOR, GOG_TIMEZONE, GOG_AUTH_MODE, GOG_*_API_KEY, GOG_*_BASE_URL. Zero GOGCLI_* env vars exist in source. The GOG_* namespace is gogcli's established convention; this proposal matches it.
(This differs from sibling mcporter's MCPORTER_* convention, but matching gogcli's own internal convention is the right principle — pushing GOGCLI_* would force gogcli to break its own namespace.)
Why a *_HOME umbrella, not just a *_CONFIG_DIR
config.Dir() in internal/config/paths.go is the single function controlling every persisted-state location in gogcli today — config, keyring, credentials, drive downloads, gmail attachments, service-account keys, gmail-watch state, tracking config. After XDG conformance lands, that single function splits into per-kind resolvers (DataDir, StateDir, CacheDir, etc.). The override layer needs to match that shape: one umbrella (GOG_HOME — analogous to CARGO_HOME, RUSTUP_HOME) plus per-kind overrides for operators who want to split lifetimes (durable data on a backed-up volume, cache on tmpfs).
A single GOG_CONFIG_DIR would only cover one of the four+ resolvers, defeating the purpose. Matches the more established CLI convention (cargo, rustup, gh).
Current behavior (after XDG-conformance fix)
Once gogcli#621 lands, the path-resolution chain for each kind is:
$XDG_<KIND>_HOME env var, if set
$HOME/<spec-default>/gogcli (XDG fallback)
There's no gogcli-specific override above XDG. If the parent process strips or rewrites the XDG vars, the operator has no recourse.
Why this matters
gogcli's deployability remains coupled to upstream/sandbox XDG handling. Concrete pain point we hit:
OpenClaw strips XDG_CONFIG_HOME from the inherited environment of subprocesses it spawns, due to a policy oversight where XDG_CONFIG_HOME is listed in blockedOverrideOnlyKeys without a matching entry in allowedInheritedOverrideOnlyKeys (see host-env-security-policy.json). Filed upstream as openclaw#84854.
Even once that bug is fixed, other sandboxes / container runtimes / CI environments may also restrict or rewrite XDG vars. A tool-specific override is the standard escape hatch — it's portable, it doesn't collide with broader sandbox policies that target XDG vars, and it makes operator intent explicit ("I want gogcli's state here") rather than implicit via a shared env var.
mcporter#184 illustrates the inverse failure mode: embedders sometimes set XDG_CONFIG_HOME for an unrelated downstream tool, accidentally redirecting other XDG-aware tools too. A tool-specific override insulates gogcli from this kind of cross-tool XDG collision.
Precedent: mcporter (sibling project in openclaw/) exposes MCPORTER_CONFIG for exactly this reason — to override the XDG-derived config path when XDG resolution is unavailable or undesirable (see path-discovery.ts at v0.11.1).
Proposed solution
Scope: this proposal covers the four XDG Base Directory kinds (config, data, state, cache). The fifth kind from gogcli#621 — downloads — falls under a separate freedesktop spec (xdg-user-dirs) and is intentionally not part of GOG_HOME's umbrella: downloads are user-visible content with their own routing semantics (operators expect ~/Downloads/-style paths, not state-dir paths). Operators wanting downloads under GOG_HOME should set XDG_DOWNLOAD_DIR explicitly. A symmetric GOG_DOWNLOAD_DIR per-kind override could be added if the maintainer prefers — flagging as an open question.
Per-XDG-kind precedence chain (first match wins, most-specific to least-specific):
GOG_<KIND>_DIR env var (where <KIND> is CONFIG / DATA / STATE / CACHE) — direct directory path, used as-is with no gogcli subdir append. Highest precedence; lets operators split lifetimes (e.g. data on a backed-up volume, cache on tmpfs).
--home <path> CLI flag — per-invocation umbrella. Resolves to <path>/<kind>/ for each kind (flat XDG-kind sub-layout). Wins over GOG_HOME per the cobra-flag-overrides-env convention. Global, persistent across all subcommands.
GOG_HOME env var — durable umbrella with the same flat XDG-kind sub-layout ($GOG_HOME/{config,data,state,cache}/). The intended shape for container entrypoints / systemd units / shell profiles.
$XDG_<KIND>_HOME/gogcli — spec-conformant XDG path, from gogcli#621.
$HOME/<XDG-default>/gogcli — XDG default fallback (e.g. ~/.config/gogcli, ~/.local/share/gogcli, ~/.local/state/gogcli, ~/.cache/gogcli).
Rank 1 (GOG_<KIND>_DIR) wins over both umbrella forms because per-kind overrides represent the most specific operator intent.
Why flat XDG-kind sub-layout under GOG_HOME (not $HOME-style dotted sub-layout): operators setting GOG_HOME=/persist expect to find gogcli's state directly under /persist/, not under /persist/.local/share/gogcli/. Cargo/Rustup precedent backs this — CARGO_HOME contains registry/, git/, bin/ directly (not .local/share/cargo/). The .local/share/-style nesting is meaningful only in the XDG default case where the resolver synthesizes a path under $HOME; once the operator has explicitly named a directory via GOG_HOME, that directory is the gogcli root, with kinds as immediate children.
Sketch (extending the resolver from gogcli#621):
package config
// kindName is introduced by this proposal (not part of gogcli#621).
// gogcli#621 defines xdgDefault() for the XDG-default fallback case;
// kindName() is the flat-layout equivalent for use under $GOG_HOME.
//
// Different from xdgDefault() (gogcli#621): xdgDefault() returns the XDG-spec
// default path under $HOME ("config", ".local/share", ".local/state", ".cache"),
// suitable for the fallback case. kindName() returns the short kind name
// ("config", "data", "state", "cache") for use under operator-named $GOG_HOME,
// matching the CARGO_HOME / RUSTUP_HOME convention of flat sub-layouts.
func kindName(kind XdgKind) string {
switch kind {
case KindConfig: return "config"
case KindData: return "data"
case KindState: return "state"
case KindCache: return "cache"
}
return ""
}
// kindDir returns the gogcli directory for a given XDG kind.
//
// Resolution order (most specific to least):
// 1. GOG_<KIND>_DIR env var — operator-supplied absolute path; used as-is
// 2. $GOG_HOME/<kindName> — umbrella override, flat XDG-kind sub-layout
// 3. $XDG_<KIND>_HOME/gogcli — spec-conformant XDG path
// 4. $HOME/<XDG-default>/gogcli — XDG default fallback
//
// The --home CLI flag is resolved at the cobra layer by overwriting GOG_HOME
// in the process env before kindDir runs, so it doesn't need its own branch
// here — it appears as rank 2 to the operator but is implemented as a flag
// → env coercion above this resolver.
func kindDir(kind XdgKind) (string, error) {
// Per-kind direct override
if perKind := strings.TrimSpace(os.Getenv(gogKindEnvVar(kind))); perKind != "" {
return perKind, nil // operator-supplied absolute path; no AppName join
}
// Umbrella GOG_HOME — flat XDG-kind sub-layout
if home := strings.TrimSpace(os.Getenv("GOG_HOME")); home != "" {
return filepath.Join(home, kindName(kind)), nil
// e.g. GOG_HOME=/persist → /persist/data for the data kind
// (or operator overrides per-kind via GOG_DATA_DIR for full control)
}
// XDG layer (from gogcli#621)
if xdg := strings.TrimSpace(os.Getenv(xdgEnvVar(kind))); xdg != "" {
return filepath.Join(xdg, AppName), nil
}
// XDG default
home, err := os.UserHomeDir()
if err != nil {
return "", fmt.Errorf("resolve user home dir: %w", err)
}
return filepath.Join(home, xdgDefault(kind), AppName), nil
}
func gogKindEnvVar(kind XdgKind) string {
switch kind {
case KindConfig: return "GOG_CONFIG_DIR"
case KindData: return "GOG_DATA_DIR"
case KindState: return "GOG_STATE_DIR"
case KindCache: return "GOG_CACHE_DIR"
}
return ""
}
CLI: --home <path> as a persistent global flag on the root cobra command, equivalent to setting GOG_HOME for the duration of the invocation.
Interaction with gogcli#621's public API: the public wrappers added by gogcli#621 (Dir(), DataDir(), StateDir(), CacheDir()) are preserved — they delegate to kindDir(kind) exactly as before, gaining the new override layer transparently. No call-site changes beyond what gogcli#621 already specifies.
Open design questions for the maintainer
- Per-kind override semantics — strip the
gogcli suffix?: GOG_DATA_DIR=/foo/bar should resolve to /foo/bar (no gogcli join) — same as MCPORTER_CONFIG doesn't auto-join. Convention from other tools (CARGO_HOME, RUSTUP_HOME, GOPATH) is "no auto-join, operator supplies the literal directory." The sketch above implements this; flagging in case maintainer prefers an auto-join variant.
- CLI flag scope:
--home as a persistent global flag on the root command, matching --config / --profile conventions in most cobra CLIs. Per-subcommand override flags (--config-dir, etc.) are likely overkill — env vars cover the use case.
- Validation: should the per-kind override reject non-absolute paths (defensive) or accept them (let CWD context apply)? mcporter rejects non-absolute via
path.isAbsolute check. Recommended: reject non-absolute, fail-fast with a clear error.
(Note: the prior draft included an open question about GOG_HOME flat vs. XDG-default sub-layout. The sketch above commits to flat XDG-kind sub-layout per the rationale paragraph in "Proposed solution"; flagging here in case the maintainer prefers a different shape.)
Alternatives considered
- Symlink workaround at the deployment layer (e.g.
ln -sfn /persist/gogcli ~/.config/gogcli) — works as break-glass but couples deployment to an internal gogcli path convention that could change. Also doesn't compose with the XDG-kind split.
- Wrapper script exporting XDG vars before invoking
gogcli — works but only when the wrapper has control over how gogcli is spawned. Doesn't help when gogcli is spawned by another tool (an agent, a skill runner) that already sanitized the env.
- Fix only the parent sandbox (OpenClaw, in our case) — necessary, and being pursued separately (openclaw#84854). But this leaves gogcli brittle in every other environment that does similar XDG sanitization.
- Single
GOG_CONFIG_DIR only (no umbrella, no per-kind variants) — covers only one resolver; defeats the kind-aware separation that XDG conformance just introduced. This was the first-pass shape of this proposal before the kind-aware framing made the broader override necessary.
Impact
- Affected: gogcli users in containerized / sandboxed / agent-spawned environments where the parent process can't or won't set XDG vars portably.
- Severity: medium — has workarounds (symlinks, wrapper scripts) but each is a small papercut accumulating across deployments. Without this knob, every deployer of gogcli has to learn gogcli's XDG dependency and engineer around it.
- Frequency: affects every deployment of the affected class; one-time learning curve per deployer.
- Consequence: lost or misplaced OAuth refresh tokens, broken keyring continuity, persistent-state drift between container restarts when the surrounding stack is XDG-hostile.
Evidence / examples
- gogcli env-var inventory (grepped from source at tag
v0.17.0): all use GOG_* prefix, zero GOGCLI_* exist. The proposed naming matches the established convention.
- mcporter precedent for tool-specific path override:
src/config/path-discovery.ts reads MCPORTER_CONFIG env var as the highest-precedence escape hatch (at v0.11.1).
- Conventional precedent for
*_HOME umbrella vars: CARGO_HOME, RUSTUP_HOME, GOPATH, npm_config_prefix, PIP_CONFIG_FILE, GH_CONFIG_DIR, KUBECONFIG, DOCKER_CONFIG — every mature CLI exposes a tool-specific path override above the XDG default.
Additional information
Backward compatibility: fully preserved. The new env vars and flag are additional precedence above the XDG layer; existing users see no behavior change unless they opt in.
Migration path once both this and the XDG-conformance proposal ship: set GOG_HOME=/persist/gogcli (or per-kind variants for split-lifetime layouts — durable data on a backed-up volume, cache on tmpfs) in the container entrypoint. Retires the dependency on XDG_CONFIG_HOME (and the other XDG vars) reaching gogcli through the parent sandbox's env sanitizer, and gets the right per-kind separation.
Related references
Companion proposal (must-land-first):
- gogcli#621 — "Honor XDG Base Directory Spec for credentials, vault, state, cache, and download paths" (filed 2026-05-21, OPEN). Introduces the per-kind resolvers this proposal layers overrides on top of. Should land first; this proposal is incoherent without it.
Concrete trigger:
- openclaw#84854 — filed 2026-05-21: OpenClaw's host-env sanitizer strips
XDG_CONFIG_HOME and XDG_CONFIG_DIRS from inherited subprocess env, contrary to the XDG Base Directory Spec. Fixing that bug closes the immediate failure mode for the OpenClaw-spawned case; this feature request is the defense-in-depth so gogcli isn't tied to a single env-var-name's policy treatment in every container/sandbox/runner above it.
Sibling-project precedent:
openclaw/mcporter#155 ("Honor XDG Base Directory Spec for config, vault, cache, and daemon paths") — closed as completed, shipped in mcporter v0.10.0. mcporter additionally exposes MCPORTER_CONFIG in src/config/path-discovery.ts as a tool-specific path override above the XDG default — exactly the pattern proposed here for GOG_HOME + per-kind overrides.
openclaw/mcporter#184 — illustrates why a tool-specific override is valuable even when XDG support exists: embedders sometimes set XDG_CONFIG_HOME for an unrelated downstream tool, accidentally redirecting other XDG-aware tools too. A GOG_* override insulates gogcli from this kind of cross-tool XDG collision.
Conventional precedent in other CLIs:
CARGO_HOME, RUSTUP_HOME, GOPATH, npm_config_prefix, PIP_CONFIG_FILE, GH_CONFIG_DIR, KUBECONFIG, DOCKER_CONFIG — every mature CLI exposes a tool-specific path override above the XDG default.
XDG Base Directory Specification:
- freedesktop.org spec, latest revision — current XDG behavior in gogcli already follows the spec for one kind (config); the companion XDG-conformance proposal extends that to all four kinds, and this proposal adds the operator-override layer above that.
gogcli source code referenced:
internal/config/paths.go at tag v0.17.0 — the central path-resolution that this proposal extends. Today's AppName = "gogcli" constant and Dir() shape are reused; the new kindDir(kind) resolver from the XDG-conformance proposal gains the GOG_<KIND>_DIR / GOG_HOME precedence layer described above.
Summary
Even with full XDG Base Directory Spec support (gogcli#621), gogcli's path resolution remains coupled to operator control over
$XDG_*_HOMEvars. In environments where the parent process can't or won't set XDG vars portably — agent sandboxes, container runtimes, CI runners — gogcli ends up with the wrong paths.Add a gogcli-specific override layer above XDG: a primary
GOG_HOMEumbrella env var (matchingCARGO_HOME,RUSTUP_HOME,GOPATH) and per-XDG-kind overrides (GOG_CONFIG_DIR,GOG_DATA_DIR,GOG_STATE_DIR,GOG_CACHE_DIR), plus a--home <path>global CLI flag.Why
GOG_*and notGOGCLI_*Empirical verification at tag
v0.17.0: every env var gogcli currently reads uses theGOG_*prefix —GOG_KEYRING_BACKEND,GOG_KEYRING_PASSWORD,GOG_KEYRING_SERVICE_NAME,GOG_ACCOUNT,GOG_HELP,GOG_COLOR,GOG_TIMEZONE,GOG_AUTH_MODE,GOG_*_API_KEY,GOG_*_BASE_URL. ZeroGOGCLI_*env vars exist in source. TheGOG_*namespace is gogcli's established convention; this proposal matches it.(This differs from sibling
mcporter'sMCPORTER_*convention, but matching gogcli's own internal convention is the right principle — pushingGOGCLI_*would force gogcli to break its own namespace.)Why a
*_HOMEumbrella, not just a*_CONFIG_DIRconfig.Dir()ininternal/config/paths.gois the single function controlling every persisted-state location in gogcli today — config, keyring, credentials, drive downloads, gmail attachments, service-account keys, gmail-watch state, tracking config. After XDG conformance lands, that single function splits into per-kind resolvers (DataDir,StateDir,CacheDir, etc.). The override layer needs to match that shape: one umbrella (GOG_HOME— analogous toCARGO_HOME,RUSTUP_HOME) plus per-kind overrides for operators who want to split lifetimes (durable data on a backed-up volume, cache on tmpfs).A single
GOG_CONFIG_DIRwould only cover one of the four+ resolvers, defeating the purpose. Matches the more established CLI convention (cargo, rustup, gh).Current behavior (after XDG-conformance fix)
Once gogcli#621 lands, the path-resolution chain for each kind is:
$XDG_<KIND>_HOMEenv var, if set$HOME/<spec-default>/gogcli(XDG fallback)There's no gogcli-specific override above XDG. If the parent process strips or rewrites the XDG vars, the operator has no recourse.
Why this matters
gogcli's deployability remains coupled to upstream/sandbox XDG handling. Concrete pain point we hit:
OpenClaw strips
XDG_CONFIG_HOMEfrom the inherited environment of subprocesses it spawns, due to a policy oversight whereXDG_CONFIG_HOMEis listed inblockedOverrideOnlyKeyswithout a matching entry inallowedInheritedOverrideOnlyKeys(seehost-env-security-policy.json). Filed upstream as openclaw#84854.Even once that bug is fixed, other sandboxes / container runtimes / CI environments may also restrict or rewrite XDG vars. A tool-specific override is the standard escape hatch — it's portable, it doesn't collide with broader sandbox policies that target XDG vars, and it makes operator intent explicit ("I want gogcli's state here") rather than implicit via a shared env var.
mcporter#184 illustrates the inverse failure mode: embedders sometimes set
XDG_CONFIG_HOMEfor an unrelated downstream tool, accidentally redirecting other XDG-aware tools too. A tool-specific override insulates gogcli from this kind of cross-tool XDG collision.Precedent:
mcporter(sibling project inopenclaw/) exposesMCPORTER_CONFIGfor exactly this reason — to override the XDG-derived config path when XDG resolution is unavailable or undesirable (seepath-discovery.tsatv0.11.1).Proposed solution
Scope: this proposal covers the four XDG Base Directory kinds (config, data, state, cache). The fifth kind from gogcli#621 — downloads — falls under a separate freedesktop spec (xdg-user-dirs) and is intentionally not part of
GOG_HOME's umbrella: downloads are user-visible content with their own routing semantics (operators expect~/Downloads/-style paths, not state-dir paths). Operators wanting downloads underGOG_HOMEshould setXDG_DOWNLOAD_DIRexplicitly. A symmetricGOG_DOWNLOAD_DIRper-kind override could be added if the maintainer prefers — flagging as an open question.Per-XDG-kind precedence chain (first match wins, most-specific to least-specific):
GOG_<KIND>_DIRenv var (where<KIND>isCONFIG/DATA/STATE/CACHE) — direct directory path, used as-is with nogogclisubdir append. Highest precedence; lets operators split lifetimes (e.g. data on a backed-up volume, cache on tmpfs).--home <path>CLI flag — per-invocation umbrella. Resolves to<path>/<kind>/for each kind (flat XDG-kind sub-layout). Wins overGOG_HOMEper the cobra-flag-overrides-env convention. Global, persistent across all subcommands.GOG_HOMEenv var — durable umbrella with the same flat XDG-kind sub-layout ($GOG_HOME/{config,data,state,cache}/). The intended shape for container entrypoints / systemd units / shell profiles.$XDG_<KIND>_HOME/gogcli— spec-conformant XDG path, from gogcli#621.$HOME/<XDG-default>/gogcli— XDG default fallback (e.g.~/.config/gogcli,~/.local/share/gogcli,~/.local/state/gogcli,~/.cache/gogcli).Rank 1 (
GOG_<KIND>_DIR) wins over both umbrella forms because per-kind overrides represent the most specific operator intent.Why flat XDG-kind sub-layout under
GOG_HOME(not$HOME-style dotted sub-layout): operators settingGOG_HOME=/persistexpect to find gogcli's state directly under/persist/, not under/persist/.local/share/gogcli/. Cargo/Rustup precedent backs this —CARGO_HOMEcontainsregistry/,git/,bin/directly (not.local/share/cargo/). The.local/share/-style nesting is meaningful only in the XDG default case where the resolver synthesizes a path under$HOME; once the operator has explicitly named a directory viaGOG_HOME, that directory is the gogcli root, with kinds as immediate children.Sketch (extending the resolver from gogcli#621):
CLI:
--home <path>as a persistent global flag on the root cobra command, equivalent to settingGOG_HOMEfor the duration of the invocation.Interaction with gogcli#621's public API: the public wrappers added by gogcli#621 (
Dir(),DataDir(),StateDir(),CacheDir()) are preserved — they delegate tokindDir(kind)exactly as before, gaining the new override layer transparently. No call-site changes beyond what gogcli#621 already specifies.Open design questions for the maintainer
gogclisuffix?:GOG_DATA_DIR=/foo/barshould resolve to/foo/bar(nogogclijoin) — same asMCPORTER_CONFIGdoesn't auto-join. Convention from other tools (CARGO_HOME,RUSTUP_HOME,GOPATH) is "no auto-join, operator supplies the literal directory." The sketch above implements this; flagging in case maintainer prefers an auto-join variant.--homeas a persistent global flag on the root command, matching--config/--profileconventions in most cobra CLIs. Per-subcommand override flags (--config-dir, etc.) are likely overkill — env vars cover the use case.path.isAbsolutecheck. Recommended: reject non-absolute, fail-fast with a clear error.(Note: the prior draft included an open question about
GOG_HOMEflat vs. XDG-default sub-layout. The sketch above commits to flat XDG-kind sub-layout per the rationale paragraph in "Proposed solution"; flagging here in case the maintainer prefers a different shape.)Alternatives considered
ln -sfn /persist/gogcli ~/.config/gogcli) — works as break-glass but couples deployment to an internal gogcli path convention that could change. Also doesn't compose with the XDG-kind split.gogcli— works but only when the wrapper has control over how gogcli is spawned. Doesn't help when gogcli is spawned by another tool (an agent, a skill runner) that already sanitized the env.GOG_CONFIG_DIRonly (no umbrella, no per-kind variants) — covers only one resolver; defeats the kind-aware separation that XDG conformance just introduced. This was the first-pass shape of this proposal before the kind-aware framing made the broader override necessary.Impact
Evidence / examples
v0.17.0): all useGOG_*prefix, zeroGOGCLI_*exist. The proposed naming matches the established convention.src/config/path-discovery.tsreadsMCPORTER_CONFIGenv var as the highest-precedence escape hatch (atv0.11.1).*_HOMEumbrella vars:CARGO_HOME,RUSTUP_HOME,GOPATH,npm_config_prefix,PIP_CONFIG_FILE,GH_CONFIG_DIR,KUBECONFIG,DOCKER_CONFIG— every mature CLI exposes a tool-specific path override above the XDG default.Additional information
Backward compatibility: fully preserved. The new env vars and flag are additional precedence above the XDG layer; existing users see no behavior change unless they opt in.
Migration path once both this and the XDG-conformance proposal ship: set
GOG_HOME=/persist/gogcli(or per-kind variants for split-lifetime layouts — durable data on a backed-up volume, cache on tmpfs) in the container entrypoint. Retires the dependency onXDG_CONFIG_HOME(and the other XDG vars) reaching gogcli through the parent sandbox's env sanitizer, and gets the right per-kind separation.Related references
Companion proposal (must-land-first):
Concrete trigger:
XDG_CONFIG_HOMEandXDG_CONFIG_DIRSfrom inherited subprocess env, contrary to the XDG Base Directory Spec. Fixing that bug closes the immediate failure mode for the OpenClaw-spawned case; this feature request is the defense-in-depth so gogcli isn't tied to a single env-var-name's policy treatment in every container/sandbox/runner above it.Sibling-project precedent:
openclaw/mcporter#155("Honor XDG Base Directory Spec for config, vault, cache, and daemon paths") — closed as completed, shipped in mcporterv0.10.0. mcporter additionally exposesMCPORTER_CONFIGinsrc/config/path-discovery.tsas a tool-specific path override above the XDG default — exactly the pattern proposed here forGOG_HOME+ per-kind overrides.openclaw/mcporter#184— illustrates why a tool-specific override is valuable even when XDG support exists: embedders sometimes setXDG_CONFIG_HOMEfor an unrelated downstream tool, accidentally redirecting other XDG-aware tools too. AGOG_*override insulates gogcli from this kind of cross-tool XDG collision.Conventional precedent in other CLIs:
CARGO_HOME,RUSTUP_HOME,GOPATH,npm_config_prefix,PIP_CONFIG_FILE,GH_CONFIG_DIR,KUBECONFIG,DOCKER_CONFIG— every mature CLI exposes a tool-specific path override above the XDG default.XDG Base Directory Specification:
gogcli source code referenced:
internal/config/paths.goat tagv0.17.0— the central path-resolution that this proposal extends. Today'sAppName = "gogcli"constant andDir()shape are reused; the newkindDir(kind)resolver from the XDG-conformance proposal gains theGOG_<KIND>_DIR/GOG_HOMEprecedence layer described above.