---
title: Template Synchronization
read_when:
  - modifying commit message prompts
  - encountering test_file_sync.py failures
  - editing commit-message-prompt.md in any location
tripwires:
  - action: "editing commit-message-prompt.md in either location"
    warning: "Update BOTH copies: .claude/skills/erk-diff-analysis/references/commit-message-prompt.md AND packages/erk-shared/src/erk_shared/gateway/gt/commit_message_prompt.md. CI enforces byte-equality."
last_audited: "2026-02-08 00:00 PT"
audit_result: edited
---

# Template Synchronization

Certain shared content must exist in two places because it serves two execution contexts that cannot share a file path. This document explains why the duplication exists, where it happens, and how to avoid the main pitfall.

## Why Two Copies Exist

The commit message prompt is consumed by two completely different runtimes:

1. **Claude's skill loader** reads `.claude/skills/erk-diff-analysis/references/commit-message-prompt.md` as context when the `erk-diff-analysis` skill executes
2. **Python's `_load_prompt()`** reads `packages/erk-shared/src/erk_shared/gateway/gt/commit_message_prompt.md` at runtime via `prompts.py`

<!-- Source: packages/erk-shared/src/erk_shared/gateway/gt/prompts.py, _load_prompt -->

These runtimes have no shared filesystem convention — Claude skills load from `.claude/skills/` while Python packages load from their own package tree. There is no way to make one file serve both consumers without introducing a build step or symlink, both of which add fragile indirection.

If the copies diverge, commit messages will differ depending on whether they were generated by Claude (via the skill) or by the Python CLI (via `erk exec gt commit-message`). This silent inconsistency breaks the user's mental model of deterministic output.

## The Enforcement Gap

There is **no at-edit-time validation**. An agent or human can update one file and commit without touching the other. The divergence is only caught when CI runs the byte-equality test.

<!-- Source: tests/unit/test_file_sync.py, test_diff_analysis_guide_in_sync_with_commit_message_prompt -->

**Common mistake**: Editing the skill copy (under `.claude/skills/`) to fix a Claude-side prompt issue, then forgetting the Python package copy exists.

**CI error message**: `"Skill prompt and Python package prompt are out of sync!"`

## Update Workflow

When modifying the commit message prompt:

1. Edit **both** files with identical content
2. Verify byte-equality before committing:
   ```bash
   diff .claude/skills/erk-diff-analysis/references/commit-message-prompt.md \
        packages/erk-shared/src/erk_shared/gateway/gt/commit_message_prompt.md
   ```

## Note: Custom Prompt Override

<!-- Source: packages/erk-shared/src/erk_shared/gateway/gt/prompts.py, get_commit_message_prompt -->

The Python runtime supports a per-repo override via `.erk/prompt-hooks/commit-message-prompt.md`. When this file exists, it completely replaces the built-in prompt for CLI-generated commit messages. This override is independent of the synchronization requirement — the two built-in copies must still match because the override only applies to the Python path, not to the Claude skill path.

## Related Documentation

- [Commit Message Generation](commit-message-generation.md) — How the prompt is consumed in PR workflows
