dmx
Configuration

Shared Sources

Shared sources let an engineering organization define its loops, skills, and validators once, in a dedicated git repository, and have every app repo build on them. Teams can layer their own shared repo on top, and each repo can still override what it needs. Without them, teams copy the same .dmx/loops/ and validators/ files into each repo and watch them drift.

Shared skills are discoverable: developers ask their agent what's available, and it lists matches from every source. See Custom Skills.

For how to structure org-wide and team-level config, see Team Setup.

How resolution works

A shared source adds a tier between your repo's own files and the defaults bundled with dmx:

  1. 1Your repo
    Repo overrides

    App repo

    .dmx/loops/.dmx/skills/validators/
  2. 2team-frontend
    Team layer

    Shared source, declared first

    .dmx/vendor/team-frontend/
  3. 3org-wide
    Organization baseline

    Shared source, declared second

    .dmx/vendor/org-wide/
  4. 4Bundled with dmx
    Defaults

    Ships with the dmx package

    spec, plan, dev, validate, release loops and /dmx/* skills
dmx uses the first layer that has the file. It overrides the same file in every layer below.

The repo always wins. A file at .dmx/loops/dev.yaml overrides a shared dev.yaml, which overrides the bundled Dev Loop. Among several shared sources, the first one declared wins. An override replaces the whole file; dmx doesn't merge YAML or skill content across layers.

A repo with no .dmx/shared-sources.yaml resolves exactly as before: app repo, then bundled.

Declaring sources

Declare sources in .dmx/shared-sources.yaml:

shared_sources:
  - name: team-frontend
    source: "git::https://github.com/acme/dmx-frontend.git//?ref=v2.1.0"
  - name: org-wide
    source: "git::https://github.com/acme/dmx-shared.git//?ref=v1.4.0"

Order matters: the first source listed wins when two define the same name. List the most specific source first, so a team's config takes precedence over the organization's baseline.

Each entry has two fields:

FieldDescription
nameShort identifier for the source. Becomes the folder name under .dmx/vendor/. Must be a plain slug: letters, digits, _, and -, not starting with -. Must be unique.
sourceGit address of the source, pinned to a ref.

The source address uses the same git:: convention Terraform uses for module sources:

git::<url>[//<subdir>]?ref=<tag|branch|sha>
  • <url>: any URL git clone accepts: HTTPS or SSH, on GitHub, GitHub Enterprise, GitLab, or any other git host.
  • //<subdir>: optional. A path within the source repo where loops/, skills/, and validators/ live, if they aren't at its root. Must be relative, and can't contain a .. segment.
  • ?ref=: required. A tag, branch, or commit SHA. There's no default-branch fallback — every source has to pin something. Pin a tag or SHA for reproducible behavior; a branch name gets whatever is on that branch each time you sync.

This file is kept separate from .dmx/config.md on purpose. config.md is loaded into every prompt; shared-source config is only needed when resolving a loop, skill, or validator and when syncing.

Shaping a shared source repo

A shared source is a plain git repository with any of these top-level directories (or under the //<subdir> you point at):

dmx-shared/
├── loops/
│   └── hotfix.yaml
├── skills/
│   ├── deploy-preview.md          # flat skill
│   └── security-review/           # folder-shaped skill
│       ├── SKILL.md
│       ├── scripts/
│       └── references/
└── validators/
    └── security_scan.py

Each directory follows the same rules as its counterpart in an app repo: loops are loop configs, validators follow the validator contract, and skills are Markdown files with frontmatter.

At least one of loops/, skills/, or validators/ must exist, or /dmx/sync rejects the source.

Skill shapes

Skills can take either of two shapes:

  • Flat: skills/{name}.md, dmx's own format.
  • Folder: skills/{name}/SKILL.md, the agentskills.io / Claude Code / Cursor convention, with optional scripts/, references/, and assets/ folders next to it.

This means you can point a shared source at an existing standards-shaped skills repo without restructuring it for dmx. If both shapes exist for the same name, the flat file wins.

When a folder-shaped skill runs, dmx tells the agent the skill's root directory (for example, .dmx/vendor/org-wide/skills/security-review/) so it can resolve the scripts/, references/, and assets/ paths the skill mentions. If the skill's frontmatter declares dependencies:, dmx surfaces them to the agent as an explicit note. dmx doesn't install them for you.

Every entry under skills/ must be one of these two shapes. A stray file, or a folder without a SKILL.md, fails the sync for that source. Hidden entries like .gitkeep and .DS_Store are ignored.

Both shapes work in every tier, not just shared sources: your repo's own .dmx/skills/ and dmx's bundled skills resolve them the same way.

Syncing with /dmx/sync

dmx never fetches a shared source while a loop runs. Instead, /dmx/sync vendors each source into your repo, where it's committed like any other .dmx/ file:

/dmx/sync

For each declared source, /dmx/sync:

  1. Clones the source at its pinned ref
  2. Copies its tree into .dmx/vendor/{name}/, replacing what was there before. This is a plain copy, not a submodule or nested git repo.
  3. Writes .dmx/vendor/{name}/.lock.json, recording the commit SHA the ref resolved to
  4. Checks for name collisions across your repo and every declared source

Then it commits .dmx/vendor/ and .dmx/shared-sources.yaml and pushes the branch.

Run it whenever you add a source or bump a ref, then open a PR like any other dependency update. If nothing changed since the last sync, it reports that you're already up to date and makes no commit.

Run it on a branch

/dmx/sync produces a commit, so it's blocked on your integration branch (branch_base in .dmx/config.md), the same way other dmx write paths are. Running it there stops with:

Cannot run /dmx/sync from `main` — it commits vendored files directly, and every
other write path in dmx requires that go through a reviewed PR rather than landing on
`main` directly.

Create a branch first, e.g.:
  git checkout -b chore/sync-shared-sources

Then run /dmx/sync again.

When a source fails

If .dmx/shared-sources.yaml itself is invalid (bad YAML, a missing ?ref=, an invalid or duplicate name, or a bad subdir), nothing is synced and /dmx/sync shows the error.

Otherwise each source is synced on its own, and a failure names its cause:

CauseWhat it means
Clone failedThe URL is wrong, or this machine's git credentials can't reach it
Ref not foundThe ref doesn't exist — it may have been deleted, renamed, or force-pushed
Subdir not foundThe //<subdir> in the address doesn't exist at that ref
Not a shared sourceNone of loops/, skills/, or validators/ exist at the resolved path
Malformed skillsAn entry under skills/ is neither {name}.md nor {name}/SKILL.md

If some sources fail and others succeed, /dmx/sync tells you which failed and why, and asks whether to commit the ones that worked or stop and fix the config first. It never commits a partial sync without asking.

Collisions

After vendoring, /dmx/sync checks loops, skills, and validators for the same name defined in more than one place: two sources that both define spec.yaml, say, or a local skill that shadows an org-wide one. Skills are compared by logical name, so review.md in one source collides with review/SKILL.md in another.

A collision is a warning, not a failure. The sync still commits, and the warning names the winner:

`spec.yaml` exists both locally (`.dmx/loops/`) and in `org-wide` — the local copy wins
and it is fully shadowed. If this local file isn't meant to be a deliberate override,
remove it.

Because the warnings appear in the sync output, an unintended shadow shows up in review instead of surprising someone at loop-run time. To fix one, delete or rename the file that shouldn't win, or reorder shared_sources.

Credentials and private repositories

Network access and git credentials are only needed when you run /dmx/sync. Loops read the vendored copy, so they don't need either.

/dmx/sync runs plain git, so it uses whatever credentials your environment's git already has: an SSH agent, gh auth, or a CI deploy key or machine-user token. There's nothing dmx-specific to configure, and private repositories on GitHub Enterprise, GitLab, or any other host work the same way.

Tips

Pin to tags. A tag gives every repo the same content, and the .lock.json SHA lets you confirm exactly what was vendored. Bump the tag in a PR when you want the update.

Keep overrides deliberate. Your repo's own files always win, so a leftover .dmx/loops/dev.yaml silently replaces the org-wide version. Read the collision warnings after each sync.

Review vendored diffs. A sync PR shows exactly what changed in the shared loops, skills, and validators. Review it like any other dependency bump — validators in particular run as code on every loop.

On this page