Skip to content

Move global config to XDG location (~/.config/projector/config.toml)#27

Merged
kevdoran merged 2 commits into
mainfrom
xdg-config-location
Jun 23, 2026
Merged

Move global config to XDG location (~/.config/projector/config.toml)#27
kevdoran merged 2 commits into
mainfrom
xdg-config-location

Conversation

@kevdoran

Copy link
Copy Markdown
Owner

What & why

Closes #22. Moves the default global config from ~/.projector/projector-config.toml to the XDG-style ~/.config/projector/config.toml, matching the conventions used by gh, mise, and iterm2 and reducing home-directory clutter.

ConfigDir/ConfigFilePath now honor $XDG_CONFIG_HOME:

  • If $XDG_CONFIG_HOME is set: $XDG_CONFIG_HOME/projector/config.toml.
  • Otherwise: ~/.config/projector/config.toml (XDG default base ~/.config).

Backwards-compatibility / resolution order

config.Load() resolves in this order:

  1. New location ($XDG_CONFIG_HOME/projector/config.toml, default ~/.config/projector/config.toml) — preferred.
  2. Legacy location (~/.projector/projector-config.toml) — fallback when the new file is absent.
  3. Neither present → ErrNotFound (treated as not-yet-configured, same as before).

config.Save() always writes to the new location.

Migration semantics: copy, not move

When the config exists only at the legacy location, Load copies it to the new location (creating ~/.config/projector/), leaves the legacy file untouched, and prints a one-line notice to stdout:

Migrated projector config to <new> (copied from <legacy>; the old file was left in place).

Rationale for copy-vs-move: copying is the safer choice for users who may still run an older pj binary that only reads the legacy path — both binaries keep working. Migration is best-effort: if the copy fails (e.g. read-only ~/.config), Load still loads directly from the legacy file rather than failing the command. Since Save targets the new location, the two files can diverge after a subsequent write; this is the accepted trade-off for keeping older binaries functional, and Load always prefers the new file once it exists.

Tests

Added/updated tests in internal/config/config_test.go:

  • new location preferred over legacy (and legacy left unchanged)
  • legacy → new copy-migration (new file created, legacy preserved, second load reads new)
  • $XDG_CONFIG_HOME override and default-to-~/.config
  • Save writes to new location only
  • no-config-anywhere → ErrNotFound

The shared test helper now also clears XDG_CONFIG_HOME to keep resolution self-contained.

Docs

Updated docs/commands.md (incl. a note on the XDG location + legacy fallback/migration), CLAUDE.md (config package row), pj-skill.md, and the pj config command Short help text.

Verification

Locally: go build ./cmd/projector, go vet ./..., and go test -race -count=1 ./... all pass.

For reviewers to scrutinize / not verified locally

  • Real-world cross-binary behavior (old pj reading legacy while new pj reads/writes the new path) is reasoned about, not exercised in CI.
  • The migration message goes to stdout; if any command's stdout is machine-parsed, this one-time line could be unexpected. It only prints on the first load after the file exists solely at the legacy path.
  • $XDG_CONFIG_HOME is used verbatim if set; no validation that it is an absolute path (matches typical XDG tooling behavior).

🤖 Generated with Claude Code

kevdoran and others added 2 commits June 22, 2026 20:15
Change the default global config location to the XDG-style
$XDG_CONFIG_HOME/projector/config.toml (defaulting to
~/.config/projector/config.toml), matching gh/mise/iterm2 conventions and
reducing home-directory clutter.

Backwards compatible:
- Load prefers the new location, then falls back to the legacy
  ~/.projector/projector-config.toml.
- When config is found only at the legacy location, it is copy-migrated to
  the new location (legacy file left in place for older pj binaries) and a
  message is printed to stdout.
- Save always targets the new location.

ConfigDir/ConfigFilePath now honor $XDG_CONFIG_HOME. Added tests for
resolution order, migration, XDG override, and the no-config case. Updated
docs (commands.md, CLAUDE.md, pj-skill.md) and the config command help text.

Closes #22

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Keeps stdout clean for machine-readable commands like `pj path`
and `pj config get`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@kevdoran
kevdoran merged commit 2e493f7 into main Jun 23, 2026
2 checks passed
@kevdoran
kevdoran deleted the xdg-config-location branch June 23, 2026 00:29
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.

Change default global config location

1 participant