Skip to content

Repository configuration reference ​

This page lists every field of an Agent Marketplace configuration file and the rules the CLI checks when it reads one. Use it when you write or review .agents/config.yaml by hand, or when a command reports a v4.* diagnostic and you need to know which rule you broke.

A configuration file is a YAML file. The committed .agents/config.yaml says which sources a repository uses, which resources it takes from each source, and which harnesses receive them. The same schema is used by the user, organization, and personal-local files described in the configuration layers reference.

For task-oriented guidance, see How to adopt agent-marketplace in a repository and How to keep resources reproducible. The sources and resources explanation describes what each map is for and how the two work together.

Configuration holds your selection policy. Generated lockfiles record the exact Git commits and Marketplace revisions that the policy resolved to; see the lockfiles reference. The CLI adapts v4 sources into its internal requirement model on every run. You can edit sources and resources by hand, or let install, remove, update, and the TUI edit them for you. Those commands edit only the file they target and never rewrite an included fragment; a request that lives in a fragment is refused with config.edit.include-owned.

Schema versions ​

apiVersion: agent-marketplace/v4 is the only supported consumer configuration schema. Every existing organization, user-personal, repository, and personal-local root must declare that exact string. New configuration files created by install, remove, init, and the TUI use v4. A missing file retains its normal first-run behavior; an existing empty or versionless file is not a missing layer.

A root without apiVersion fails with v4.api-version-required. Explicit v1, v2, v3, unknown, empty, null, non-string, or non-exact versions fail with v4.api-version. The diagnostic identifies the authored file and the apiVersion field, with line context when available. The root cannot inherit its version from another layer or an included fragment.

The CLI has no migrate command, startup conversion prompt, TUI migration modal, or compatibility reader. Convert writable roots with an older released migrator before upgrading; have organization configuration converted externally by its administrator. Conversion can refuse includes, unrepresentable input, or missing verified Marketplace evidence. Changing only the version string does not convert legacy fields.

A command checks every config file and include it needs before it downloads anything or writes config, locks, or harness files. If an earlier command was interrupted mid-write, a command that can recover may first finish that write, which changes the files it recorded; read-only commands return dependency.recovery-required and do not replay it. Apart from that recovery, a refused command leaves existing config, lock, and harness files and their metadata untouched, creates no missing config file or lock, and may still write logs.

This consumer-format requirement does not change the internal v4 runtime adapter, lock v1 reads/v2 writes, historical source-revision verification, Marketplace operator agent-marketplace.io/marketplace/v1, API/artifact versions, or native harness schemas.

File location and scope ​

To find the repository configuration, Agent Marketplace starts in the current directory and walks up toward the filesystem root. It uses the first directory that contains .agents/config.yaml, with two limits:

  • It skips your home directory, because ~/.agents/config.yaml is the user file.
  • It does not leave the current Git repository. A nested repository never picks up a parent repository's configuration.

If no directory qualifies, the Git repository root is used, and outside Git the current directory is used. Configuration files found at different levels are never merged.

The personal-local file is searched the same way, from the current directory up to that repository root. This lets a subdirectory of a monorepo keep its own .agents/config.local.yaml on top of the committed file at the root.

Repository-scoped output is written under the directory that holds .agents/.

The four configuration layers are:

LayerConfigurationGenerated lockPurpose
Organization/etc/agent-marketplace/config.yaml/etc/agent-marketplace/lock.yamlManaged machine policy and required resources
User~/.agents/config.yaml~/.agents/lock.yamlPersonal machine-wide targets and resources
Repository<repo>/.agents/config.yaml<repo>/.agents/lock.yamlShared project targets and resources
Repository personal<repo>/.agents/config.local.yaml<repo>/.agents/lock.local.yamlChoices for one checkout, kept out of Git

Commit the repository lock with its configuration. Keep the personal-local files out of Git: when <repo>/.agents/config.local.yaml exists, the CLI appends .agents/config.local.yaml and .agents/lock.local.yaml to the repository's .gitignore if they are missing. Consumer commands never create an absent organization lock. Directory sources are read live and never appear in a lock.

Schema ​

A v4 root file must declare exactly agent-marketplace/v4:

yaml
apiVersion: agent-marketplace/v4
sources:
  shared:
    git: https://github.com/example-org/agent-resources.git
    ref: v1.4.0
    path: resources
resources:
  shared:
    include:
      - skill/code-review
      - command/release

The sources map holds named source declarations. The resources map holds one resource group per source name, and each group says what to take from that source. A source name is a label inside one configuration file and its includes. It does not identify what gets fetched (the URL, ref, and path do that), and it does not choose where resources install (the layer does that).

A source declares exactly one kind:

  • git is a Git repository and requires ref.
  • directory is a folder on disk, read live on every run. In the repository .agents/config.yaml and .agents/config.local.yaml files, relative paths resolve from the repository root. In user and organization files, in included fragments, and in any other file, they resolve from the directory of the file that declares them.
  • marketplace is a hosted Marketplace endpoint.

The kind is always explicit. A path is never treated as a directory source because it lacks a .git suffix.

The parser rejects:

ProblemDiagnostic
Unknown top-level fieldv4.unknown-field
Legacy installation key such as registries, skills, or marketplacesv4.legacy-key
YAML aliasv4.alias-forbidden
YAML merge key (<<)v4.merge-key-forbidden
Duplicate mapping keyv4.duplicate-key
More than one YAML document in the filev4.multiple-documents
Root file without apiVersionv4.api-version-required
apiVersion other than agent-marketplace/v4v4.api-version

Explicitly included fragments under a validated v4 root may omit apiVersion or declare exactly agent-marketplace/v4. An explicit unsupported or invalid fragment version fails the include tree with v4.api-version, naming the fragment and field. This exception does not apply to personal-local roots and does not relax layer field restrictions, source bindings, include precedence, or root-owned edits and locks.

Configuration layers ​

Layers merge from lowest to highest precedence: organization, user, repository, repository personal. Top-level target harnesses are chosen per selecting layer. Resources the repository selects use a non-empty repository harnesses list, then the user list, then the organization list. Resources the user or organization selects use the user list, then the organization list, so a repository cannot narrow what they install in your home directory. A resource group's harnesses list narrows its scope's set and cannot add a harness that is not already selected.

Each layer allows only some fields. For example, telemetry, backup, and logging belong to machine-level files, and the personal-local file cannot declare harnesses or allowlists. The configuration layers reference has the full table.

include ​

include pulls local YAML files into the layer that declares it. It accepts one path or an ordered list of paths:

yaml
apiVersion: agent-marketplace/v4
include: profiles/company.yaml

A list includes more than one fragment:

yaml
include:
  - profiles/company.yaml
  - profiles/payments-team.yaml

Relative paths resolve from the directory of the file that declares them. Absolute paths are accepted. Includes can nest. A fragment shared by two branches of the include tree is loaded once for each branch; the loader reports a cycle (v4.include-cycle) only when a file includes one of its own ancestors. Glob patterns and remote URLs are not supported.

An included fragment has lower precedence than the file that includes it. In a list, the first fragment merges first, each later fragment merges over the earlier ones, and the including file merges last. Fields keep their own merge rules:

  • A source name declared in more than one file must have identical values everywhere. Different values fail with v4.source-conflict.
  • Resource groups with the same name are combined. Their include and exclude lists are concatenated in merge order. tags, all, registries, required, and harnesses take the value from the last file that sets them.
  • allowed_registries and allowed_marketplaces take the first declaration in merge order. A fragment that sets an allowlist cannot be relaxed by a later fragment or by the including file.
  • harnesses takes the value from the last file that sets it. backup, logging, update_check, telemetry, and materialization merge field by field, with later files winning.

The loader rejects the whole layer when an include is missing, unreadable, malformed, not allowed in that layer, or part of a cycle. Fragments must use only the fields their layer allows. Organization fragments have extra ownership and permission requirements; see the configuration layers reference.

Root fields ​

Unknown top-level fields are rejected.

FieldTypeRequiredDescription
includepath or list of pathsnoLocal YAML fragments merged into this layer. Relative paths resolve from the declaring file.
apiVersionstringyes for root filesMust equal agent-marketplace/v4.
harnesseslist of stringsnoTarget harnesses. A repository list applies only to resources the repository selects. When omitted or empty in the repository file, targets come from the user file, then the organization file.
sourcesmappingnoNamed Git, directory, or Marketplace source declarations.
resourcesmappingnoResource groups, each keyed by a source name.
allowed_marketplaceslist of regular expressionsnoRestricts hosted Marketplace endpoint URLs.
allowed_registrieslist of regular expressionsnoRestricts remote Git origins.
backupmappingnoPre-sync backups of machine-scope harness folders: enabled (default true), max_days (default 14), max_per_day (default 10). Both limits must be positive. Organization and user files only.
loggingmappingnoLog file settings: enabled, level, file, max_size_mb, max_backups, max_age_days, compress. See the logging reference.
update_checkmappingnoRelease upgrade notice: enabled (default true). Organization and user files only; the user value wins.
telemetrymappingnoMachine telemetry policy: level, endpoint, community_reporting, retention_policy, ca_file, allow_insecure, headers. See the telemetry reference. Organization and user files only.
materializationmappingnoWhether generated resources are symlinks or regular files: mode and targets. See Materialization.

harnesses, allowed_registries, and allowed_marketplaces must be lists of strings. Allowlist entries must compile as regular expressions.

harnesses ​

Supported targets are:

ValueHarness
claudeClaude Code
factoryFactory Droid
cursorCursor
windsurfWindsurf
geminiGemini CLI
devinDevin CLI
codexCodex
opencodeOpenCode

Target names are lowercase. Unknown targets fail with v4.harness.

For resources the repository selects, a non-empty repository harnesses list takes precedence over the user and organization lists. If the repository file omits the field or sets an empty list, the user list is used; if that is also missing or empty, the organization list is used. Resources the user or organization selects use the user list, then the organization list, and fall back to the repository list only when neither declares one. See target harnesses. Commands that only read the catalog, such as list, work without any target list and print a warning. sync needs a target list and exits with an error when none is configured.

Output paths for each harness are listed in the harnesses and output paths reference.

Source declarations ​

Each entry under sources describes one place to fetch resources from. The source name must match [A-Za-z0-9][A-Za-z0-9._-]* (v4.source-name).

yaml
sources:
  shared:
    git: https://github.com/example-org/agent-resources.git
    ref: main
    path: skills
    source_harness: claude
  local:
    directory: ./agent-resources

A source must contain exactly one of git, directory, or marketplace; zero or two fail with v4.source-discriminator. All values are strings.

FieldApplies toRequiredDescription
gitGityesGit clone URL.
refGityesBranch, tag, or commit to resolve.
pathGitnoSubdirectory of the repository to discover resources in.
source_harnessGit, directorynoHarness layout the source content is written in. Omit it to let the CLI detect the layout.
directoryDirectoryyesFolder on disk, read live.
marketplaceMarketplaceyesHosted Marketplace endpoint URL.

Validation rules by kind:

RuleDiagnostic
Git source without refv4.git-ref-required
Invalid refv4.git-ref
git value that is a local path (/, ./, ../), a git:// URL, or a file:// URL with a host or a relative path. Remote URLs, scp-style origins such as git@host:org/repo.git, and hostless absolute file:/// URLs are accepted.v4.git-origin
path that is absolute, contains . or .. segments, or leaves the repositoryv4.git-path
ref or path on a directory sourcev4.source-field
ref, path, or source_harness on a Marketplace sourcev4.source-field
directory path that leaves its base directory, or reaches outside it through a symlinkv4.directory-path
marketplace URL that is not http or https, has no host, carries user info, a query, or a fragment, or contains . or .. path segmentsv4.marketplace-url
source_harness that is not a supported harness idv4.harness
Empty git, directory, or marketplace valuev4.source-value

A directory source names the folder to read directly; a subfolder is selected through directory, not path.

In the repository .agents/config.yaml and .agents/config.local.yaml, directory: . selects the repository root and directory: ./resources/skills selects <repo>/resources/skills. User and organization files, included fragments, and files outside that layout resolve relative paths from their own directory. Relative paths, including through symlinks, must stay inside that base directory. Absolute paths are used as written. Earlier v4 releases resolved repository-root declarations from .agents/; a source stored under .agents/ needs an explicit ./.agents/ prefix.

Two source names may point at the same URL, ref, and path. They stay separate in configuration, and the CLI fetches the content once.

Resource groups ​

Every key under resources must be the name of a source declared in the same file or its includes. A group for an undeclared source fails with v4.undefined-source.

yaml
resources:
  shared:
    include:
      - skill/code-review
      - command/release
    tags: [platform]
    exclude:
      - skill/legacy-review
    harnesses: [claude, cursor]

A plain list is shorthand for a group with only include:

yaml
resources:
  shared:
    - skill/code-review
    - command/release
FieldTypeDefaultDescription
includeresource-item listnothing selectedExplicit resource requests.
excludeexclusion listnothing excludedRemoves matching selections that are not required.
tagsstring listno tag selectionSelects resources whose metadata.tags contain a listed tag.
allbooleanfalseSelects every resource of every kind in the source.
registriesstring listabsentMarketplace registry slugs that bound all and tags. Invalid for Git and directory sources (v4.option-combination).
requiredbooleanfalseProtects this group's selections from exclusions and from remove. It selects nothing by itself.
harnessesstring listinheritedNarrows the target set for this group. It never adds a harness.

String lists must not contain empty or duplicate values (v4.duplicate). all and required must be YAML booleans. Unknown group fields fail with v4.unknown-field.

Omitted fields leave inherited values alone when fragments merge. An explicit tags: [] switches off tag selection inherited from a fragment, all: false switches off inherited all, and harnesses: [] means no harness receives the group's resources.

For a Marketplace group with all: true or non-empty tags, registries must list at least one registry slug (v4.dynamic-unbounded). A registries list alone selects nothing.

What each source kind supports ​

Field or optionGit and directoryMarketplace
includeyesyes
exclude*, <kind>/*, or <kind>/<name>exact <registry-slug>/<kind>/<name> only, not a collection
tags, allyesaccepted by the parser, rejected at run time
registriesrejectedaccepted by the parser, rejected at run time
harnesses on the groupyesrejected at run time
requiredyesyes
revision optionrejectedyes
as optiononly the resource's own nameyes, except for collections

"Rejected at run time" means the file loads, but sync and other commands that resolve Marketplace resources fail with v4.marketplace-runtime-unsupported. Marketplace groups select through explicit include requests.

Resource locators and options ​

A locator names one resource. Git and directory sources use <kind>/<name>. Marketplace sources use <registry-slug>/<kind>/<name>, because one endpoint serves many registries. The kinds are skill, command, subagent, hook, mcp, and collection. A locator in the wrong shape for its source fails with v4.locator.

Each include item is either a locator string or a mapping with one locator key and an options mapping:

yaml
resources:
  shared:
    - command/deploy:
        as: deploy-platform
  company:
    - platform-tools/skill/review:
        revision: sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
OptionTypeDefaultDescription
asstringresource nameName to install the resource under. It must be a safe file name (v4.installed-name). Collections cannot use as because they do not install as themselves (v4.option-combination).
revisionstringno exact constraintExact Marketplace resource or collection revision, written sha256:<64 lowercase hex> (v4.revision).

revision is invalid for Git and directory resources. Git resources use their source's ref; declare a second source to use a different ref. Semantic-version constraints and latest are not v4 options.

On Git and directory sources, as may be omitted or set to the resource's own name. A different name passes the parser but fails with v4.runtime-option when the configuration is resolved.

Listing the same locator twice in one include list fails with v4.duplicate-request, even when the options match. An option value that is empty, null, or not a string fails with v4.resource-options, and a mapping item with more than one key fails with v4.resource-item. Unknown option names fail with v4.unknown-field.

Selection and exclusions ​

A group's candidates are the resources named by include, matched by tags, or covered by all. Collections then expand into their members, and exclusions remove anything that is not required. When a resource is both requested explicitly and selected by tags or all, the explicit request's options apply.

Within one file, exclusions apply after inclusions, whatever order the keys appear in. Across an include tree, order matters: an include in a later file brings back a resource that an earlier fragment excluded. Required resources are never excluded.

required: true protects the group's selections but is not a selection by itself, so a group that contains only required: true selects nothing. Marketplace resources selected by an organization group are not required unless that group sets required: true; when it does, the protection covers its direct pins and the members of any collection it selects.

Collections expand to their members before resources are resolved. Collections themselves are never written into harness folders. See the collections reference for the collection file format.

Hosted Marketplaces ​

Declare a hosted Marketplace as a named source and request resources from it in a group:

yaml
sources:
  company:
    marketplace: https://marketplace.example.com
resources:
  company:
    include:
      - shared-agents/skill/review:
          revision: sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef

Installing and resolving Marketplace resources requires a verified lock record in the owning layer's lock that matches the requested endpoint, registry, resource, and revision. A missing or unusable lock fails with v4.marketplace-lock-required. A lock with no record for the endpoint, or with a record that does not match, fails with v4.marketplace-lock-mismatch. A writing agent-marketplace sync or lock for a user, repository, or personal-local layer records entries for selected Marketplace resources that an existing lock is missing, keeping existing pins unless the configuration requests an explicit revision; read-only modes (sync --check, sync --locked, sync --offline, and doctor) report the error and never write. Organization locks are only written by lock --scope organization. Either way nothing is installed until the lock records the resource. One layer can have only one source that fetches from a given endpoint.

Marketplace exclusions are exact registry-slug/kind/name entries under resources.<source>.exclude, and they win over inclusions: a group that includes a collection and excludes one of its members installs only the remaining members. The excluded resource is never fetched, so it cannot fail a sync.

A Marketplace group that contains only exclude makes its source exclusion-only. Such a source fetches nothing, needs no lock record, and hides optional resources that the organization file selects from the same endpoint. Exclusion-only Marketplace sources are allowed only in the user file; elsewhere they fail with v4.layer-field. Exclusions never hide required: true pins, and apart from this user override of organization pins, they never hide another layer's selections. Because the user file applies to the whole machine, the override does too. For example:

yaml
apiVersion: agent-marketplace/v4
sources:
  company:
    marketplace: https://marketplace.example.com
resources:
  company:
    exclude: [shared-agents/skill/review]

See How to install a resource from a hosted Marketplace for the full workflow.

allowed_marketplaces holds regular expressions matched against normalized Marketplace endpoint URLs (lowercase scheme and host, no trailing slash). The first layer that declares it, checked in the order organization, user, repository, controls the policy. The personal-local file cannot declare it.

Registry allowlist ​

allowed_registries holds regular expressions matched against normalized Git origins. Before matching, the CLI removes an https://, http://, git://, or ssh:// prefix, turns a leading git@host: into host/, and strips trailing slashes and a trailing .git. For example, git@github.com:example-org/tools.git is matched as github.com/example-org/tools.

yaml
allowed_registries:
  - '^github\.com/example-org/'

The first layer that declares the field controls it, checked in the order organization, user, repository. Within that layer, the first declaration in include order wins. The personal-local file cannot declare it. Every git source is checked, including file:// origins. Directory sources are not checked.

ConfigurationEffect
field omitted in every layerAll Git origins are allowed.
allowed_registries: []All Git origins are denied.
one or more patternsA Git origin must match at least one pattern.

Materialization ​

materialization controls how sync writes skills, commands, and subagents into harness folders (the product calls this step materialize):

yaml
materialization:
  mode: symlink
ModeBehavior
symlinkDefault. Skills, commands, and subagents are symlinks into the compiled cache under ~/.cache/agent-marketplace/. Factory commands are always regular files.
fileWrites regular files and folders for every target. The CLI tracks what it wrote in a materialization manifest.

targets gives one harness a different mode:

yaml
materialization:
  mode: file
  targets:
    devin: symlink

Mode values are symlink or file; target keys must be supported harness ids.

Which scope a setting affects depends on the file:

FileRepository-scoped outputMachine-scoped output
Useryes (default for both scopes)yes
Repositoryyesno
Repository personalyesno
Organizationnot allowed (v4.layer-field)not allowed

Every harness supports both modes. Shared files such as hook and MCP configuration are always regular files edited in place, and their ownership rules apply in either mode.

Name collisions ​

When sources with different origins or refs select resources with the same kind and name, Agent Marketplace picks one winner and prints a warning. A resource from a required: true group wins first, then the one from the higher-precedence layer or file, then the one with the alphabetically first normalized origin. Configuration order breaks any remaining tie.

Hooks are the exception: hooks from independent sources are all installed, even when their names match. Repeated references to the same source are installed once.

Resources of one kind whose names differ only in letter case, such as commands deploy and Deploy, name one file on case-insensitive filesystems. Sync refuses all of them with bundle.conflict.duplicate-artifact-path, on every host. The exception is a resource from a required: true group that outranks the others: it is installed, and each of the others is reported with a materialize.collision.shared-path warning. Between two required resources, the higher-precedence layer or file wins, and a tie is still refused.

Different kinds collide only on a harness target that installs them at the same path. Devin CLI and Codex install commands as skills, so a skill and a command with the same installed name compete there under the same rules, and sync prints a materialize.collision.shared-path warning naming both. Names that differ only in letter case, such as audit and Audit, count as the same name here on every host, because they are one path on case-insensitive filesystems. status lists the losing resource only for the targets where it is still installed. On targets with separate skill and command paths, such as Claude Code, both are installed.

The scopes, selection, and precedence explanation covers collisions, exclusions across layers, and removal in more detail.