[WIP] respect XDG Base Directory Specification for config, data, and cache#1963
[WIP] respect XDG Base Directory Specification for config, data, and cache#1963dgageot wants to merge 1 commit intodocker:mainfrom
Conversation
There was a problem hiding this comment.
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
/tmpwhen 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") |
There was a problem hiding this comment.
🔴 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:
- Make
GetDataDir()return an error and handle it here, OR - 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") |
There was a problem hiding this comment.
🟠 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
Implement XDG Base Directory Specification support so that cagent stores files in the standard platform directories instead of everything under ~/.cagent:
This is a work in progress because working on this is a good opportunity to use the new
docker-agentname but I didn't yet take the time to do it.Closes #1638