# crefft Config Sync — downstream template # # TEMPLATE. This file does not run in crefft itself: it lives outside # .github/workflows/ so GitHub cannot schedule it here. Copy it into your own # project to keep crefft's agent and command definitions up to date. # # Install: # 1. Copy to .github/workflows/sync-crefft.yml in your project. # 2. Review CREFFT_REF and optionally set CREFFT_COMMIT below. # 3. Enable "Allow GitHub Actions to create and approve pull requests" in # Settings > Actions > General. Without it, create-pull-request fails. # 4. Optionally set CREFFT_SYNC_TOKEN if you need the pull request to # trigger your own CI; GITHUB_TOKEN-authored pull requests deliberately # do not. # # See configs/github/README.md for the full adoption notes. name: Sync crefft Configs on: schedule: # Weekly on Monday at 09:00 UTC. - cron: '0 9 * * 1' workflow_dispatch: inputs: dry_run: description: 'Preview changes without creating a pull request' required: false default: false type: boolean # Least privilege at the workflow level; the job widens only what it needs. permissions: contents: read env: CREFFT_REPO: agh/crefft CREFFT_REF: v2026.10.1 # Optional full commit SHA: the applier verifies it against the release checkout. CREFFT_COMMIT: '' jobs: sync: name: Sync owned crefft configuration runs-on: ubuntu-latest permissions: contents: write pull-requests: write steps: - name: Checkout project uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Checkout crefft uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: ${{ env.CREFFT_REPO }} ref: ${{ env.CREFFT_REF }} path: .crefft-upstream persist-credentials: false - name: Sync configs id: sync env: DRY_RUN: ${{ inputs.dry_run }} run: | set -euo pipefail # Verify the optional pin before executing code from the upstream checkout. commit="$(git -C .crefft-upstream rev-parse HEAD)" if [ -n "${CREFFT_COMMIT}" ] && [ "${commit}" != "${CREFFT_COMMIT}" ]; then printf '%s\n' '::error::crefft commit does not match CREFFT_COMMIT' >&2 exit 1 fi version="$(cat .crefft-upstream/VERSION)" if [[ ! "${version}" =~ ^[0-9]{4}\.(1[0-2]|[1-9])\.(0|[1-9][0-9]*)$ ]]; then printf '%s\n' '::error::VERSION must contain one calendar version' >&2 exit 1 fi project_dir="${GITHUB_WORKSPACE}" if [ "${DRY_RUN}" = 'true' ]; then # Preview in a disposable project clone; never restore or clean the workspace. preview_dir="$(mktemp -d "${RUNNER_TEMP}/crefft-preview.XXXXXXXX")" trap 'rm -rf -- "${preview_dir}"' EXIT git clone --quiet --no-hardlinks "${GITHUB_WORKSPACE}" "${preview_dir}" project_dir="${preview_dir}" fi args=(--ref "${CREFFT_REF}") if [ -n "${CREFFT_COMMIT}" ]; then args+=(--commit "${CREFFT_COMMIT}") fi .crefft-upstream/scripts/sync-claude-config.sh "${args[@]}" "${project_dir}" printf 'version=%s\ncommit=%s\n' "${version}" "${commit}" >> "${GITHUB_OUTPUT}" changed="$(git -C "${project_dir}" status --porcelain --untracked-files=all -- .claude)" if [ -n "${changed}" ]; then printf '%s\n' 'changes=true' >> "${GITHUB_OUTPUT}" else printf '%s\n' 'changes=false' >> "${GITHUB_OUTPUT}" fi { printf '%s\n' 'report<> "${GITHUB_OUTPUT}" - name: Dry run summary # workflow_dispatch delivers a real Boolean, so compare against true # rather than the string `true`. On a scheduled run inputs.dry_run is # null and this step is skipped. if: inputs.dry_run == true env: SYNC_VERSION: ${{ steps.sync.outputs.version }} SYNC_CHANGES: ${{ steps.sync.outputs.changes }} SYNC_REPORT: ${{ steps.sync.outputs.report }} run: | { printf '%s\n' '## crefft sync — dry run' '' printf '%s\n' "Upstream version: \`${SYNC_VERSION}\`" '' if [ "${SYNC_CHANGES}" = 'true' ]; then printf '%s\n' 'A pull request would be opened with these changes:' '' printf '%s\n' '```' "${SYNC_REPORT}" '```' else printf '%s\n' 'No changes detected.' fi } >> "${GITHUB_STEP_SUMMARY}" - name: Create pull request if: steps.sync.outputs.changes == 'true' && inputs.dry_run != true uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 with: token: ${{ secrets.CREFFT_SYNC_TOKEN || secrets.GITHUB_TOKEN }} commit-message: | chore: sync crefft configs to ${{ steps.sync.outputs.version }} Apply ${{ env.CREFFT_REPO }}@${{ env.CREFFT_REF }} with its ownership receipt. Upstream commit: ${{ steps.sync.outputs.commit }} title: 'chore: sync crefft configs to ${{ steps.sync.outputs.version }}' body: | ## crefft config sync Applies the pinned Claude Code configuration from [${{ env.CREFFT_REPO }}](https://github.com/${{ env.CREFFT_REPO }}). - Upstream version: `${{ steps.sync.outputs.version }}` - Source: `${{ env.CREFFT_REPO }}@${{ env.CREFFT_REF }}` - Commit: `${{ steps.sync.outputs.commit }}` The upstream sync script replaces or removes only receipt-owned files. Project additions survive, and existing settings are preserved. ### Changes ``` ${{ steps.sync.outputs.report }} ``` ### Before merging - Confirm no project-specific overrides were overwritten. - Exercise the agents and commands you rely on. - Review any permission or hook changes in `settings.json`. add-paths: .claude/ branch: chore/sync-crefft delete-branch: true labels: | dependencies automated