facet CLI how to install assets into a specific AI coding tool. The first-party adapters cover Claude Code, OpenCode, and Codex; this guide shows how to build your own using the @agent-facets/adapter SDK.
An adapter is a small TypeScript library. You write one file, build it, and install it locally — from a directory, from GitHub, or (once published) by name.
How an adapter fits in
When you runfacet install, the CLI reads each facet’s assets and hands them to every installed adapter. The adapter decides where on disk each asset goes and how it’s formatted, so the target tool picks it up. That’s the entire job: translate a facet asset into files your tool understands.An adapter implements a small contract from the SDK. Two methods matter most:buildAssetMetadatavalidates the per-asset metadata an author put infacet.json(theadapters.<name>block) and enriches it with your defaults.installAssetwrites the asset to disk. Its siblingsreadAssetanddeleteAssetcomplete the lifecycle.
Scaffold the package
1
Create a package and add the SDK
@agent-facets/common (the shared types) is bundled into it, so you don’t install anything else.2
Write the adapter
Create
src/index.ts and default-export a defineAdapter call. Here is a minimal, working adapter that writes each asset to ~/.my-tool/<type>s/<name>.md:src/index.ts
installAssetFile, readAssetFile, and deleteAssetFile are SDK helpers that manage YAML front-matter, create parent directories, and stay byte-stable across a write→read round-trip. Use them instead of hand-rolling file I/O so re-installs don’t report phantom drift.The adapter contract
Everything an adapter can implement, from@agent-facets/adapter:string
required
A unique id (e.g.
my-tool). Users install and reference the adapter by this name.Validated<AdapterMetadata>
required
Validate and enrich the per-asset metadata from a facet’s
adapters.<name> block. Return { ok: true, data } or { ok: false, errors }. Runs during facet build, so bad config is caught early.boolean
Set to
true only when all three I/O methods below are implemented. It makes the adapter selectable in the install picker; a metadata-only adapter omits it and stays hidden.Promise<string | undefined>
Write the asset to disk. Return the absolute path (for verbose logs) or
undefined.Promise<{ content, metadata }>
Read an asset back from disk.
Promise<string | undefined>
Remove an asset. Return its path or
undefined.scope is 'system', 'user', or 'project' (decide your on-disk layout per scope), and assetType is 'skill', 'agent', or 'command'.Bundle it
facet adapter install re-bundles your adapter into a self-contained adapter.js, but it needs a clean single-module entry to start from. Compile your package first — for example with tsdown (what the first-party adapters use) or tsc:package.json exports/main at the compiled entry so the CLI can resolve it.Install your adapter
facet adapter install accepts your adapter three ways:adapter.js, verifies it exports a valid adapter, and places it in $FACET_DIR/adapters/<name>/ (default ~/.facet). See facet adapter install for every specifier format.Verify it works
Confirm the adapter is registered, then install a facet to see it materialize assets:assetPath puts them. From here, harden buildAssetMetadata with a real schema and flesh out the on-disk layout your tool expects.Share it upstream
Built an adapter for a major AI coding assistant? Contributions are welcome. If your adapter targets a widely used tool, open a pull request on thefacets repository to share it upstream as a first-party adapter.A first-party adapter is installable by name (facet adapter install <name>) via the CLI, so everyone using that tool benefits.