docs/solutions/developer-experience/2026-03-13-template-update-script-should-not-own-ci-verification.md
registry.yml was calling pnpm templates:update --local, and that helper script was also running its own bun lint:fix and bun typecheck.
That meant the workflow could fail inside the updater before the actual workflow checks ran. The failure looked like a registry sync problem, but it was really a bad boundary: the helper script was trying to be a mini CI pipeline.
Two things were wrong:
update-template.sh mixed generation with verification.npx shadcn@latest was not reliable in CI and could blow up on transitive module resolution.ts or .tsx extensions back into generated filesci-templates would fail on formatting driftThe first issue made the workflow brittle. The second made the updater noisy and flaky.
Keep verification at the workflow layer.
In tooling/scripts/update-template.sh:
pnpm dlx shadcn@latest add ... instead of npx, which avoided the Actions-only tinyexec module failure.ts and .tsx import specifiers after local-file installsbun lint:fix so generated template files are normalized immediatelyTEMPLATE_SKIP_VERIFY=true to skip only the script-local bun typecheckIn the workflows:
TEMPLATE_SKIP_VERIFY=true when running pnpm templates:update --localbun lint and bun run build checks after sync at the workflow level instead of inside the helpergh act before pushing a fix when CI behavior is unclearThat keeps the updater focused on generation and keeps CI responsible for CI.
The workflow now has one clear boundary:
bun lint:fixSo a registry sync no longer dies because the helper script wandered into unrelated typecheck noise, while the generated output is still cleaned up before CI checks it.
That just moved the mess around and widened lint scope in ugly ways. The problem was not “templates need special Biome config.” The problem was “the wrong layer was running verification.”
For generated templates, Biome was also a bad source of false failures:
noUnresolvedImports flagged valid package imports, alias imports, and even eslint.config.mjs importsuseImportExtensions re-added relative .ts and .tsx extensions that break the template TypeScript config on buildThe stable fix was to disable both rules in the template biome.jsonc files and let update-template.sh run bun lint:fix immediately after generation.
templates:update --local plus bun lint:fix can legitimately rewrite a lot of generated template files. If CI is failing on template lint after a registry sync, that churn usually belongs in the commit. Pretending it is unrelated just leaves ci-templates red.
These commands passed after the fix:
pnpm lint
pnpm --filter www rd
TEMPLATE_SKIP_VERIFY=true pnpm templates:update --local
cd templates/plate-template && bun lint && bun run build
cd templates/plate-playground-template && bun lint && bun run build
gh act pull_request -W .github/workflows/ci-templates.yml -j ci
gh act pull_request -W .github/workflows/registry.yml -j validate-registry
The full repo gate also passed:
bun check
Before Docker was available, gh act failed immediately with:
Cannot connect to the Docker daemon at unix:///var/run/docker.sock
After Docker was up, both local workflow reproductions passed:
cd templates/plate-template && bun run build
cd templates/plate-playground-template && bun run build
bash -n tooling/scripts/update-template.sh