The three-copy rule

Exhaustive reference for where DOS skills, hooks, and config live — the three canonical copies and how to keep them in sync.

Every DOS skill, hook, and configuration file lives in three places at once. When you edit one, you must edit all three. Skipping any copy silently desynchronizes the system.

From Durante/CLAUDE.md:

LocationPurpose
~/.claude/skills/Live installation (what runs in your current session)
Releases/v0.0.3/.claude/skills/Submodule tracked in cc-durante-studio, tagged per release
Packs/*/src/Pack source — distributable, generic, safe to publish standalone

<!-- brand-voice:exempt — technical invariant, not marketing claim --> Each copy serves a different audience and lifecycle. Dropping any one breaks a guarantee:

  • Without ~/.claude/, you cannot test the change in a real session before committing it.
  • Without the submodule, the next durante upgrade overwrites your work with the old version.
  • Without Packs/*/src/, downstream distribution regresses.

The rule in one example

Don't

Edit a skill only under ~/.claude/skills/simplify/SKILL.md. It works in your current session. Next week, someone runs durante upgrade. The upgrade clones the release, wipes ~/.claude/, restores your backups — and your edit, which never made it into the submodule, is gone. The pack source is also stale, so the next Pack publish ships the old behavior.

Do

Edit ~/.claude/skills/simplify/SKILL.md and validate in a live session. Mirror into Releases/v0.0.3/.claude/skills/simplify/SKILL.md and commit inside the submodule. Mirror into Packs/Utilities/src/Simplify/SKILL.md. Commit the updated submodule pointer in the parent repo. Now all three stay in lockstep through upgrades and Pack publishes.

Submodule workflow

Always commit the submodule first, then the parent. The parent repo only stores a pointer to a commit inside the submodule — committing the parent first creates a dangling reference that cannot be fetched.

Commit order
$ 1. Inside the submodulecd Releases/v0.0.3/.claudegit add <files> && git commit -m "message"2. In the parentcd ~/Durantegit add Releases/v0.0.3/.claude && git commit -m "Update Durante release"

When all three must update

ChangeLiveSubmodulePack
Skill body / SKILL.md edityesyesyes
New skill fileyesyesyes
Hook handler in hooks/handlers/yesyesyes
Prompt templates under Prompts/yesyesyes
settings.json schema-level changeyesyesn/a
New tool under DOS/Tools/yesyesyes (pack src/Lib/ if pack-scoped)

Edit just one copy and assume it will be overwritten the next time the other two sync.

When one copy is intentional

  • PRDs under MEMORY/WORK/ — private work tracking for the current machine. Never mirrored.
  • MEMORY/ state — work.json, reflections, session progress, licenses. Backed up during durante upgrade and restored, but never committed.
  • Work in progress — half-written skills iterate under ~/.claude/ first, then fold into the submodule and pack source when stable.
  • Pack documentationINSTALL.md, VERIFY.md, and README.md inside a pack live only under Packs/*/.

Ordering in practice

  1. Edit under ~/.claude/ and validate in a live session.
  2. Mirror into Releases/v0.0.3/.claude/ and commit inside the submodule.
  3. Mirror into Packs/*/src/ and commit in the parent.
  4. Commit the updated submodule pointer in the parent repo.

The parent commit always lands last so the parent reference can never point at an unpushed submodule state.

Was this page helpful?