Skip to main content
The facet manifest (facet.json) is the source of truth for a facet’s identity and the text assets it contains. This page defines every field in the manifest schema and is the canonical reference for the facet name grammar.

Example

{
  "name": "acme-dev",
  "version": "1.0.0",
  "description": "Acme org developer toolkit",
  "author": "acme-org",
  "skills": ["code-standards", "pr-template"],
  "agents": {
    "reviewer": {
      "description": "Org code reviewer",
      "prompt": { "file": "agents/reviewer.md" },
      "adapters": {
        "opencode": {
          "tools": { "grep": true, "bash": true }
        }
      }
    }
  },
  "commands": {
    "review": {
      "description": "Run a code review",
      "prompt": { "file": "commands/review.md" }
    }
  }
}

Identity

FieldRequiredTypeDescription
nameYesstringFacet identity. An unscoped name (cowsay) or a scoped name (@scope/name). See Schema Constraints.
versionYesstringSemver version string.
descriptionNostringHuman-readable description.
authorNostringAuthor name or identifier.
privateNobooleanPrivacy declaration. true declares private publish intent; false or omission is public-by-default. See Privacy.
The name and version fields MUST be present. A manifest missing either field MUST be rejected. The name MUST be a valid facet identity: an unscoped name (<slug>) or a scoped name (@<scope>/<slug>). Asset names (skills, agents, commands) are validated independently as local kebab-case identifiers and are never scoped. Consumers MUST tolerate unrecognized top-level fields. Unknown fields MUST be ignored — not rejected.

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 Flow). 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.
ValidInvalidWhy invalid
abashorter than 2 characters
cowsayCowsayuppercase letters
admin-tester1abcdoes not start with a letter
apple-b34rabc-ends with a hyphen
@julian/cowsayabc--defconsecutive hyphens
@acme/deploy-toolsabc_defunderscore is not allowed
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).

Text Assets

Text assets are the locally authored content included in the facet.
FieldRequiredTypeDescription
skillsNoarray of stringsSkill names. Each corresponds to a file in the facet.
agentsNomap of string → agent descriptorAgent name → agent descriptor (description, prompt, adapter config).
commandsNomap of string → command descriptorCommand name → command descriptor (description, prompt).
A facet MUST have at least one locally authored text asset. A manifest with no text assets MUST be rejected.

Agent Descriptor

FieldRequiredTypeDescription
descriptionNostringHuman-readable description of the agent.
promptYesstring or {file: path}The agent’s prompt content or a reference to it.
adaptersNomap of string → adapter configAdapter name → adapter-specific agent configuration.
The prompt field MUST be present. It MAY be:
  • A string containing the prompt text directly
  • An object with a file key containing a path relative to the facet root
The adapters section is OPTIONAL. It contains adapter-specific configuration (tool access, permissions, model preferences) keyed by adapter name. Each installed adapter validates its own metadata schema at build time. Unknown adapters produce a warning. Invalid metadata for an installed adapter is a build error.

Command Descriptor

FieldRequiredTypeDescription
descriptionNostringHuman-readable description of the command.
promptYesstring or {file: path}The command’s prompt content or a reference to it.
The prompt field follows the same rules as the agent descriptor’s prompt.

Schema 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 locally authored text asset.
  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 manifest MUST NOT be modified by any tooling — it is immutable.