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

> Discover if the skills CLI supports XDG Base Directory for skill storage. Learn how it uses $XDG_STATE_HOME or falls back to ~/.agents for seamless configuration management.

- Repository: [Vercel Labs/skills](https://github.com/vercel-labs/skills)
- Tags: how-to-guide
- Published: 2026-04-23

---

**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](https://github.com/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`](https://github.com/vercel-labs/skills/blob/main/src/skill-lock.ts)

The core logic resides in [`src/skill-lock.ts`](https://github.com/vercel-labs/skills/blob/main/src/skill-lock.ts), where the `getSkillLockPath()` helper determines the correct storage location:

```typescript
// 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`](https://github.com/vercel-labs/skills/blob/main/.skill-lock.json) for the lock file
- Falls back to the legacy `~/.agents/` directory only when necessary

### CLI Integration in [`src/cli.ts`](https://github.com/vercel-labs/skills/blob/main/src/cli.ts)

The main command-line interface in [`src/cli.ts`](https://github.com/vercel-labs/skills/blob/main/src/cli.ts) leverages the same XDG-aware logic at line 311 when executing commands like `skills add`, `skills check`, or `skills update`:

```typescript
// 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`](https://github.com/vercel-labs/skills/blob/main/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:

```typescript
// 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:

```typescript
// 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:

```bash

# 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

```bash

# 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

```typescript
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`](https://github.com/vercel-labs/skills/blob/main/.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`](https://github.com/vercel-labs/skills/blob/main/src/skill-lock.ts), CLI integration in [`src/cli.ts`](https://github.com/vercel-labs/skills/blob/main/src/cli.ts)
- **Verified behavior**: Comprehensive test coverage in [`tests/xdg-config-paths.test.ts`](https://github.com/vercel-labs/skills/blob/main/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.