Template Updates
Receive SvelDocs template updates through reviewable pull requests.
How Template Updates Work
GitHub creates an independent repository from a template. The new repository does not remain connected to the template and does not receive later changes automatically.
SvelDocs includes an opt-in workflow that checks BranDenn/SvelDocs for updates every Monday and can also be run manually. When shared infrastructure changes, it opens a pull request in your repository for review.
The workflow never merges updates automatically. Your normal reviews, status checks, and branch protection rules still apply.
Enable Update Pull Requests
GitHub may prevent workflows from creating pull requests until you enable the repository setting:
- Open Settings > Actions > General in your repository.
- Under Workflow permissions, select Read and write permissions.
- Select Allow GitHub Actions to create and approve pull requests.
- Save the changes.
No personal access token is required. The workflow uses the repository's temporary GITHUB_TOKEN and reads the public SvelDocs template.
Choose The SvelDocs Directory
The workflow supports both standalone repositories and monorepos. Set SVELDOCS_PATH near the top of .github/workflows/template-sync.yml to the directory that contains the SvelDocs app:
env:
SVELDOCS_PATH: '.' # SvelDocs is at the repository root For a monorepo with the SvelDocs app under docs, use:
env:
SVELDOCS_PATH: 'docs' This setting applies to scheduled and manual runs. It must be a relative path and cannot contain .. segments.
Keep template-sync.yml under the repository root's .github/workflows directory, even when the SvelDocs app is under docs. GitHub does not discover workflow files inside docs/.github/workflows.
Run An Update Check
The scheduled check runs weekly. To check immediately:
- Open the Actions tab in your repository.
- Select Sync Template Updates.
- Select Run workflow.
If updates are available, the workflow creates a pull request from a uniquely named chore/template-sync-* branch. Review its checks and resolve any conflicts before merging it. Repeated runs update the same open pull request instead of creating duplicates. If you close one without merging, a later update uses a new branch and pull request, so the closed pull request cannot block future updates.
name: Sync Template Updates
on:
schedule:
- cron: '0 9 * * 1'
workflow_dispatch:
env:
# Set to 'docs' when SvelDocs is located in a monorepo subdirectory.
SVELDOCS_PATH: '.'
jobs:
sync-template:
if: github.repository != 'BranDenn/SvelDocs'
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Sync template-owned paths
id: sync
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SOURCE_REPOSITORY: https://github.com/BranDenn/SvelDocs.git
run: |
if [[ "$SVELDOCS_PATH" = /* || "$SVELDOCS_PATH" =~ (^|/)\.\.(/|$) ]]; then
echo "SVELDOCS_PATH must be a relative path without '..' segments" >&2
exit 1
fi
target_path="${SVELDOCS_PATH%/}"
[[ -n "$target_path" ]] || target_path='.'
source_path="$(mktemp -d)"
git clone --depth 1 "$SOURCE_REPOSITORY" "$source_path"
base_commit="$(git rev-parse HEAD)"
branch="$(
gh pr list \
--state open \
--base "$GITHUB_REF_NAME" \
--json headRefName \
--jq 'map(select(.headRefName | startswith("chore/template-sync-"))) | .[0].headRefName // ""'
)"
if [[ -n "$branch" ]]; then
git fetch origin "$branch:refs/remotes/origin/$branch"
else
branch="chore/template-sync-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT"
fi
git checkout -B "$branch" "$base_commit"
ignore_file="$target_path/.templatesyncignore"
while IFS= read -r managed_path || [[ -n "$managed_path" ]]; do
[[ -n "$managed_path" && "$managed_path" != \#* ]] || continue
if [[ "$managed_path" = /* || "$managed_path" =~ (^|/)\.\.(/|$) ]]; then
echo "Invalid managed path: $managed_path" >&2
exit 1
fi
source_item="$source_path/$managed_path"
target_item="$target_path/$managed_path"
skip_managed_path=false
directory_excludes="$(mktemp)"
if [[ -f "$ignore_file" ]]; then
while IFS= read -r ignored_path || [[ -n "$ignored_path" ]]; do
[[ -n "$ignored_path" && "$ignored_path" != \#* ]] || continue
ignored_path="${ignored_path#/}"
ignored_path="${ignored_path%/}"
if [[ "$ignored_path" =~ (^|/)\.\.(/|$) ]]; then
echo "Invalid ignored path: $ignored_path" >&2
exit 1
fi
managed_root="${managed_path%/}"
if [[ "$managed_root" == "$ignored_path" || "$managed_root" == "$ignored_path/"* ]]; then
skip_managed_path=true
break
fi
if [[ "$ignored_path" == "$managed_root/"* ]]; then
echo "/${ignored_path#"$managed_root/"}" >> "$directory_excludes"
fi
done < "$ignore_file"
fi
if [[ "$skip_managed_path" == true ]]; then
continue
fi
if [[ -d "$source_item" ]]; then
mkdir -p "$target_item"
rsync --archive --delete --exclude-from="$directory_excludes" "$source_item/" "$target_item/"
elif [[ -f "$source_item" ]]; then
mkdir -p "$(dirname "$target_item")"
cp "$source_item" "$target_item"
else
rm -rf "$target_item"
fi
done < "$source_path/.templatesyncpaths"
git add -A -- "$target_path"
if git diff --cached --quiet; then
echo 'has_changes=false' >> "$GITHUB_OUTPUT"
exit 0
fi
template_revision="$(git -C "$source_path" rev-parse --short HEAD)"
git config user.name 'github-actions[bot]'
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
git commit -m "chore: sync SvelDocs template ($template_revision)"
git push --force-with-lease origin "$branch"
echo 'has_changes=true' >> "$GITHUB_OUTPUT"
echo "branch=$branch" >> "$GITHUB_OUTPUT"
- name: Create update pull request
if: steps.sync.outputs.has_changes == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HEAD_BRANCH: ${{ steps.sync.outputs.branch }}
run: |
open_prs="$(
gh pr list \
--state open \
--base "$GITHUB_REF_NAME" \
--head "$HEAD_BRANCH" \
--json number \
--jq 'length'
)"
if [[ "$open_prs" != '0' ]]; then
exit 0
fi
gh pr create \
--base "$GITHUB_REF_NAME" \
--head "$HEAD_BRANCH" \
--title 'chore: sync SvelDocs template updates' \
--body "Sync template-owned infrastructure from \`BranDenn/SvelDocs\` into \`$SVELDOCS_PATH\`.
Review the changes and resolve any conflicts before merging. Site content,
configuration, branding, styling, and workflow files are not managed." Change The Schedule
The default cron expression runs at 09:00 UTC every Monday:
on:
schedule:
- cron: '0 9 * * 1'
workflow_dispatch: Change the final number to choose another day: 0 or 7 is Sunday, 1 is Monday, and 6 is Saturday. For example, use '0 9 * * 5' to check every Friday at 09:00 UTC. GitHub Actions schedules use UTC and may start later during periods of high demand.
To disable scheduled checks and keep only the Run workflow button, replace the trigger with:
on:
workflow_dispatch: What Gets Updated
Update pull requests include shared application code, routes, Markdown processing plugins, dependencies, and build configuration.
The .templatesyncpaths file explicitly lists the template-owned files and directories that can be changed:
# Framework directories
plugins/
src/lib/components/
src/lib/docs/
src/lib/markdown/
src/params/
src/routes/
src/types/
# Framework entry points and configuration
src/app.d.ts
src/app.html
src/lib/utils.ts
eslint.config.js
package.json
bun.lockb
svelte.config.js
tsconfig.json
vite.config.ts
# Keep this ownership manifest in downstream repositories
.templatesyncpaths Everything outside that list remains untouched, including documentation content, site configuration, styling, environment files, and unrelated monorepo applications. Files removed from a managed directory in the template are also removed from that directory in the update pull request.
Preserve Custom Files
Use .templatesyncignore for site-specific files that are located inside a managed directory. Paths are relative to the SvelDocs app, regardless of whether SVELDOCS_PATH is . or docs:
# Site-specific navigation and branding
src/lib/docs/server/navigation/doc-navigation.config.ts
src/lib/components/docs/header/header-logo.svelte
src/lib/components/logo/ For example, use src/lib/docs/server/navigation/doc-navigation.config.ts, not docs/src/lib/docs/server/navigation/doc-navigation.config.ts, when the app is under docs. Add one exact file or directory path per line. The workflow preserves those paths when synchronizing their parent directories.
The default exclusions protect the navigation configuration, header logo wrapper, and shared logo component. Add other locally customized files before running the workflow. Because .templatesyncignore is downstream-owned, template update pull requests do not replace it.
Workflow Updates
GitHub does not allow GITHUB_TOKEN to create or update files under .github/workflows. Those files are therefore excluded from template update pull requests.
Compare your workflow files with the SvelDocs template workflows when release notes call out workflow changes. This includes updates to the GitHub Pages deployment workflow and the template sync workflow itself.
A fine-grained personal access token or GitHub App can synchronize workflow files, but it adds a long-lived credential or extra application setup. The included workflow intentionally avoids that requirement.