About update-project
update-project is a repository-maintenance skill for projects generated with Copier. It routes legacy task workflows to migration before updating templates, then applies and validates an update while tracking local changes.
Key features
- 01Preflight routing for migration or update
- 02Stable and unstable template channels
- 03Copier three-way update
- 04Language profile and package options
- 05Changed-path reconciliation and validation
Use cases
- 01Updating a Copier-managed repository from its recorded Git source
- 02Migrating repositories with legacy tasks.md files before template updates
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ robertderose/ dstack --skill update-projectAfter installing, type/update-projectin Claude Code to confirm it loaded.
Bundled filesscripts/layout_contract.pyscripts/update-project.py
Details
From the project READMEPurpose
Use this skill for an existing repository. It first decides whether the repository is ready for a Copier update, needs
legacy-workflow migration, or is the dstack template source eligible for explicit self-adoption. A normal update
resolves the recorded stable or unstable channel from the Git source in .copier-answers.yml, then applies Copier's
three-way update so project-owned changes remain local.
Resolve <skill-dir> as the directory containing this SKILL.md; resolve <core-dir> as its sibling dstack-core
skill directory. Run the update helper through the shared workflow runner so uv reuses one environment for the workflow
rather than creating one environment per script path.
Shared trust contract
Before executing this workflow, read and follow
../dstack-core/references/TRUST-AND-AUTHORITY.md. That contract is
normative for this workflow. If it conflicts with this skill, follow the more restrictive rule and report the conflict.
Startup version evidence
Before applying an update or migration, follow
../dstack-core/references/SKILL-VERSION.md for update-project. After
the read-only preflight, capture the exact one-line output and include it in the update/migration JSON or response
before mutation. A stale result warns with npx skills update; unavailable records that no freshness claim was made
and does not block offline work.
Update-specific authority:
- Invocation authorizes preflight inspection. It authorizes a local Copier update and dedicated reconciliation commit only after the repository passes migration routing. It does not authorize push, merge, force-push, branch deletion, or unrelated project changes.
- The default channel is
stable, which selects the newest stable PEP 440-compatiblevX.Y.Zrelease.unstableselects the recorded source's default-branch HEAD. Existing projects preserve their recorded channel. - Every selected tag, branch, or explicit revision is resolved to a reachable commit and that exact SHA is persisted in
_commit; installed skill metadata is never template provenance. - Explicit development revisions must be reported before mutation. Template-source self-adoption is never implicit.
1. Route legacy repositories before update
Run the non-mutating preflight first:
uv run <core-dir>/scripts/run-workflow.py <skill-dir>/scripts/update-project.py --preflight --json
The helper inspects:
- whether
.copier-answers.ymlexists; - active
tasks.mdfiles anywhere in the project, excluding tool, template, archive, migration, and vendored directories; - initialized Beads state, without treating a copied formula as an initialized database.
When recommended_workflow is migrate-workflow, do not run Copier update. Explain the detected task files and missing
Beads state, then ask exactly one question with AskUserQuestion: Run /migrate-workflow now?
- If the user agrees, execute
/migrate-workflowand let that workflow adopt the current tagged template, manually reconcile the rendered new-project structure, initialize Beads, and import the legacy task state. - If the user declines, stop without running Copier or changing files.
- After migration completes and commits its checkpoints, rerun this preflight before considering an update.
This routing applies whether Copier state is already present or absent. A repository with legacy tasks.md files and no
Beads state must migrate before template update.
For Copier-managed projects whose answers do not yet contain language_profiles, use the preflight's root-only
suggested_language_profiles. It maps pyproject.toml to Python, tsconfig.json or package.json to TypeScript,
Cargo.toml to Rust, go.mod to Go, mix.exs to Elixir, and flake.nix to Nix. Ask the user to confirm the
suggestions; never apply them automatically. If none are found or accepted, offer the exclusive other profile.
Recursive package discovery is outside this workflow.
Older answer files default to single-package with no packages. Preserve that state unless the user explicitly requests
conversion. Convert only with --repository-layout monorepo and one --monorepo-package '<JSON object>' per complete
package; never infer packages. The preflight lists exact destinations and occupied paths and rejects invalid, reserved,
overlapping, case-colliding, or symlinked paths before revision lookup or rendering. Package objects contain exactly
display_name, slug, path, and language_profiles; preserve display names and acronyms exactly.
2. Update preconditions
Continue with a normal update only when preflight recommends update-project and:
.copier-answers.ymlrecords a Git-backed_src_pathplus_commit;- the initial scaffold or completed migration checkpoint is committed;
- the worktree is clean unless the user explicitly accepts a dirty update;
- the recorded Git source can resolve the selected channel or explicit revision.
3. Apply the template update
Update through the recorded channel, or override it explicitly:
uv run <core-dir>/scripts/run-workflow.py <skill-dir>/scripts/update-project.py
uv run <core-dir>/scripts/run-workflow.py <skill-dir>/scripts/update-project.py --stable
uv run <core-dir>/scripts/run-workflow.py <skill-dir>/scripts/update-project.py --unstable
Preview, include prereleases, or explicitly select another revision:
uv run <core-dir>/scripts/run-workflow.py <skill-dir>/scripts/update-project.py --pretend
uv run <core-dir>/scripts/run-workflow.py <skill-dir>/scripts/update-project.py --prereleases --pretend
uv run <core-dir>/scripts/run-workflow.py <skill-dir>/scripts/update-project.py --vcs-ref <release-tag>
uv run <core-dir>/scripts/run-workflow.py <skill-dir>/scripts/update-project.py --vcs-ref <reviewed-tag-branch-or-commit>
uv run <core-dir>/scripts/run-workflow.py <skill-dir>/scripts/update-project.py --add-profile typescript
uv run <core-dir>/scripts/run-workflow.py <skill-dir>/scripts/update-project.py --remove-profile python --add-profile other
Omitting profile flags preserves the recorded selection. Add/remove flags are repeatable, idempotent set operations; the
same profile cannot appear in both sets. other is exclusive, and removing the final recognized profile requires adding
other in the same invocation.
Updates reuse structured project-brief values already recorded by Copier. For an older project missing any of purpose,
users, scope, boundaries, or project kind, ask one question at a time and pass the corresponding --purpose, --users,
--scope, --boundaries, and --project-kind flags. Never derive missing values from a legacy description.
An explicit branch, commit, or HEAD is a one-shot override. The helper persists the exact resolved commit while
leaving the selected stable/unstable channel as the default for the next update.
dstack self-adoption
When preflight reports update-project-adopt, run only after explicit user approval and a clean worktree:
uv run <core-dir>/scripts/run-workflow.py <skill-dir>/scripts/update-project.py --adopt --unstable \
--project-name dstack --project-slug dstack \
--purpose "<purpose>" --users "<users>" --scope "<scope>" --boundaries "<boundaries>" \
--project-kind other --language-profile python --json
Self-adoption renders the reachable remote default-branch commit in isolation, copies missing generated paths, preserves
existing dstack-owned paths, writes differing generated versions under migration/copier-adoption-candidates/, and
records exact unstable Copier state. Reconcile every candidate and remove the directory before validation or commit. It
never adopts a local-only commit or runs generated code before reconciliation.
Helper contract
The helper:
- resolves the Git root and performs migration/self-adoption routing before any revision lookup or mutation;
- reads the Copier source and previous revision from
.copier-answers.yml; - resolves the preserved or explicit channel: stable uses the greatest eligible tag by PEP 440 ordering; unstable uses the source default-branch HEAD;
- excludes prereleases by default and includes them only with
--prereleases; - verifies every selected revision is reachable and persists its exact commit SHA before reporting success;
- requires a clean worktree by default;
- applies the Copier update;
- checks only Git-visible modified and untracked files for coherent conflict markers, Git unmerged paths, and newly
produced
.rejfiles; - ignores dependency environments and other Git-ignored content such as
.venv; - when conflict-free, runs
python3 scripts/setup-tooling.py --jsonto refreshmise.lock, install with--locked, and reconcile hk hooks; - after successful tooling, runs
bd hooks installand verifies every hook reported bybd hooks list --jsonis installed and current; the separatebeads_hooksresult reports status and recovery commands; - when conflicted, skips all generated project code, reports tooling and Beads hooks as skipped, and names the recovery command;
- runs
scripts/check-docs.pywhen present; - runs storage-mode-neutral Beads smoke checks with
bd info --jsonandbd ready --json --limit 1; - validates the project feature formula when present;
- preserves or explicitly adds/removes canonical language profiles, with legacy root-manifest suggestions reported by preflight but never silently applied;
- defaults older layout answers to single-package and validates explicit package conversion before rendering;
- reports the selected release, resolved Copier commit, changed files, separate tooling and Beads hook stages, validation, warnings, conflicts, and readiness.
bd doctor is not used because it is not supported by every Beads storage mode.
4. Reconcile every changed path
Build a path-accounting ledger from the helper's changed-file output plus git status --short and
git diff --name-status. Every changed path must appear exactly once with one classification:
template change accepted;project change preserved;conflict resolved.
For each path, record the upstream change, local behavior that must remain, resolution, and validation evidence:
| Path | Classification | Upstream/local intent | Resolution | Validation |
|---|---|---|---|---|
… | template change accepted | … | … | … |
Preserve project-owned architecture, operations, development, reference, roadmap, and feature history. Stop when a path
is ambiguous; absence of a textual conflict is not acceptance. Reconciliation is incomplete while any changed path is
missing from the ledger or classified only as unknown.
After every path is accounted for, rerun project-specific validation against the final files and commit the template
update as a dedicated boundary before resuming feature work. A degraded tooling result is unresolved: run each reported
recovery command and verify a current nonempty mise.lock before classifying the update ready.
Return
Report:
- preflight route, legacy task files, Beads-state result, and user consent decision when migration was offered;
- destination and Copier source;
- previous Copier revision and channel;
- selected channel, friendly tag/branch/ref, and exact resolved revision;
- previous, suggested, and resulting language profiles;
- repository layout, exact package preflight, rendered package paths, and every unresolved candidate;
- changed files and the complete path-accounting ledger;
- real update conflicts and resolutions;
- separate tooling availability, lock, install, and hook states plus exact recovery commands;
- documentation and Beads validation;
- warnings and any unclassified path;
- readiness to resume feature work, which must be false while migration is required, conflicts or degraded tooling remain, candidates remain unresolved, the lock is stale or missing, or a changed path is unclassified.