Skip to main content

@slats/agents-assets-sync

CLI engine that injects a package's agent docs (skills, rules, commands) into Claude Code and Codex asset locations.

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

A package author authors one asset tree and declares where it lives. End users pick which agents to inject for, and the engine writes each asset where that agent actually reads it.

Every choice is reachable by flag, so a coding agent can drive a whole run without a prompt.

Installation

The engine is never a runtime dependency of a consumer, so end users invoke it through npx:

npx @slats/agents-assets-sync \
--package=@canard/schema-form \
--agent=claude,codex \
--scope=project

CLI Surface

<bin> --package <name...> [--agent <type...>] [--scope=user|project] [--asset <kind...>]
[--dry-run] [--force] [--yes] [--no-interactive] [--root=<cwd>] [--json]
FlagMeaning
--package <name>Required. @scope/pkg, pkg, or a scope alias @scope that fans out to every installed package declaring agents.assetPath.
--agent <type>claude | codex | agents. Omitted, an interactive terminal asks; anywhere else the run exits 2.
--scopeuser (home) or project (nearest ancestor owning .claude, AGENTS.md, .agents, .codex or .git).
--asset <kind>skills | rules | commands. Default: all. An excluded kind is absent from the plan, so it is neither reported nor deleted.
--dry-runPrint the plan; write nothing.
--forceOverwrite diverged content and delete orphans.
--yesApprove the confirmation without showing it.
--no-interactiveNever prompt, even on a terminal.

Agent destinations

Every agent resolves from one shared project root, so a single run cannot straddle two projects.

Kindclaudecodexagents
skills (user)~/.claude/skills/**~/.codex/skills/**~/.agents/skills/**
skills (project)<root>/.claude/skills/**<root>/.agents/skills/**<root>/.agents/skills/**
rules (user)~/.claude/rules/**~/.codex/AGENTS.md~/.agents/AGENTS.md
rules (project)<root>/.claude/rules/**<root>/AGENTS.md<root>/AGENTS.md
commands<root>/.claude/commands/**unsupported — skipped with a reasonunsupported

agents is not a product: it is the vendor-neutral .agents convention, for tools that read it instead of keeping a home of their own. It differs from codex only at user scope.

One rule file becomes one marker block, so its body hash equals the manifest hash for that file and the copy/skip/diverged verdict is as precise as it is for a copied file:

<!-- AGENTS-ASSETS-SYNC:START:@canard/schema-form:rules/schema-form-rule.md -->
…source bytes, verbatim…
<!-- AGENTS-ASSETS-SYNC:END:@canard/schema-form:rules/schema-form-rule.md -->

Everything outside this tool's own blocks — other tools' blocks, hand-written prose — is carried through byte for byte.

Shipping assets from your package

{
"scripts": {
"build": "… && yarn build:hashes",
"build:hashes": "agents-build-hashes",
},
"devDependencies": {
"@slats/agents-assets-sync": "^0.1.0",
},
"files": ["dist", "docs", "README.md"],
"agents": {
"assetPath": "docs/agents",
},
}
docs/agents/
├── skills/<skill-name>/SKILL.md
├── rules/*.md
└── commands/*.md

agents-build-hashes hashes the tree at build time into dist/agents-hashes.json, which the engine compares against on every inject.

Relationship to @slats/claude-assets-sync

@slats/claude-assets-sync is the single-agent name this engine was migrated from. Its published releases stay on npm, so packages released against its claude.assetPath contract keep installing and working — but nothing new ships under that name. Declare agents.assetPath and use this engine.

AI Agent Reference

AI Reference

Package: @slats/agents-assets-sync v0.1.2 Purpose: AI agent asset injection CLI engine.

Exports

import { runCli } from '@slats/agents-assets-sync';
import { HASH_MANIFEST_FILENAME } from '@slats/agents-assets-sync';
import { MARKER_PREFIX } from '@slats/agents-assets-sync';
import { PROJECT_ANCHORS } from '@slats/agents-assets-sync';
import { computeNamespacePrefixes } from '@slats/agents-assets-sync';
import { formatBlockId } from '@slats/agents-assets-sync';
import { isValidAgent } from '@slats/agents-assets-sync';
import { isValidScope } from '@slats/agents-assets-sync';
import { parseBlocks } from '@slats/agents-assets-sync';
import { readHashManifest } from '@slats/agents-assets-sync';
import { resolveAgentTarget } from '@slats/agents-assets-sync';
import { resolveDestinations } from '@slats/agents-assets-sync';
import { resolveProjectRoot } from '@slats/agents-assets-sync';
import type { AgentTarget } from '@slats/agents-assets-sync';
import type { AgentType } from '@slats/agents-assets-sync';
import type { AssetKind } from '@slats/agents-assets-sync';
import type { Destination } from '@slats/agents-assets-sync';
import type { HashManifest } from '@slats/agents-assets-sync';
import type { InjectReport } from '@slats/agents-assets-sync';
import type { OrphanScan } from '@slats/agents-assets-sync';
import type { ProjectRootResolution } from '@slats/agents-assets-sync';
import type { Scope } from '@slats/agents-assets-sync';
import type { AssetType } from '@slats/agents-assets-sync';