Skip to main content

@slats/claude-assets-sync

CLI tool to sync Claude commands and skills from npm packages to your project's .claude/ directory.

@slats/claude-assets-sync npm versionlicense
yarn add @slats/claude-assets-sync

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>
OptionDescription
-p, --package <name>Package to sync (repeatable)
-f, --forceForce sync even if version matches
--dry-runPreview changes without writing files
-l, --localRead from local workspace instead of node_modules
-r, --ref <ref>Git ref (branch, tag, commit) to fetch from
--no-flatUse 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]
OptionDescription
-p, --package <name>Package to add (required)
-l, --localRead from local workspace
-r, --ref <ref>Git ref to fetch from

Keyboard controls in interactive mode:

KeyAction
/ Navigate items
SpaceToggle selection
/ Expand / collapse directory
EnterConfirm and sync
aSelect all
nDeselect all
qCancel
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]
OptionDescription
--no-remoteSkip 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

VariableDescriptionDefault
GITHUB_TOKENGitHub personal access token (raises rate limit to 5,000 req/hr)unauthenticated (60 req/hr)
VERBOSEEnable debug loggingdisabled
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.type and repository.url are required
  • assetPath is 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';