Skip to main content
CLIBreakingNew Feature
Resolve name collisions between facets; manifest 0.1, lockfile 0.3, and asset aliasing

Two facets, one name

Facets are published independently, so sooner or later two of them ship an asset with the same name. Until now the second one quietly overwrote the first. Now facet add and facet install detect every collision across the whole project before writing anything, and stop.In a terminal, the install pauses and hands you the decision:
Give each contested asset one of three outcomes — Keep it under the published name, Alias it to a name you choose, or Omit it entirely. Only one of them has to change; the names just have to differ from each other.What this means for you:
  • Nothing is written until you decide. A collision leaves facets.json, facets.lock, the receipt, and your materialized assets byte-identical. Cancelling with Esc ends the command without applying anything — it reports the cancellation and exits non-zero, and your project is exactly as you left it.
  • You decide once. Your choices are saved into facets.json, so the next install — and every teammate’s, and CI’s — replays them without prompting.
  • No tool picks a winner. Not the CLI, not the registry, not the facet authors. A silent winner means a silently discarded asset.

Alias or omit any asset

The same mechanism works without a collision. A facet entry can carry a materialization block naming, per asset, what you want:
facets.json
  • Aliasing renames the file, nothing else. Archive paths, per-file integrity, and the lockfile all keep the publisher’s authored name. That is what makes an alias safe: it can never be used to smuggle different content in under a familiar name.
  • Omitted assets are still verified. They are resolved, hashed, and recorded in the lockfile — they are just never written to disk. Dropping them from the lockfile would make an omission indistinguishable from a facet that never published the asset.
  • Skills and commands share one namespace, agents have their own. A skill deploy and a command deploy collide; an agent deploy coexists with both.
See Materialization for the full model.

Breaking: facets.json entries may be objects

facets.json now carries a manifestVersion (currently 0.1), and a facet entry is either a source string or an object with source and materialization:
facets.json
If you have tooling that reads facets.json, it must handle both forms. Code that assumes every value is a string will render an expanded entry as [object Object] — or, worse, destroy a recorded alias when it rewrites the file.A manifest with no manifestVersion is still read as the legacy format and is migrated in place on the next successful install. There is no separate migration command and nothing to run.

Breaking: lockfile 0.3 (and receipt 0.3)

Every asset entry in facets.lock now carries a required materialization disposition — authored, aliased, or omitted. Version 0.2 remains readable and is migrated to 0.3 by any normal install. The withdrawn closed-alpha 1 is no longer read at all: if you still have one, delete facets.lock and run facet install to regenerate it. The number 1 is reserved for the eventual stable v1 format.The machine-local install receipt moves to 0.3 alongside it, so it can record the disposition each asset was materialized under. It migrates itself on the next install and lives outside your repository, so there is nothing to commit and nothing to run.
facets.lock
Note name and files keep the authored name even when aliased. Versions are matched exactly, never by ordering: a version number names a schema rather than a position in a sequence, so a reader recognizes the versions it supports and fails on anything else instead of comparing magnitudes.Each asset’s files are also checked against the asset itself now, not just for path safety: an agent or command lists exactly its own primary file, and every path in a skill lives under that skill’s directory. A lockfile that pointed an asset at an unrelated file no longer validates.In CI: a --frozen-lockfile install fails if facets.json declares any materialization override while facets.lock is still at 0.2, which has no field in which to record it. Run one normal facet install locally and commit the migrated lockfile. Frozen mode also treats a changed alias as drift, exactly like a changed version, and never prompts.

The install pipeline resolves everything before writing anything

Commit used to be an interleaved loop — resolve facet A, write it, then start facet B. Detecting that A and Z want the same name is impossible that way, because A is already on disk.It now runs in three phases: Resolve-all, Compose, then Apply. The first two are read-only, which is why a collision, an invalid alias, or a cancelled resolution leaves the project untouched rather than rolled back. Deletion also moved to the start of Apply, before any write, so an asset name can transfer from one facet to another in a single install without the new owner’s file being deleted behind it.Removing a facet is the exception. When your machine’s install receipt already accounts for everything you are keeping, facet remove refines those lockfile entries in place instead of resolving them, so it still works with a cold cache and an unreachable registry.Two smaller consequences you may notice:
  • Disposition changes report as updated. Aliasing an asset at an unchanged version is a real change to what is on disk, not a no-op and not a repair.
  • Stale choices are pruned and reported. If you upgrade a facet and the publisher removed an asset you had aliased, the override is dropped on a successful install and the CLI tells you which one.

Breaking: only your install receipt authorizes deletion

facets.lock is shared, version-controlled state. It says what should be materialized — not what your machine actually wrote — so it is no longer treated as proof of ownership. Deletion is driven by the machine-local install receipt alone.Two rules replace the old fallback:
  • Your project’s desired state authorizes writes. An install still materializes every declared asset, overwriting an unmanaged file that happens to occupy the same name. (If what is already there matches byte for byte, it is adopted without a rewrite.) Either way the file is tracked from then on.
  • The receipt authorizes deletions. Files the CLI has no record of writing are never deleted.
What you may notice:
  • Pull a teammate’s facets.lock onto a machine that never ran an install, then facet remove the facet: facets.json and facets.lock drop it and the files stay exactly where they are. The summary says so instead of reporting a cleanup that did not happen, and those files are then yours to delete by hand.
  • facet remove may need the network. The offline guarantee is a property of tracked state, not of removal. If a facet you are keeping is not fully accounted for by your receipt, the removal runs the ordinary pipeline to materialize it before claiming it — which succeeds when the content is reachable and fails, deleting nothing, when it is not. Run facet install first to take ownership.
  • An unusable receipt is reported. Unreadable, or recorded against a different project: nothing on disk is tracked, so nothing is cleaned up, and the run records only what it materializes.

Breaking: facet remove decides what is declared under the lock

Whether a name is declared is now answered by the commit, holding the project lock, instead of by a read taken before it. A pre-lock read can be stale, and acting on one let a facet added by a concurrent process survive the removal that asked for it.So facet remove ghost in a project with no adapter opens the picker in a terminal and exits non-zero in CI, rather than printing a no-op summary it never verified. Names that really are absent under the lock are still ignored, and a removal whose names are all absent still succeeds. An unreadable facets.json is still reported as a manifest problem, before any adapter is discovered.

Adapter authors

The adapter contract is unchanged — no rebuild, no version bump. But request.name has always been, and now visibly is, the effective name: the name the consuming project chose. Address files by request.name and never re-derive a path from a facet’s manifest. See Custom adapters.
CLIBreakingNew Feature
Facets ship non-asset files; archive 0.2, per-file lockfiles, first-class README, and the 0.1 adapter contract

Facets can ship non-asset files

A facet is no longer just its assets. You can now declare supplementary files that travel inside the .facet archive and are integrity-protected like everything else:
  • Skill companions — files beside a SKILL.md (references, scripts, templates). They install and remove atomically with their skill, and files you add to a skill directory yourself are preserved on removal.
  • Top-level archive-only filesREADME.md, LICENSE, design notes. They ship in the archive but are never written to disk at install.
Declare them with exact paths (no globs) in the manifest’s top-level files array or a skill descriptor’s own files array:
See Supplementary files.

First-class README authoring

facet create now writes and declares an editable README.md by default (skip it with --no-readme), and facet edit has a dedicated README panel for creating, adopting, editing, or removing both README.md and the extensionless README.

Breaking: archive 0.2, per-file lockfiles, and naming

  • Archive format 0.2. Every build now emits facetVersion: 0.2 with a complete per-entry hash map covering every file, asset or not. Consumers still accept legacy 0.1 archives during the compatibility window; the two are dispatched by exact version match, never numeric ordering. An archive whose version your CLI doesn’t support fails with upgrade guidance — run facet self-update.
  • Lockfile 0.2. facets.lock records a per-file { path, integrity } record for every materialized file inside each asset, and install reconciles them before writing, reporting and repairing drift by exact path. A verified legacy alpha lockfile migrates automatically on a normal install. See Lockfile.
  • Asset names. Skill, command, and agent names are now single-segment Agent Skills names — slash-namespaced names like viper-plans/planning are no longer valid in new manifests (use viper-planning). Skills and commands now share one namespace and can’t reuse a name.
  • Primary files carry no front matter. Asset metadata lives in the manifest; a SKILL.md, agent, or command file with YAML front matter is now a build error. Supplementary files still ship verbatim.

Breaking: adapter API 0.00.1

The adapter contract advances from the positional single-file shape (0.0) to the tagged multi-file request/result contract (0.1) that carries skill companions. A 0.1 CLI treats a positional 0.0 adapter as unsupported and fails closed before any write. Rebuild against a 0.1 SDK and reinstall:
The archive facetVersion, the lockfile version, and the adapter API are three independent axes — a consumer classifies each separately. See Custom adapters.

Rollout

The change ships consumer-first: the protocol package publishes dual 0.1/0.2 verification, then the registry adopts it, then the adapter SDK and first-party adapters publish 0.1, and finally the CLI release turns on 0.2 production. Existing 0.0 CLIs keep selecting compatible 0.0 adapters until you update.
CLIImprovement
facet remove now prunes empty adapter directories

facet remove prunes empty adapter directories

Removing a facet now cleans up empty parent directories left behind in each connected adapter. When facet remove (or facet rm) deletes the last asset inside a nested folder — for example skills/<name>/SKILL.md under Claude Code or OpenCode — the CLI walks up and removes empty parent directories, stopping at (but not including) the adapter’s root.What this means for you:
  • Tidier working tree. Uninstalling a facet no longer leaves behind empty namespace folders that you’d otherwise have to delete by hand.
  • No configuration. The behavior is automatic for the Claude Code and OpenCode adapters — no flags, no opt-in.
  • Bounded to each adapter. Pruning stops at the adapter’s own root, so it can never walk into the rest of your project.
Ships in @agent-facets/adapter@0.26.0, @agent-facets/adapter-claude-code@0.7.0, and @agent-facets/adapter-opencode@0.8.0. Run facet self-update to pick it up.
CLIImprovementBreaking
Server-side search for facet search; asset names now follow the Agent Skills grammar
facet search now forwards your query term to the registry as the ?q= parameter on the facets endpoint and renders whatever the server returns, in order. The registry — not the CLI — owns relevance ranking, sorting, and paging.
What this means for you:
  • Results match the web UI. Ordering is consistent with what agentfacets.io shows, because both surfaces read the same server-ranked list.
  • Better matching, no upgrade required. Improvements to registry search (typo tolerance, ranking, new sort orders) take effect immediately — the CLI just displays what the server sends.
  • Old behavior removed. The client-side case-insensitive name substring filter is gone. If a term returns no matches on the server, the CLI now shows an empty result instead of falling back to local filtering.
See the facet search reference for usage.

Asset names now follow the Agent Skills grammar

Breaking: skill, command, and agent names declared in facet.json are now validated against the Agent Skills name grammar at both build and install time. Each /-separated segment must be:
  • 1–64 characters long
  • lowercase ASCII letters, digits, and hyphens only
  • no leading, trailing, or consecutive hyphens
Digit-start names like 2fa are now accepted; previously they were rejected. Non-conforming names like MySkill or foo_bar are now rejected — previously they slipped past the looser kebab-case check. Namespaced names like viper-plans/planning validate per segment.
Error messages now cite the specific rule that failed (e.g. "must be at most 64 characters") instead of a generic kebab-case hint.If you have a facet with a legacy non-kebab asset name, facet modify --update and facet modify --remove still accept the old name so you can rename or drop the asset without a chicken-and-egg problem. See the manifest schema and facet modify reference.
CLINew FeatureImprovementFix
Agent-friendly CLI: instructions, modify, headless create, build --verify; TypeScript 7 support; trailing newlines on generated JSON

TypeScript 7 support

The public @agent-facets/* packages now declare their typescript peer dependency as ^5 || ^6 || ^7, so they install cleanly on projects that have upgraded to TypeScript 7. Consumers still on TypeScript 5 or 6 are unaffected — no action needed.This applies to:
  • @agent-facets/protocol
  • @agent-facets/adapter
  • @agent-facets/brand
  • @agent-facets/adapter-claude-code
  • @agent-facets/adapter-codex
  • @agent-facets/adapter-opencode

Trailing newlines on generated JSON

Every JSON file the CLI writes now ends with exactly one trailing newline and uses consistent 2-space indentation:
  • facets.lock
  • install receipts and parallel-install lock payloads
  • build manifests inside the .facet archive
  • scaffolded facet.json (from facet create)
  • cache integrity sidecars
Previously these files ended without a trailing newline, so editors configured to auto-append one produced a one-character diff every time you opened a CLI-generated file. That’s fixed — open a file, save it, no diff.facets.json continues to be written through the comment-preserving serializer (so your hand-edited comments survive) and now upholds the same trailing-newline invariant.

The CLI is now agent-friendly

Every interactive authoring flow now has a non-interactive, scriptable path, and the CLI can describe itself to an AI agent on demand. Three themes: built-in instructions, headless authoring, and machine-readable output.

New command: facet instructions

facet instructions [topic] prints agent-oriented usage guidance — how to author and use facets, written for an autonomous agent to read before it acts. It is workflow guidance, not per-flag help.
The manifest topic appends the facet.json JSON Schema generated live from the schema definition — a single source of truth, never a hand-maintained copy. See facet instructions.

New command: facet modify

facet modify is the scriptable counterpart to the interactive facet edit wizard: one headless, flag-driven edit to a facet.
Per-asset adapter config uses a name-embedded flag whose value is a JSON object: --adapter-<name> '<json>' sets a block (replacing it wholesale), and --remove-adapter-<name> deletes one. Add --json for a structured change summary. Exactly one lifecycle action (--add, --remove, or --rename) is allowed per call; illegal flag combinations are rejected up front. See facet modify.

facet create gains headless flags

Pass authoring flags to scaffold a facet without the interactive wizard:
Repeat --skill/--agent/--command for multiple assets; --private marks the facet private, --force overwrites an existing facet.json (required in headless mode), and --json prints a structured result. See facet create.

facet build --verify and --json

facet build --verify runs the full validation pipeline without writing any output — a no-op build that confirms facet.json and every asset are valid and buildable. --json emits a machine-readable result and works with or without --verify.
See facet build.

Fix: subcommand --version is no longer shadowed

The global --version flag now applies only before the command name, so facet modify facet --version 1.2.3 sets the facet’s version instead of printing the CLI version.
CLINew Feature
New facet remove command (aliased rm)

New command: facet remove

facet remove <facet> [more facets...] is the inverse of facet add: it takes facets back out of a project. In one command it removes the named facets from facets.json, deletes their assets from every connected adapter, and rewrites facets.lock without them.
Removal reuses the same install pipeline as facet add, so it is transactional: any failure restores facets.json byte-for-byte and leaves the project unchanged. Removing multiple facets is all-or-nothing — if any name is not declared in facets.json, nothing is removed. Every facet you don’t name is left untouched.See the facet remove reference for details.
CLIBreakingNew FeatureFix
Bearer-token auth for the registry; new login/whoami/logout commands; FACET_REGISTRY_API_KEY removed; install now re-resolves a stale lockfile; new --frozen-lockfile flag

Registry authentication is now bearer-token based

Breaking: the FACET_REGISTRY_API_KEY environment variable has been removed — there is no fallback or deprecation shim. The CLI now sends an Authorization: Bearer <token> header, where the token is a you mint in the web UI.Provide the token one of two ways:
When FACET_TOKEN is set it takes precedence over the saved file. Read-only commands like facet search and facet add send the token too when one is available (earning a higher rate-limit tier) and work anonymously otherwise.

New commands: login, whoami, logout

  • facet login — guided sign-in. Paste a PAT; the CLI verifies it against the registry before saving it, so a typo or expired token fails fast instead of surfacing later at publish time. A browser sign-in option is shown as “coming soon”.
  • facet whoami — prints the signed-in username, email, and tier, and notes when FACET_TOKEN is the active credential.
  • facet logout — removes the saved credentials file. It makes no server call; revoke PATs in the web UI. If FACET_TOKEN is still set, it tells you so.

facet publish takes an optional directory

facet publish now accepts a directory argument and defaults to the current directory, matching facet build, facet edit, and facet create:
A first-time publish of a reserved or over-budget global facet may be queued for admin review — this is reported as a success, not an error.

Registry errors render verbatim

When the registry rejects a request, the CLI now shows the registry’s own message and suggested fix rather than translating the error code through a local table. The registry is the single source of truth for what an error means — so error guidance stays accurate as the registry evolves, with no CLI release required.See the Publish Flow spec for the full authentication model.

Editing a version in facets.json now takes effect

Fix: facets.json is the source of truth, but facet install was ignoring an edited version when the lockfile still pinned the old one. If you bumped a facet to a version that didn’t exist, install “succeeded” and wrote a self-contradictory lockfile entry instead of failing.Now facet install compares each lockfile entry against its manifest specifier. A locked version that no longer satisfies the manifest is treated as stale and re-resolved:
A wildcard the lock still satisfies (manifest 1.*, lock 1.2.3) is unaffected — it stays pinned and reproducible. See resolution semantics.

New: facet install --frozen-lockfile

For reproducible CI installs, --frozen-lockfile makes the lockfile the source of truth: install never re-resolves or writes the lockfile, and fails if the lockfile is missing, omits a manifest facet, or has drifted out of sync with facets.json.
This mirrors --frozen-lockfile from npm and bun. See frozen lockfile semantics.
CLIBreaking
Consolidate everything under FACET_DIR; new FACET_BIN_OVERRIDE; lock moves out of project root

One directory, one override

The facet CLI used to spread its state across four near-identical locations and five separate environment variables. State for the cache, installed adapters, the curl-installed binary, and parallel- install coordination all lived in different places with different overrides. This release collapses everything into a single root: one directory, one environment variable.

The new shape

Everything the CLI writes to disk now lives under $FACET_DIR:
The default for $FACET_DIR is ~/.facet/. Setting FACET_DIR IS the override — there is no separate variable per subsystem. Curl installs put the binary at $FACET_DIR/bin/facet; facet add and facet install resolve cache and adapters relative to the same root.

What changed

FACET_CLI_REGISTRY (npm registry URL override) and FACET_VERSION (used by install.sh) are unchanged.

FACET_BIN_OVERRIDE, by name

The launcher’s binary override gets a new name that carries its own semantics: FACET_BIN_OVERRIDE. Setting it means you’ve taken control of which binary the launcher executes. facet self-update continues to refuse while it’s set, because if you’ve overridden the binary path, self-update has no business writing over whatever you pointed it at. The refusal is coupled to the override on purpose.Unset FACET_BIN_OVERRIDE to re-enable self-update for a real install.

Project root: clean

The install advisory lock no longer touches your project root. Previously, facet install materialized .facets/.install.lock next to facets.json — a project-local directory that wasn’t tracked anywhere and could be left behind on crashes. The lock now lives at $FACET_DIR/locks/<basename>-<sha256(realpath)[:16]>.lock, keyed by the project’s canonical path so two checkouts of the same repo at different paths (git worktrees, Conductor workspaces) get distinct locks.No .facet.lock file, no .facets/ directory, no untracked entry next to your facets.json. The project root stays as clean as facets.json itself.Breaking: No automatic migration. The new code reads $FACET_DIR only — existing cached payloads and adapters at ~/.facets/ are not detected, copied, or warned about. Old env vars (FACETS_CACHE_DIR, FACETS_ADAPTERS_DIR, FACET_CACHE_DIR, FACET_ADAPTERS_DIR, FACET_INSTALL_DIR, FACET_BIN_PATH) are silently ignored — anyone who had them set in shell rc files or CI configs must rename to FACET_DIR / FACET_BIN_OVERRIDE or the values stop taking effect. Existing ~/.facets/ data can be deleted at any time; the new code will rebuild cache and adapters on first use.See the environment variables reference and the facet install page for the updated paths.
CLIBreakingImprovement
@agent-facets/core split into protocol (public, Node-native) and engine (private, Bun-native)

Three layers, honestly named

@agent-facets/core was always two things: the facet artifact specification (schemas, integrity rules, deterministic archive format, hash algorithm) and the Bun-native CLI implementation of that specification (subprocess-driven adapter bundling, registry HTTP client, install pipeline, scaffold, edit, self-update). The first set is portable Node-runnable data + cryptography that any third party — a registry server, a future alternative CLI, an offline .facet linter — needs to honor. The second is intrinsically Bun-native and runs only on a developer’s machine.Splitting them produces three honest layers:
  • @agent-facets/protocol (NEW, public, Node-native, Node 22+) — the TypeScript reference implementation of the facet artifact specification. Schemas, bytes-validators, integrity verification, content hashing, deterministic tar layout, version-spec grammar, front-matter encoding, build validators. Pure data + cryptography. No subprocesses, no network, no developer-machine state.
  • @agent-facets/engine (RENAMED from @agent-facets/core, made private) — the Bun-native CLI machinery. Install pipeline, registry HTTP client, adapter machinery, source resolvers, manifest mutations, cache, scaffold, edit, self-update, build pipeline orchestrator, gzip compression, path-based loaders. Internal to the monorepo; never published.
  • agent-facets (the CLI binary, unchanged) — argv parsing, Ink TUI, error formatting, exit codes.
See the specification for the full layer description and the design rationale for keeping the registry HTTP API outside the protocol.Breaking: @agent-facets/core is no longer published. The package is frozen at v0.9.1 on npm; existing pins continue to resolve, but there will be no further versions. New consumers (registry servers, third-party tooling) MUST use @agent-facets/protocol. There is no deprecation message on the legacy package — closed-alpha, no known external consumers.No CLI behavior change. Every @agent-facets/core import in the CLI was redirected to either @agent-facets/protocol (data primitives) or @agent-facets/engine (orchestrators). User-visible commands, flags, and output are unchanged.
CLINew FeatureBreaking
facet add now installs in one step; new source grammar; lockfile-driven install

facet add and facet install converge

facet add now does everything end-to-end. Resolve, fetch, verify integrity, materialize into adapters, write the lockfile — all in a single command. There is no separate facet install step after facet add.
facet install is still there, and it’s the right command after a fresh git clone or after pulling teammate changes that updated facets.json. It honors any pinned versions in facets.lock verbatim and only resolves entries that don’t have a lockfile entry yet — making installs reproducible across machines without a separate facet update command.If a project has no adapters installed, both facet add and facet install now auto-launch the adapter picker on a TTY, so first-run experience is a single command from a cold start.

New source grammar

facet add accepts a richer set of sources, aligned with what npm and bun users already expect:
Bare names default to the resolved exact version when written back to facets.json — so facet add viper-plans produces viper-plans@1.2.3 in the manifest, the same way npm install and bun add pin lockable defaults.

Lockfile-driven, with bootstrap

facets.lock is now the single source of truth for what gets installed:
  • When a lockfile entry exists, that exact version is fetched. The manifest’s range is not re-resolved.
  • When a lockfile entry doesn’t exist (first run, or a freshly-added manifest entry), the manifest specifier is resolved fresh.
  • When facets.lock doesn’t exist yet, facet install bootstraps it — the same way bun install creates bun.lock.

Three-check integrity protocol

Every fetched facet is verified before any asset is written:
  • Registry sources run three independent checks: cache vs. registry metadata, archive manifest vs. registry metadata, computed content vs. archive manifest. Each defends against a distinct adversary.
  • Git sources run a single check: computed content vs. lockfile integrity. Defends against tag-move attacks.
  • Local sources are trust-by-path.
Any mismatch is a hard security error. The install aborts before any asset is written; the project is exactly as it was before.

Cache

Resolved facet content is cached at ~/.facets/cache/<name>@<version>/. Subsequent installs of the same identity hit the cache instead of the network. Override with the FACETS_CACHE_DIR environment variable.

Repaired outcome

If you delete a materialized asset by hand and re-run facet install, the affected facet now reports as repaired in the summary — the adapter file is restored without bumping the version. This makes self-heal explicit instead of silent.

Breaking changes

  • git+ prefix is removed. Use plain https://...git or git@host:owner/repo instead. The new grammar accepts everything git+ did, just without the prefix.
  • Caret, tilde, and comparator version ranges are rejected. Use 1.* for major-pinned, 1.2.* for minor-pinned, * or latest for unpinned, or 1.2.3 for exact. The @latest alias and bare-name form both produce the same result as *.
  • facet install --dry-run is gone. No replacement; facet install always commits.
  • facet install rejects positional arguments. To add a new facet to the project, use facet add.
See the facet add and facet install CLI reference for full details.
CLIFix
Publish pipeline fixed across all packages

Publish pipeline fixed across all packages

Recent releases of agent-facets and the supporting packages had been failing or shipping inconsistently due to issues in the publish pipeline. All affected packages have been republished from a known-good state:
  • agent-facets — the CLI
  • @agent-facets/core and @agent-facets/adapter — authoring and adapter SDKs
  • @agent-facets/adapter-claude-code, @agent-facets/adapter-opencode, and @agent-facets/adapter-codex — first-party adapters
If you installed or upgraded the CLI in the last week and ran into install or runtime errors, reinstall:
Or, on any platform with Node.js:
No usage changes — facet add, facet install, and the adapter commands all behave the same as before.
Improvement
Mobile-responsive landing page

Mobile-responsive landing page

The agentfacets.io landing page is now fully responsive. If you previously visited on a phone or tablet, the experience was broken — the scroll-linked demo, navigation, and layout all assumed a desktop viewport. That’s fixed.Here’s what changed:
  • Mobile navigation — the nav bar collapses into a slide-down menu on screens ≤ 1024 px wide, with all links accessible from a single tap.
  • Adapted CLI demo — the interactive terminal demo skips the widest step on small screens so it fits without horizontal scrolling.
  • Stacked sections — the explainer, hero, and footer all reflow into a clean single-column layout on narrow viewports.
  • Registry CTA — on mobile, the install command is replaced with a link to agentfacets.io so you can browse facets without needing a terminal.
The desktop layout is unchanged.
Improvement
Landing page and new docs URL

agentfacets.io landing page

The Agent Facets website now has a proper landing page at agentfacets.io. It walks you through what facets are, shows a live CLI demo, and makes it easy to get started with a single install command:

New docs URL

Documentation has moved to its own subdomain at docs.agentfacets.io. The main domain at agentfacets.io now serves the landing page, and the CLI installer lives at agentfacets.io/install. Existing docs links have been preserved — you’ll just land on the new URL. Update any bookmarks accordingly.
CLINew Feature
Install pipeline and new install URL

facet add and facet install

You can now add facets from external sources and install them into your AI coding tools end-to-end.facet add resolves a facet from GitHub, a Git URL, or a local path and writes it to your project’s facets.json, preserving any hand-edited comments:
facet install reads facets.json, builds each facet, and materializes its assets into every adapter you’ve connected. The pipeline is built for iteration:
  • Lockfile diffing — only changed assets are written on each run.
  • Rollback on failure — if something goes wrong mid-install, changes are reversed automatically.
  • Concurrent safety — an atomic install lock prevents two facet install runs from interfering with each other.
  • --verbose — full pipeline trace for debugging.
See the facet add and facet install CLI reference for details.

New install URL

The CLI installer has moved to its own home at agentfacets.io/install. If you previously bookmarked the install URL, update it to:
This works on macOS and Linux. For Windows or any platform with Node.js, you can install via npm instead:
The download link on the docs site has been updated automatically.
CLIImprovement
Faster adapter installs

Self-contained adapter bundles

Adapters now ship as fully self-contained bundles with all dependencies inlined. When you run facet adapter install, the CLI uses a prebuilt fast path that skips the build step entirely — falling back to a full rebuild only if the prebuilt bundle is missing or incompatible.This also means adapter installs no longer leave build artifacts in your source tree.See the environment variables reference for configuring the adapter install location with FACETS_ADAPTERS_DIR.
CLINew Feature
Adapter system with Claude Code, OpenCode, and Codex

Adapter SDK and first-party adapters

Adapters are the bridge between facets and your AI coding tool — each adapter knows where and how to write assets for a specific tool. The first three first-party adapters ship today:
  • Claude Code
  • OpenCode
  • Codex (early access — installable, but asset materialization via facet install is coming soon)
When you run facet install, the CLI writes your facet assets into the correct locations for every adapter you’ve installed. Third-party adapters use the same installation and loading mechanism as first-party ones — install via npm, Git URL, or local path.Manage adapters with:
If no adapters are installed when you run facet install, an interactive picker appears so you can select which AI tools to connect.See the adapter CLI reference for full usage, including all built-in adapter names.
CLIImprovement
Self-contained archives

Self-contained .facet archives

The .facet build output is now a single self-contained archive. The build manifest is embedded inside the archive rather than shipped as a separate file, making distribution simpler. You can extract the manifest for debugging with --emit-manifest during build.See the facet build CLI reference.