Skip to content

[WIP] respect XDG Base Directory Specification for config, data, and cache#1963

Draft
dgageot wants to merge 1 commit intodocker:mainfrom
dgageot:xdg
Draft

[WIP] respect XDG Base Directory Specification for config, data, and cache#1963
dgageot wants to merge 1 commit intodocker:mainfrom
dgageot:xdg

Conversation

@dgageot
Copy link
Member

@dgageot dgageot commented Mar 6, 2026

Implement XDG Base Directory Specification support so that cagent stores files in the standard platform directories instead of everything under ~/.cagent:

  • Config: $XDG_CONFIG_HOME/cagent (default ~/.config/cagent)
  • Data: $XDG_DATA_HOME/cagent (default ~/.local/share/cagent)
  • Cache: $XDG_CACHE_HOME/cagent (default ~/.cache/cagent)

This is a work in progress because working on this is a good opportunity to use the new docker-agent name but I didn't yet take the time to do it.

Closes #1638

@dgageot dgageot requested a review from a team as a code owner March 6, 2026 10:57
@dgageot dgageot marked this pull request as draft March 6, 2026 10:58
Copy link

@docker-agent docker-agent bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

Assessment: 🟡 NEEDS ATTENTION

This PR implements XDG Base Directory Specification support with legacy fallback. I found 1 CONFIRMED and 1 LIKELY bug in error handling and migration logic:

  • CONFIRMED: Store silently falls back to /tmp when home directory unavailable, risking data loss on reboot
  • LIKELY: History migration may fail to find legacy data if XDG directory exists but is empty

Both issues relate to the migration path and error handling during the transition from ~/.cagent to XDG directories.


This is an automated review. All findings have been verified against the actual diff.

}

store.baseDir = filepath.Join(homeDir, ".cagent", "store")
store.baseDir = filepath.Join(paths.GetDataDir(), "store")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 CONFIRMED BUG - Error Handling Degradation

The new code calls paths.GetDataDir() without error handling. If os.UserHomeDir() fails, GetDataDir() silently falls back to filepath.Join(os.TempDir(), ".cagent"), creating the store under /tmp/.cagent/store.

Impact: On systems where /tmp is cleared on reboot, stored artifacts will be lost, causing unexpected re-downloads. The old code explicitly returned the error, allowing callers to handle the failure appropriately.

Recommendation: Either:

  1. Make GetDataDir() return an error and handle it here, OR
  2. Add explicit validation that the returned path is not under os.TempDir() and fail with a clear error message

Failing fast is better than silently using an ephemeral location for persistent data.

func (h *History) migrateOldHistory(homeDir string) error {
oldPath := filepath.Join(homeDir, ".cagent", "history.json")
func (h *History) migrateOldHistory(dataDir string) error {
oldPath := filepath.Join(dataDir, "history.json")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 LIKELY BUG - Migration Path Issue

The migrateOldHistory function looks for history.json at filepath.Join(dataDir, "history.json"), where dataDir comes from paths.GetDataDir().

Problem: If the XDG directory exists but is empty (e.g., created manually or by another component), GetDataDir() returns the XDG path instead of the legacy path. The migration then looks for history.json in the empty XDG directory instead of the legacy ~/.cagent/ directory, failing to find and migrate the user's existing history.

Recommendation: The migration should explicitly check the legacy directory for history.json, regardless of which path GetDataDir() returns:

legacyHistoryPath := filepath.Join(legacyDir(), "history.json")
if _, err := os.Stat(legacyHistoryPath); err == nil {
    // migrate from legacy location
}

This ensures migration always checks the legacy location first.

…cache

Implement XDG Base Directory Specification support so that cagent stores
files in the standard platform directories instead of everything under
~/.cagent:

- Config: $XDG_CONFIG_HOME/cagent (default ~/.config/cagent)
- Data:   $XDG_DATA_HOME/cagent   (default ~/.local/share/cagent)
- Cache:  $XDG_CACHE_HOME/cagent  (default ~/.cache/cagent)

For backward compatibility, if the legacy ~/.cagent directory exists and
the new XDG directory does not, the legacy path is used automatically.

Changes:
- pkg/paths: Rewrite GetDataDir, GetConfigDir, GetCacheDir to resolve
  XDG paths with legacy fallback
- pkg/modelsdev: Use paths.GetCacheDir() instead of hardcoded ~/.cagent
- pkg/content: Use paths.GetDataDir() instead of hardcoded ~/.cagent/store
- pkg/gateway: Use paths.GetCacheDir() instead of hardcoded ~/.cagent
- pkg/history: Use paths.GetDataDir() instead of hardcoded ~/.cagent;
  WithBaseDir now takes a data dir directly
- cmd/root: Session DB default now uses paths.GetDataDir()
- Updated help text and comments to reference XDG dirs

Closes docker#1638

Assisted-By: cagent
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.

Add support for XDG spec

1 participant