GitHub Actions workflows
When scaffolding a new Node.js/Bun project, or when adding CI to an existing one:
Setup
- Ask the user: "Will this project be hosted on GitHub?" If no, skip all CI workflow creation entirely.
- Read the repo name from
package.jsonnamefield (the name with hyphens is the repo name). - Read
config.tomlfrom this directory. If it exists, extractgithub_ownerandgithub_url_basefor defaults. If not, ask the user for these values and write them toconfig.toml(one-time setup). - Ask the user for the GitHub owner (default:
<github_owner from config>) - Ask the user for the URL base for badge links:
go.<owner>.com/gh(default, e.g.https://<github_url_base from config>)github.com/<owner>(e.g.https://github.com/<github_owner from config>)- Custom — user provides their own
- Ask the user: "Do you want to set up Renovate for automated dependency updates?"
If yes, load the
renovateskill and follow its instructions for GitHub projects. This createsrenovate.jsonand optionally.github/workflows/renovate.yml.
Substitute <owner>, <repo>, and <base> in all workflow files and badges using the values gathered above.
Workflow files
.github/workflows/lint.yml— always (typecheck viatsc --noEmit).github/workflows/test.yml— always (bun test).github/workflows/create_draft_release.yml— only if the user opts in (ask first).github/workflows/npm.yml— only if the user opts in (ask first)renovate.json— only if the user opted in to Renovate
Badges
After creating workflow files, add corresponding badges to the top of README.md in a single row. The GitHub Tag badge is always added.
| Badge | Condition | Markdown |
|---|---|---|
| GitHub Tag | always | [](<base>/<repo>/releases) |
| Lint | always | [](<base>/<repo>/actions/workflows/lint.yml) |
| Test | always | [](<base>/<repo>/actions/workflows/test.yml) |
| npm | if opted in | [](https://www.npmjs.com/package/<repo>) |
| Renovate | if opted in | [](https://docs.renovatebot.com) |
Templates
Each template file lives in assets/. Read the .yml.tmpl with the Read tool, substitute placeholders, then write the result to .github/workflows/<name>.yml:
assets/lint.yml.tmpl→lint.yml(no substitutions)assets/test.yml.tmpl→test.yml(no substitutions)assets/create_draft_release.yml.tmpl→create_draft_release.yml(only if user opted in)assets/npm.yml.tmpl→npm.yml(only if user opted in)
Create the directory before writing:
mkdir -p .github/workflows
Action pinning policy
All workflow actions (uses: lines) are pinned to full commit SHAs with a version comment. The pinned version is the latest stable release available for > 30 days, ensuring a vetting window before automated updates are proposed. Renovate's minimumReleaseAge: "30 days" respects this window. To update a pin, find the desired tag's commit SHA via the GitHub API (/repos/{owner}/{repo}/git/ref/tags/{tag}) or the action's release page. Consider setting up Renovate (step 5) to automate these updates.
Bun is installed via the official curl -fsSL https://bun.sh/install | bash script. No third-party action needed. To pin a specific version, pass it as an argument: bash -s "bun-v1.2.0".
npm Trusted Publishing
The assets/npm.yml.tmpl uses npm OIDC trusted publishing (GA since July 2025) instead of long-lived NPM_TOKEN secrets. Setup steps:
- First publish must use a classic access token (create on npmjs.com → Account → Access Tokens → read and write).
- After the first publish, go to the package on npmjs.com → Settings → Trusted Publisher.
- Fill in GitHub owner, repo name, and the workflow filename (
npm.yml). - Delete the classic access token from npm and the secret from GitHub.
- Remove
always-authandregistry-urlfrom the workflow if present.
The workflow strips _authToken from .npmrc before publish to prevent setup-node from interfering with OIDC. It publishes with --provenance for supply chain attestation.
If the user prefers classic tokens over OIDC, they can set NODE_AUTH_TOKEN as a repository secret and the workflow falls back to token-based auth.
README update
After creating workflow files, add the corresponding badges to README.md at the top, below the # <title> line. Badges go in a single row.