Does the Skills CLI Support XDG Base Directory Specification for Skill Storage Paths?

Yes, the Vercel Labs skills CLI fully respects the XDG Base Directory specification, storing its global lock file at $XDG_STATE_HOME/skills/.skill-lock.json when the environment variable is set, with automatic fallback to ~/.agents/.skill-lock.json when it is not.

The vercel-labs/skills repository provides a command-line interface for managing AI agent skills. Understanding how this tool handles configuration paths is essential for users who follow modern Linux desktop standards and want to keep their home directories clean.


How Skills CLI Implements XDG Base Directory Support

The XDG Base Directory specification defines standard locations for user-specific data files, configuration files, and runtime files. The skills CLI specifically uses XDG_STATE_HOME for its persistent state data.

Primary XDG Implementation in src/skill-lock.ts

The core logic resides in src/skill-lock.ts, where the getSkillLockPath() helper determines the correct storage location:

// From src/skill-lock.ts (lines 63-68)
function getSkillLockPath(): string {
  const xdgStateHome = process.env.XDG_STATE_HOME;
  if (xdgStateHome) {
    return path.join(xdgStateHome, 'skills', '.skill-lock.json');
  }
  return path.join(os.homedir(), '.agents', '.skill-lock.json');
}

This implementation follows the XDG specification precisely:

  • Checks XDG_STATE_HOME first
  • Creates a skills subdirectory within the state home
  • Uses a hidden file name .skill-lock.json for the lock file
  • Falls back to the legacy ~/.agents/ directory only when necessary

CLI Integration in src/cli.ts

The main command-line interface in src/cli.ts leverages the same XDG-aware logic at line 311 when executing commands like skills add, skills check, or skills update:

// From src/cli.ts (line 311)
const lockPath = getSkillLockPath();
// Used for reading/writing skill lock state during CLI operations

This ensures consistent path resolution across all skill management operations, whether the user has explicitly configured XDG directories or not.


Verifying XDG Base Directory Behavior

The skills CLI includes comprehensive test coverage for XDG path handling in tests/xdg-config-paths.test.ts.

Test Coverage for XDG State Home

Lines 71-78 verify that the CLI correctly uses XDG_STATE_HOME when available:

// From tests/xdg-config-paths.test.ts (lines 71-78)
test('uses XDG_STATE_HOME when set', () => {
  const customState = '/custom/state/dir';
  process.env.XDG_STATE_HOME = customState;
  
  const lockPath = getSkillLockPath();
  
  expect(lockPath).toBe('/custom/state/dir/skills/.skill-lock.json');
  expect(lockPath).not.toContain('.agents');
});

Fallback Verification

The same test file confirms proper fallback behavior when XDG_STATE_HOME is unset, ensuring backward compatibility for existing users.

Scope Protection for Non-XDG Agents

Lines 82-88 demonstrate that the XDG handling is intentionally scoped and does not override agent-specific paths for tools like Cursor or Cline that use their own historic directories:

// From tests/xdg-config-paths.test.ts (lines 82-88)
test('non-XDG agents use home-based paths', () => {
  process.env.XDG_STATE_HOME = '/xdg/path';
  
  // Cursor and Cline ignore XDG_STATE_HOME
  const cursorPath = getAgentConfigPath('cursor');
  expect(cursorPath).toBe(path.join(os.homedir(), '.cursor', 'skills.json'));
});

Practical Usage Examples

Using XDG_STATE_HOME with Skills CLI

Configure your environment to use XDG-compliant paths:


# Add to ~/.bashrc, ~/.zshrc, or equivalent

export XDG_STATE_HOME="$HOME/.local/state"

# Create the directory if it doesn't exist

mkdir -p "$XDG_STATE_HOME/skills"

# Now skills commands use XDG paths automatically

skills list
skills add my-skill

Checking Your Current Configuration


# See where skills stores its lock file

XDG_STATE_HOME=/custom/path skills list --verbose

# Or inspect programmatically

node -e "console.log(require('./src/skill-lock').getSkillLockPath())"

Programmatic Access in Node.js

import { getSkillLockPath } from 'skills/src/skill-lock';

// Returns path based on current environment
const lockPath = getSkillLockPath();
console.log('Skills lock file:', lockPath);

// Example output with XDG_STATE_HOME set:
// /home/user/.local/state/skills/.skill-lock.json

// Example output without XDG_STATE_HOME:
// /home/user/.agents/.skill-lock.json

Summary

The Vercel Labs skills CLI provides complete XDG Base Directory specification support for skill storage paths:

  • Primary XDG variable: Uses XDG_STATE_HOME when defined, following the specification for state data
  • Lock file location: Stores .skill-lock.json at $XDG_STATE_HOME/skills/.skill-lock.json
  • Backward compatibility: Falls back to ~/.agents/.skill-lock.json when XDG_STATE_HOME is unset
  • Implementation files: Core logic in src/skill-lock.ts, CLI integration in src/cli.ts
  • Verified behavior: Comprehensive test coverage in tests/xdg-config-paths.test.ts confirms correct path resolution and fallback handling

Frequently Asked Questions

What is the XDG Base Directory specification?

The XDG Base Directory specification is a standard that defines where user-specific data files, configuration files, and runtime files should be placed on Linux and Unix-like systems. It aims to reduce clutter in the home directory by using specific environment variables like XDG_STATE_HOME for state data, XDG_CONFIG_HOME for configuration, and XDG_CACHE_HOME for cached files.

How do I configure skills CLI to use XDG paths?

You don't need to configure anything manually. Simply set the XDG_STATE_HOME environment variable in your shell configuration, and the skills CLI will automatically detect and use it. For example, add export XDG_STATE_HOME="$HOME/.local/state" to your ~/.bashrc or ~/.zshrc file, create the directory with mkdir -p "$XDG_STATE_HOME/skills", and the CLI will store its lock file at that location.

Does skills CLI migrate existing data when switching to XDG paths?

No, the skills CLI does not automatically migrate existing data when you switch from the legacy ~/.agents/ path to an XDG-compliant path. The fallback mechanism simply checks for XDG_STATE_HOME and uses it if present, otherwise it uses the legacy path. If you have existing skills installed in ~/.agents/.skill-lock.json and want to migrate to XDG paths, you would need to manually move or copy that file to the new $XDG_STATE_HOME/skills/ directory after setting the environment variable.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →