@slats/claude-assets-sync
CLI tool to sync Claude commands and skills from npm packages to your project's .claude/ directory.
yarn add @slats/claude-assets-sync@slats/agents-assets-syncThis engine was migrated to @slats/agents-assets-sync,
which injects one asset tree into Claude Code, Codex, and the vendor-neutral
.agents layout. Releases published under this name stay on npm and keep
working, but nothing new ships here — new packages declare agents.assetPath
and use the current engine. What follows documents the released
claude.assetPath contract.
Allows npm package authors to distribute Claude Code commands and skills alongside their packages.
When users install these packages, they can sync the assets to their local .claude/ directory for immediate use.
- Multi-package sync in a single command
- Version tracking — skips re-sync when version is unchanged
- Flat file structure with prefixed filenames (default)
- Interactive add/list UI (ink-based terminal UI)
- Status monitoring with npm registry update checks
- Dry-run mode to preview changes before applying
- Legacy nested structure support and migration tool
Installation
# One-time use (recommended)
npx @slats/claude-assets-sync -p @canard/schema-form
# Global install
npm install -g @slats/claude-assets-sync
Commands
sync (default)
Sync Claude assets from one or more npm packages.
npx @slats/claude-assets-sync [options] -p <package>
| Option | Description |
|---|---|
-p, --package <name> | Package to sync (repeatable) |
-f, --force | Force sync even if version matches |
--dry-run | Preview changes without writing files |
-l, --local | Read from local workspace instead of node_modules |
-r, --ref <ref> | Git ref (branch, tag, commit) to fetch from |
--no-flat | Use legacy nested directory structure |
# Sync a single package
npx @slats/claude-assets-sync -p @canard/schema-form
# Sync multiple packages
npx @slats/claude-assets-sync -p @canard/schema-form -p @lerx/promise-modal
# Preview without writing
npx @slats/claude-assets-sync -p @canard/schema-form --dry-run
# Force re-sync
npx @slats/claude-assets-sync -p @canard/schema-form --force
# Sync from a specific branch
npx @slats/claude-assets-sync -p @canard/schema-form -r main
add
Add a package with interactive file selection (TTY).
npx @slats/claude-assets-sync add -p <package> [options]
| Option | Description |
|---|---|
-p, --package <name> | Package to add (required) |
-l, --local | Read from local workspace |
-r, --ref <ref> | Git ref to fetch from |
Keyboard controls in interactive mode:
| Key | Action |
|---|---|
↑ / ↓ | Navigate items |
Space | Toggle selection |
→ / ← | Expand / collapse directory |
Enter | Confirm and sync |
a | Select all |
n | Deselect all |
q | Cancel |
npx @slats/claude-assets-sync add -p @lerx/promise-modal
list
List all synced packages with an interactive tree view.
npx @slats/claude-assets-sync list [--json]
View mode keys: e edit, r refresh, q quit
Edit mode keys: d delete file, a add file, Esc exit edit
# Interactive tree view
npx @slats/claude-assets-sync list
# JSON output for scripting
npx @slats/claude-assets-sync list --json
┌─ Synced Packages ─────────────────────────────┐
│ │
│ ▼ @canard/schema-form@1.0.0 │
│ ├─ commands/ │
│ │ └─ @canard-schema-form-my-command.md │
│ └─ skills/ │
│ └─ @canard-schema-form-my-skill.md │
│ │
│ [e] Edit [r] Refresh [q] Quit │
└───────────────────────────────────────────────┘
status
Show sync status and check for available updates.
npx @slats/claude-assets-sync status [--no-remote]
| Option | Description |
|---|---|
--no-remote | Skip npm registry check |
Status indicators: ✓ up-to-date, ⚠ update available, ✗ error
┌─ Package Status ──────────────────────────────┐
│ ✓ @canard/schema-form │
│ Local: 1.0.0 Synced: 1.0.0 Assets: 2 │
│ ⚠ @lerx/promise-modal │
│ Local: 0.6.0 Synced: 0.5.0 │
├─ Summary ────────────────────────────────────┤
│ Total: 2 ✓ 1 ⚠ 1 │
└───────────────────────────────────────────────┘
remove
Remove a synced package and its assets.
npx @slats/claude-assets-sync remove -p <package> [--yes] [--dry-run]
npx @slats/claude-assets-sync remove -p @canard/schema-form --yes
migrate
Migrate from legacy nested structure to flat structure.
npx @slats/claude-assets-sync migrate [--dry-run]
Directory Structure
Flat (default)
your-project/
└── .claude/
├── commands/
│ ├── @canard-schema-form-my-command.md
│ └── @lerx-promise-modal-another-command.md
└── skills/
├── @canard-schema-form-my-skill.md
└── @lerx-promise-modal-another-skill.md
A single .sync-meta.json tracks all packages in each asset directory.
Nested (legacy, --no-flat)
your-project/
└── .claude/
├── commands/
│ └── @canard/schema-form/
│ ├── my-command.md
│ └── .sync-meta.json
└── skills/
└── @lerx/promise-modal/
├── my-skill.md
└── .sync-meta.json
.sync-meta.json
{
"version": "0.0.1",
"syncedAt": "2025-02-05T10:30:00.000Z",
"packages": {
"@canard-schema-form": {
"originalName": "@canard/schema-form",
"version": "1.0.0",
"files": {
"commands": [
{
"original": "my-command.md",
"transformed": "@canard-schema-form-my-command.md"
}
],
"skills": [
{
"original": "my-skill.md",
"transformed": "@canard-schema-form-my-skill.md"
}
]
}
}
}
}
Environment Variables
| Variable | Description | Default |
|---|---|---|
GITHUB_TOKEN | GitHub personal access token (raises rate limit to 5,000 req/hr) | unauthenticated (60 req/hr) |
VERBOSE | Enable debug logging | disabled |
GITHUB_TOKEN=ghp_xxxxxxxxxxxx npx @slats/claude-assets-sync -p @package1 -p @package2
For Package Authors
Add a claude field to your package.json and place assets under the declared path:
{
"name": "@your-scope/your-package",
"version": "1.0.0",
"repository": {
"type": "git",
"url": "https://github.com/your-org/your-repo.git",
"directory": "packages/your-package"
},
"claude": {
"assetPath": "docs/claude"
}
}
your-package/
└── docs/claude/
├── commands/
│ └── your-command.md
└── skills/
└── your-skill.md
- Asset files must be Markdown (
.md) repository.typeandrepository.urlare requiredassetPathis relative to the package root
Sync Flow
1. Read package.json from node_modules (or local workspace)
2. Extract claude.assetPath
3. Parse repository URL → GitHub owner/repo
4. Compare version against .sync-meta.json (skip if unchanged, unless --force)
5. Fetch file list from GitHub API (commands/ and skills/ under assetPath)
6. Download each file from raw.githubusercontent.com
7. Write to .claude/{type}/{prefixed-name}.md
8. Update .sync-meta.json
Programmatic API
import { syncPackage, syncPackages } from '@slats/claude-assets-sync';
import type { CliOptions, SyncResult } from '@slats/claude-assets-sync';
// Sync a single package
const result: SyncResult = await syncPackage('@canard/schema-form', {
force: false,
dryRun: false,
flat: true,
});
// Sync multiple packages
const results = await syncPackages(
['@canard/schema-form', '@lerx/promise-modal'],
{
force: true,
},
);
AI Agent Reference
AI Reference
Package: @slats/claude-assets-sync v0.0.6
Purpose: Claude Code asset synchronization CLI tool.
Exports
import { syncPackage } from '@slats/claude-assets-sync';
import { syncPackages } from '@slats/claude-assets-sync';
import { createProgram } from '@slats/claude-assets-sync';
import { run } from '@slats/claude-assets-sync';
import { migrateToFlat } from '@slats/claude-assets-sync';
import { needsMigration } from '@slats/claude-assets-sync';
import type { MigrationResult } from '@slats/claude-assets-sync';
import type { AssetType } from '@slats/claude-assets-sync';
import type { CliOptions } from '@slats/claude-assets-sync';
import type { ClaudeConfig } from '@slats/claude-assets-sync';
import type { GitHubRepoInfo } from '@slats/claude-assets-sync';
import type { PackageInfo } from '@slats/claude-assets-sync';
import type { SyncMeta } from '@slats/claude-assets-sync';
import type { SyncResult } from '@slats/claude-assets-sync';
import type { UnifiedSyncMeta } from '@slats/claude-assets-sync';
import type { PackageSyncInfo } from '@slats/claude-assets-sync';
import type { FileMapping } from '@slats/claude-assets-sync';