#620·Trellis

`trellis init` corrupts the manifest hash of mixed-ownership files under `.trellis/` (e.g. `config.yaml`), causing the next `trellis update` to silently overwrite user customizations

Author: TianYiTianCreated Sep 15, 2026Updated Sep 15, 2026
Labelsbugpkg:cli

Bug Description

trellis init --<platform> (the "add platform to an existing project" path) rewrites .trellis/.template-hashes.json by re-hashing every file under .trellis/ against its current on-disk content. For mixed-ownership files such as .trellis/config.yaml this records the user-modified content as the baseline, erasing the "Modified by you" protection. The next trellis update then classifies the file as "Template updated (will auto-update)" and silently overwrites the user's customizations.

Per update.js's own comment, mixed-ownership files (AGENTS.md, .github/copilot-instructions.md, .trellis/config.yaml) are supposed to differ from their recorded template hash — that difference is what triggers the "Modified by you (need your decision)" branch and protects local edits. But initializeHashes() (dist/utils/template-hash.js, ~L275) recursively walks all of .trellis/ and stores computeHash(currentContent) per file. EXCLUDE_FROM_HASH only excludes workspace/, tasks/, spec/, .developer, .backup-*, .version, .gitignore, .template-hashes.jsonnot config.yaml, workflow.md, scripts/, or agents/. So after init, config.yaml's manifest entry equals the local customized hash → update treats it as unmodified and overwrites it.

Related: #575 fixed the same class of receipt problem on the update path (writing back unchangedFiles); this is the parallel defect on the init path (initializeHashes re-baselining user-owned files).

Steps to Reproduce

  1. trellis init a project; edit .trellis/config.yaml (e.g. set session_commit_message: "custom" and codex.dispatch_mode: inline).
  2. Run trellis update --dry-runconfig.yaml correctly shows under "Modified by you (need your decision)".
  3. Run trellis init --dsh (or any platform) to add a platform.
  4. Run trellis update --dry-run again → config.yaml has moved to "Template updated (will auto-update)". The manifest now stores the customized content's hash.
  5. A subsequent plain trellis update silently overwrites the customizations.

Suggested fix: initializeHashes should not re-baseline files the user may own. Either (a) exclude .trellis/config.yaml and other mixed-ownership paths from the .trellis/ re-hash, matching update.js's mixed-ownership set; or (b) only record hashes for files init actually wrote in that invocation (scope the re-hash to reinitWritten / the newly-added platform's file set), not the whole .trellis/ tree.

Trellis Version

@mindfoldhq/trellis 0.7.0-beta.4 (also present on the 0.6.x line; observed while running trellis init --dsh --devin on a project whose config.yaml carried local customizations)

Node.js Version

v24

Operating System

Windows