Template Sync¶
Repos created from this template can pull configuration updates via the Template Sync workflow.
Prerequisites¶
.github/template-state.jsonmust exist (created automatically for new repos, or manually for older ones)- Allow actions to create pull-requests: repo Settings → Actions
Using Template Sync¶
- Go to Actions → Template Sync → Run workflow
- Choose a version:
latest(default),master, or a specific tag (e.g.,v1.2.3) - Optionally enable dry_run to preview changes without creating a PR
- Review and merge the created PR
.claude/toolbox/scripts/template-sync.sh --local
.claude/toolbox/scripts/template-sync.sh --local --version v1.2.3
.claude/toolbox/scripts/template-sync.sh --local --dry-run # preview only
Requires jq, git, curl, and yq (mikefarah/yq). Review changes with git diff before committing.
What Gets Synced¶
Updated: .claude/ (settings, CLAUDE.extra.md, statusline scripts), .codex/ (config.toml, hooks, rules, scripts, agents), and the sync infrastructure itself (see Syncing Workflow Files for permission requirements). Skills, commands, and hooks are managed by the plugin system — not template sync.
Preserved: Project-specific values (name, language, prompts), settings.local.json, gitignored files.
settings.json merge behavior¶
The sync uses smart-merge semantics — your downstream settings.json is "master" and upstream fills gaps:
- New keys from upstream are added (e.g., new deny patterns, new env vars)
- Existing values are never overwritten (your customizations are preserved)
- Arrays are concatenated with deduplication (e.g., new upstream deny rules are appended)
- Manifest variables (
CC_MODEL,CC_EFFORT_LEVEL, etc.) still override after the merge — these are your explicit choices
Sync Exclusions¶
If you've removed template files you don't need, prevent sync from re-adding them.
Edit .github/template-state.json and add a sync_exclusions array:
{
"schema_version": "1",
"upstream_repo": "serpro69/claude-toolbox",
"template_version": "v0.2.0",
"synced_at": "2025-01-27T10:00:00Z",
+ "sync_exclusions": [
+ ".claude/CLAUDE.extra.md",
+ ".claude/settings.json"
+ ],
"variables": { "..." : "..." }
}
Pattern syntax:
- Patterns use glob syntax where
*matches any characters including directory separators - Patterns are matched against project-relative paths (e.g.,
.claude/settings.json) - Common patterns:
.claude/CLAUDE.extra.md(single file),.codex/*(entire directory)
Behavior:
- Excluded files are NOT added if they exist upstream but not locally
- Excluded files are NOT updated if they exist in both places
- Excluded files are NOT flagged as deleted if they exist locally but not upstream
- Excluded files appear as "Excluded" in the sync report for transparency
Self-Updating Sync Script¶
The sync script is itself a synced file. When the target version ships a different template-sync.sh, the running script hands the whole run over to that copy before touching anything: it stages the upstream script in a temp location and re-executes it with the same arguments. The version that matches the templates therefore drives the entire sync — including migrations that only the newer script knows about — in one invocation, and --dry-run previews reflect exactly what will be applied.
This applies to local runs (--local), to the CI workflow's staging run, and to the --apply step that turns staged changes into a PR.
Set TEMPLATE_SYNC_NO_HANDOFF=1 to disable the handoff and run the locally installed script as-is (useful while developing the script itself).
One-time transition for existing consumers
Scripts installed before this behavior existed cannot hand off. The first sync that crosses over to a handoff-capable version still behaves the old way: the report and apply complete, but bash may print a spurious syntax error near unexpected token right at the end because the script overwrote itself mid-run, and migrations introduced by the new version land on the next run. Simply run the sync once more. Every sync after that is single-pass.
Syncing Workflow Files¶
Template sync updates its own workflow (.github/workflows/template-sync.yml) alongside everything else — the sync script is part of the .claude/ directory and is synced as part of that tree. However, GitHub does not allow the default GITHUB_TOKEN to push changes to workflow files — the push is rejected with a workflows permission error (details).
These updates are sometimes required for sync to work correctly (e.g., when the sync logic itself changes between versions), so skipping them indefinitely is not recommended.
Option A: Update manually before running sync¶
Update the sync files locally, commit, push, then run the workflow:
VERSION="v0.12.0" # use the version you want to sync to
curl -fsSL "https://raw.githubusercontent.com/serpro69/claude-toolbox/${VERSION}/.github/workflows/template-sync.yml" \
-o .github/workflows/template-sync.yml
Or use /kk:template:sync in Claude Code — it syncs everything including the workflow files.
Option B: Set up a GitHub App for automatic sync¶
A GitHub App token has the workflows permission that GITHUB_TOKEN lacks. Once configured, the sync workflow handles everything automatically — no manual steps needed.
-
Create a GitHub App (guide) with these repository permissions:
- Contents: Read & Write
- Pull requests: Read & Write
- Workflows: Read & Write
-
Install the app on the repository (or repositories) where you run template sync.
-
Generate a private key for the app (Settings → Private keys → Generate).
-
Configure your repository:
- Add a repository variable named
CLAUDE_TOOLBOX_APP_IDwith the app's numeric ID - Add a repository secret named
CLAUDE_TOOLBOX_APP_KEYwith the app's private key (PEM contents)
Go to repo Settings → Secrets and variables → Actions to add both.
- Add a repository variable named
The workflow detects these credentials automatically and uses them for both pushing the branch and creating the PR.
Migrating from Task Master¶
Task Master MCP was removed in favor of native markdown-based task tracking integrated into the /kk:design and /kk:implement skills.
The easiest way to migrate is to run the migration command in Claude Code:
It will port pending tasks, clean up TM files, update configs, and walk you through each step with confirmation prompts.
Manual migration steps
If you prefer to migrate manually, follow these steps after syncing:
-
Port any pending tasks to the new format: create
docs/feat/wip/[feature]/tasks.mdfiles following the example task file in the plugin. Completed tasks don't need porting. -
Remove Task Master files and config:
-
Remove Task Master from
~/.claude.json: delete thetask-master-aientry from yourmcpServersconfig. -
Remove TM variables from
.github/template-state.json: deleteTM_CUSTOM_SYSTEM_PROMPT,TM_APPEND_SYSTEM_PROMPT, andTM_PERMISSION_MODEfrom thevariablesobject. -
Remove TM references from
CLAUDE.md: delete the "Task Master Integration" and "Task Master AI Instructions" sections (including the@./.taskmaster/CLAUDE.mdimport). -
Update the template-sync workflow (why?): the old workflow contains taskmaster-specific sync logic that will break future syncs. Run
/kk:template:syncor manually replace both files:VERSION="v0.3.0" # or use latest tag curl -fsSL "https://raw.githubusercontent.com/serpro69/claude-toolbox/${VERSION}/.github/workflows/template-sync.yml" \ -o .github/workflows/template-sync.yml curl -fsSL "https://raw.githubusercontent.com/serpro69/claude-toolbox/${VERSION}/.claude/toolbox/scripts/template-sync.sh" \ -o .claude/toolbox/scripts/template-sync.sh chmod +x .claude/toolbox/scripts/template-sync.sh
Task tracking now lives in simple markdown files (docs/feat/wip/[feature]/tasks.md) created by the /kk:design skill and consumed by /kk:implement. No external MCP server required.
Upgrading to the Plugin System (v0.5.0+)¶
Skills and commands have moved from the template to the kk plugin:
- Skills remain unprefixed:
/design(annotated with(kk)in the menu) - Commands are now namespaced:
/project:chain-of-verification→/kk:chain-of-verification:default - The template-sync workflow handles migration automatically on next sync
- After merging the sync PR, run
/plugin install kk@claude-toolbox