Skip to main content
The facet manifest (facet.json) is the source of truth for a facet’s identity, the text assets it contains, and the supplementary files it ships. The names it declares are authored names: they fix every archive path and integrity value, and a consuming project may materialize an asset under a different name without changing any of that. This page defines every field in the manifest schema and is the canonical reference for both the facet name grammar and the asset name grammar.
The facet manifest is distinct from the project manifest (facets.json) — the file in a consuming project that declares which facets are installed, and how it wants their assets named. Throughout this page, “the manifest” means the facet manifest.
For conceptual guides to each asset type, see Skills, Commands, and Agents.

Example

facet.json

Schema

Every top-level field of facet.json. The name and version fields MUST be present; a manifest missing either MUST be rejected. A facet MUST also declare at least one text asset (skills, agents, commands, or facets). Consumers MUST tolerate unrecognized top-level fields — unknown fields MUST be ignored, not rejected.

Fields

string
required
Facet identity: an unscoped name (cowsay) or a scoped name (@scope/name). Validated, never normalized — see Facet name grammar. This is the facet’s own name; the names of the assets it contains follow the separate asset name grammar.
string
required
Semver version string.
string
Human-readable description.
string
Author name or identifier.
boolean
Privacy declaration. true declares private publish intent; false or omission is public-by-default. See Privacy.
map of string → skill descriptor
Skill name → skill descriptor. A skill descriptor MAY declare a files array of companion files shipped inside the skill directory.
map of string → agent descriptor
Agent name → agent descriptor.
map of string → command descriptor
Command name → command descriptor.
array of string
Top-level supplementary files: exact repo-relative paths to non-asset files that ship in the archive but never materialize (e.g. README.md, LICENSE, docs/design.md). Exact paths only — no globs or patterns. Every path MUST satisfy the portable path grammar and MUST NOT resolve under skills/ (skill companions are declared in their skill’s own files).
array of facets entries
References to other facets (name@version strings or selective entries). Schema-validated only: build does not resolve the references, and facet add rejects sources that declare a non-empty facets array.
map of string → server reference
MCP server references (source-mode version string or ref-mode { image }). Declared servers are validated but not installed; the install pipeline SHOULD surface a warning for facets that declare them.

Privacy

The optional private field declares the author’s publish-visibility intent:
  • private: true declares that the facet is private.
  • private: false, or omitting the field, declares the facet is public (public-by-default).
private is a recognized schema field, not an unknown extension. It MUST be a boolean: a non-boolean value (string, number, object, array, or null) MUST be rejected with a private-identified error rather than tolerated or coerced. Validation MUST NOT inject private: false into a manifest that omits the field — omission remains omission in the validated data, so tooling sees exactly what the author wrote. The private declaration is part of manifest content: it is embedded verbatim in the built .facet artifact and travels to the registry at publish time (see Publish). It expresses author intent; registry-side authorization and visibility enforcement are the registry’s responsibility, not the CLI’s.

Facet name grammar

A facet identity is one of exactly two forms:
  • Unscoped: a single slug, e.g. cowsay.
  • Scoped: @<scope>/<slug>, where both the scope and the base name are slugs, e.g. @julian/cowsay.
Every slug component (the unscoped name, a scope, and a scoped base name) MUST satisfy the same grammar:
  • It MUST be at least 2 and at most 64 characters long.
  • It MUST start with a lowercase ASCII letter (a-z).
  • It MUST end with a lowercase ASCII letter or ASCII digit.
  • It MUST contain only lowercase ASCII letters, ASCII digits, and hyphens (-).
  • It MUST NOT contain consecutive hyphens.
Names are validated, never normalized. Uppercase letters, non-ASCII characters, underscores, dots, spaces, and other characters outside the grammar are rejected rather than rewritten. Valid: ab, cowsay, admin-tester, apple-b34r, @julian/cowsay, @acme/deploy-tools. Invalid: The following scoped shapes are rejected: a bare scope (@scope), a missing scope (@/name), a missing name (@scope/), extra path depth (@scope/name/extra), and the legacy un-prefixed form (scope/name).

Asset names

Asset names — skill, command, and agent names — follow the Agent Skills name grammar, interpreted by Facets as a single ASCII segment: 1–64 characters of lowercase ASCII letters, digits, and hyphens, not starting or ending with a hyphen and with no consecutive hyphens. Unlike the earlier format, a current-format asset name is a single segment: it MUST NOT contain /, so slash-namespaced names like viper-plans/planning are no longer valid (use viper-planning). Skills and commands share one namespace: within a facet, a skill and a command MUST NOT use the same name. Agents are a separate namespace and may reuse a skill or command name. The manifest is validated against this rule within a single facet. The same rule is applied again across every facet in a project at install time, over the names assets are actually materialized under — see Namespaces. A companion file’s path may contain / for directory depth (references/api.md), but those separators are part of the file path, not the skill name — the skill name itself is still a single segment.
Legacy 0.1 archives retain their earlier multi-segment naming during the compatibility window. New manifests use the single-segment grammar above.

Constraints

  1. The name MUST be a valid facet identity (see Facet name grammar), and the version MUST be a semver string.
  2. A facet MUST have at least one text asset — skills, agents, commands, or facets.
  3. The @ character marks a scope (@scope/name) and also separates a name from a version when a facet is referenced elsewhere (name@version, @scope/name@version).
  4. Consumers MUST tolerate unrecognized fields. Unknown fields MUST be ignored.
  5. If present, private MUST be a boolean; non-boolean values are rejected. Omission is not rewritten to private: false (see Privacy).
  6. The facet manifest MUST NOT be modified by the build, publish, or install pipelines. (The project manifest, facets.json, follows different rules: the install pipeline writes it as part of the tri-write.)

Text assets

A facet’s content is carried by three text asset types: skills, agents, and commands. Each asset is declared in the manifest under its type’s map, and its name maps to a file at a conventional path in the source tree. The file’s content is the asset’s prompt — it is resolved by convention at build time, never referenced by a manifest field.
  • Skillskills/<name>/SKILL.md. Each skill lives in its own directory, per the Agent Skills convention; the main file MUST be named SKILL.md. A skill directory MAY also contain declared companion files at any safe depth (references/api.md, scripts/run.ts).
  • Agentagents/<name>.md. A single markdown file whose content is the agent’s system prompt.
  • Commandcommands/<name>.md. A single markdown file whose content is the command’s prompt.
A primary asset file (a SKILL.md, agent, or command file) MAY carry author-supplied YAML front matter. It ships verbatim in the archive and is reconciled with the manifest only at install time: materialization merges the manifest’s name and description, plus any per-adapter extras, on top of whatever the author wrote. The manifest always wins, so a facet cannot override its own asset identity through front matter.
The name written at install time is the asset’s effective name — the one the consuming project chose. description stays as the publisher wrote it. See Two identities.
An asset descriptor’s adapters block is validated at build time against each installed adapter’s schema: unknown adapters produce a warning, and invalid metadata for an installed adapter is a build error.

Supplementary files

Beyond its assets, a facet can declare supplementary files — non-asset files that ship inside the .facet archive and are integrity-protected like everything else, but are not independently installable assets. They have no asset type, no adapter metadata, and no lockfile asset tuple. There are two declaration sites, and every supplementary archive entry MUST be derivable from one of them (there is no auto-discovery):
  • Top-level files — repo-relative paths at the tree root, declared in the manifest’s files array. Used for README.md, LICENSE, development notes, and other project files. These ship but never materialize: they are not written to disk at install time.
  • Per-skill files — paths relative to a skill’s directory, declared in that skill descriptor’s files array. These are the skill’s companion files (references, scripts, templates). A companion materializes atomically with its owning skill and cannot list SKILL.md itself.
Supplementary files are declared as exact paths only — no globs or patterns — and each path MUST satisfy the portable path grammar. A top-level path MUST NOT resolve under skills/, so a skill’s files have exactly one declaration site. Supplementary bytes are shipped verbatim: binary and empty files are valid, and front matter is never parsed or stripped. README.md and the extensionless README are ordinary top-level files declarations — there is no README-specific manifest field. Authoring support for them is described in Create Your First Facet and facet edit.
A CLI older than the first 0.2-producing release tolerates the files fields but omits their bytes when it builds, producing a declared-but-empty facet. Build with a current release so declared files actually ship.