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:
- 1Your repoRepo overrides
App repo
.dmx/loops/.dmx/skills/validators/ - 2team-frontendTeam layer
Shared source, declared first
.dmx/vendor/team-frontend/ - 3org-wideOrganization baseline
Shared source, declared second
.dmx/vendor/org-wide/ - 4Bundled with dmxDefaults
Ships with the dmx package
spec, plan, dev, validate, release loops and /dmx/* skills
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:
| Field | Description |
|---|---|
name | Short 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. |
source | Git 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 URLgit cloneaccepts: HTTPS or SSH, on GitHub, GitHub Enterprise, GitLab, or any other git host.//<subdir>: optional. A path within the source repo whereloops/,skills/, andvalidators/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.pyEach 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 optionalscripts/,references/, andassets/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/syncFor each declared source, /dmx/sync:
- Clones the source at its pinned
ref - Copies its tree into
.dmx/vendor/{name}/, replacing what was there before. This is a plain copy, not a submodule or nested git repo. - Writes
.dmx/vendor/{name}/.lock.json, recording the commit SHA the ref resolved to - 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:
| Cause | What it means |
|---|---|
| Clone failed | The URL is wrong, or this machine's git credentials can't reach it |
| Ref not found | The ref doesn't exist — it may have been deleted, renamed, or force-pushed |
| Subdir not found | The //<subdir> in the address doesn't exist at that ref |
| Not a shared source | None of loops/, skills/, or validators/ exist at the resolved path |
| Malformed skills | An 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.