@slats/agents-assets-sync
CLI engine that injects a package's agent docs (skills, rules, commands) into Claude Code and Codex asset locations.
yarn add @slats/agents-assets-syncA 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]
| Flag | Meaning |
|---|---|
--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. |
--scope | user (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-run | Print the plan; write nothing. |
--force | Overwrite diverged content and delete orphans. |
--yes | Approve the confirmation without showing it. |
--no-interactive | Never prompt, even on a terminal. |
Agent destinations
Every agent resolves from one shared project root, so a single run cannot straddle two projects.
| Kind | claude | codex | agents |
|---|---|---|---|
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 reason | unsupported |
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';