| name | standardize-repo |
|---|---|
| description | Standardize CI, commitlint, and commit tooling for an Advisa repo |
| disable-model-invocation | true |
Migrate this repo to use Sambla Group shared CI workflows, add commitlint for commit message enforcement, and add commit message tooling for Claude Code, Codex, and GitHub Copilot. The tooling derives the Jira ticket ID from the branch name when possible (e.g. UCL-804 from UCL-804-Derive-jira-id-in-skill), falling back to asking the developer only when the branch name doesn't contain a Jira ID.
Detect the following values automatically:
- REPO_NAME — Run
git remote get-url originand extract the repo name (e.g.onboarding-apifromgit@github.com:Advisa/onboarding-api.git). Fall back to the current directory name. - PACKAGE_MANAGER — Check for lock files:
package-lock.json→ npm,yarn.lock→ yarn,pnpm-lock.yaml→ pnpm. - DEFAULT_BRANCH — Try
git symbolic-ref refs/remotes/origin/HEAD(striprefs/remotes/origin/). Fall back to the current branch name. - NODE_VERSION — Check
.nvmrcfirst, thenengines.nodeinpackage.json, then anynode-versionin existing CI workflow files. Default to22if not found. - JIRA_PREFIXES — Hardcoded:
UCL,INS,MYS,NV
Present the detected values to the user in a summary table and ask for confirmation before proceeding. Also ask whether the repo needs enable-test: true (shared workflow runs tests) or enable-test: false (repo needs custom test infrastructure like Redis, matrix strategies, etc). Check existing CI workflows to make a recommendation.
VPN reminder: If
npm installfails withE401authentication errors againstnpm.advisa.se, remind the user to connect to the VPN and retry.
Always use latest versions: When installing packages, always run
npm info <package> versionfirst to verify the latest version. Never add version numbers from memory topackage.json.
If the repo does not already have a .node-version or .nvmrc file, and does not have engines.node defined in package.json, create a .node-version file to align local development with CI:
22
Delete existing CI/test workflow(s) in .github/workflows/ that are being replaced. Keep unrelated workflows (e.g. manual build/deploy workflows, utility workflows like npm_install.yml).
Create: .github/workflows/verify.yml
name: Verify
on:
pull_request:
branches: [<DEFAULT_BRANCH>]
jobs:
verify:
uses: Advisa/gha-workflow-templates/.github/workflows/ucl-verify.yml@main
with:
node-version: '<NODE_VERSION>'
jira-project-key: 'UCL,INS,MYS,NV'
enable-test: <true|false>
secrets: inheritThe shared workflow defaults to Node 22. Only pass
node-versionif the repo requires a different version. Ifenable-test: false, either add custom test jobs to verify.yml or create a separate test.yml.
Create: .github/workflows/release.yml
name: Release
on:
push:
branches: [<DEFAULT_BRANCH>]
jobs:
release:
uses: Advisa/gha-workflow-templates/.github/workflows/ucl-release.yml@main
secrets: inheritIf enable-test: false, create .github/workflows/test.yml with the repo-specific test setup. Preserve any existing infrastructure needs (Redis, databases, matrix strategies, etc.) from the old workflow. Improvements to apply:
- Use matrix strategy for parallel test runs where applicable
- Use pre-installed tools (e.g.
jq) instead of installing them - Keep JSON/config validation as a separate job if the repo has it
- Use
actions/checkout@v4andactions/setup-node@v4 - Configure the Advisa NPM registry:
- name: Configure NPM Registry & Install Dependencies env: ADVISA_NPM_TOKEN: ${{ secrets.ADVISA_NPM_TOKEN }} run: | npm config set @advisa:registry https://npm.advisa.se/ npm config set //npm.advisa.se/:_authToken=$ADVISA_NPM_TOKEN npm ci
Run: <PACKAGE_MANAGER> install --save-dev semantic-release @semantic-release/changelog @semantic-release/git conventional-changelog-conventionalcommits
(Adjust command for yarn: yarn add --dev ..., pnpm: pnpm add -D ...)
Create: .releaserc.json
{
"branches": ["<DEFAULT_BRANCH>"],
"plugins": [
[
"@semantic-release/commit-analyzer",
{
"preset": "conventionalcommits",
"releaseRules": [
{ "type": "feat", "release": "minor" },
{ "type": "fix", "release": "patch" },
{ "type": "perf", "release": "patch" },
{ "type": "refactor", "release": "patch" },
{ "type": "style", "release": "patch" },
{ "type": "docs", "release": "patch" },
{ "type": "chore", "release": "patch" },
{ "type": "ci", "release": "patch" },
{ "type": "test", "release": "patch" },
{ "type": "build", "release": "patch" }
]
}
],
[
"@semantic-release/release-notes-generator",
{
"preset": "conventionalcommits"
}
],
[
"@semantic-release/changelog",
{
"changelogFile": "CHANGELOG.md"
}
],
[
"@semantic-release/npm",
{
"npmPublish": false
}
],
[
"@semantic-release/git",
{
"assets": ["package.json", "<LOCKFILE>", "CHANGELOG.md"],
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
}
],
"@semantic-release/github"
]
}Replace
<LOCKFILE>withpackage-lock.json(npm),yarn.lock(yarn), orpnpm-lock.yaml(pnpm). This ensures all conventional commit types trigger a release. The plugins must be installed as devDependencies because the shared workflow runsnpx semantic-releasewhich only provides the core package.
Run: <PACKAGE_MANAGER> install --save-dev @commitlint/cli @commitlint/config-conventional
(Adjust for yarn/pnpm as above)
Create: commitlint.config.js
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'subject-case': [2, 'always', ['sentence-case']],
'header-max-length': [2, 'always', 72],
},
helpUrl:
'https://github.com/Advisa/<REPO_NAME>/blob/<DEFAULT_BRANCH>/.github/instructions/commit-messages.instructions.md',
};Create: .github/instructions/commit-messages.instructions.md
---
applyTo: '**'
---
# Commit Message Guidelines
This project follows the [Conventional Commits](https://www.conventionalcommits.org/) specification.
## Format
<pre>
<type>(<scope>): <subject>
[optional body]
[optional footer(s)]
<JIRA-ID>
</pre>
## Jira ID Derivation
- **Derive the Jira ID from the current branch name** by matching the pattern `(UCL|INS|MYS|NV)-\d+`
- Example: branch `UCL-804-Derive-jira-id-in-skill` -> `UCL-804`
- Example: branch `INS-123-fix-validation` -> `INS-123`
- If no Jira ID can be extracted from the branch name, **omit it** from the commit message
- **Never invent or guess** Jira issue numbers
## Types
| Type | Description |
| ---------- | ------------------------------------------------------ |
| `feat` | A new feature |
| `fix` | A bug fix |
| `docs` | Documentation only changes |
| `style` | Formatting, missing semi-colons, etc. (no code change) |
| `refactor` | Code change that neither fixes a bug nor adds feature |
| `perf` | Performance improvement |
| `test` | Adding or correcting tests |
| `build` | Changes to build system or external dependencies |
| `ci` | Changes to CI configuration files and scripts |
| `chore` | Other changes that don't modify src or test files |
| `revert` | Reverts a previous commit |
## Rules
1. **Subject** must use sentence case (first word capitalized, rest lowercase unless proper nouns)
2. **Subject** must use imperative mood (e.g. "Add feature" not "Added feature")
3. **Header** (type + scope + subject) must not exceed 72 characters
4. **Header** should be understandable by a non-technical stakeholder
5. Do not end the subject with a period
6. Separate subject from body with a blank line
7. Wrap the body at 72 characters
8. Use the body to explain _what_ and _why_, not _how_
9. **No Co-Authored-By** -- do not add any co-authored-by lines
## Breaking Changes
Indicate breaking changes by adding `!` after the type/scope or by including a `BREAKING CHANGE:` footer:
<pre>
feat(api)!: Remove deprecated endpoints
BREAKING CHANGE: The /v1/users endpoint has been removed.
UCL-456
</pre>
## Atomic Commits
- Each commit should represent a single logical change
- Keep commits small and focused
- If a change touches multiple concerns, split it into separate commits
## Example
<pre>
feat(auth): Add JWT token refresh endpoint
Implement automatic token refresh to improve session handling.
The refresh endpoint validates the existing token and issues
a new one with an extended expiry.
UCL-804
</pre>Modify: .gitignore — find the .vscode line and change it to:
.vscode/*
!.vscode/settings.json
If there is no .vscode line, add these two lines.
Create or merge into .vscode/settings.json — if the file already exists, add this key to the existing object without overwriting other settings:
{
"github.copilot.chat.commitMessageGeneration.instructions": [
{
"file": ".github/instructions/commit-messages.instructions.md"
}
]
}Delete: .agents/skills/commit/SKILL.md if it exists (old location).
Create: .claude/skills/commit/SKILL.md and .codex/skills/commit/SKILL.md (identical content):
First, determine the Jira ticket ID from the current branch:
1. Run `git rev-parse --abbrev-ref HEAD` to get the current branch name.
2. Look for a Jira ticket ID matching the pattern `(UCL|INS|MYS|NV)-\d+` in the branch name.
3. If found, use it as the Jira ID (e.g. `UCL-804` from branch `UCL-804-Derive-jira-id-in-skill`).
4. If **no match is found**, ask me for the Jira ticket ID before proceeding.
Then generate the commit:
5. Run `git diff --cached` to see the staged changes.
6. Analyze the diff and generate a commit message following the [Conventional Commits](https://www.conventionalcommits.org/) format:
<pre>
<type>(<scope>): <subject>
[optional body]
[optional footer(s)]
<JIRA-ID>
</pre>
## Types
| Type | Description |
| ---------- | ------------------------------------------------------ |
| `feat` | A new feature |
| `fix` | A bug fix |
| `docs` | Documentation only changes |
| `style` | Formatting, missing semi-colons, etc. (no code change) |
| `refactor` | Code change that neither fixes a bug nor adds feature |
| `perf` | Performance improvement |
| `test` | Adding or correcting tests |
| `build` | Changes to build system or external dependencies |
| `ci` | Changes to CI configuration files and scripts |
| `chore` | Other changes that don't modify src or test files |
| `revert` | Reverts a previous commit |
## Rules
- **scope**: Optional, describes the area of the codebase affected
- **subject**: Sentence case (first word capitalized, rest lowercase unless proper nouns), imperative mood (e.g. "Add feature" not "Added feature"), no trailing period, max 72 chars for the full header, should be understandable by a non-technical stakeholder
- **body**: Explain _what_ and _why_ (not _how_), wrap at 72 chars, separated from subject by a blank line
- **Jira ID**: Just the ID on its own line (e.g. `UCL-804`), no "Refs:" prefix. **Never invent or guess** Jira issue numbers
- **No Co-Authored-By**: Do not add any co-authored-by lines
## Breaking Changes
Indicate breaking changes by adding `!` after the type/scope or by including a `BREAKING CHANGE:` footer:
<pre>
feat(api)!: Remove deprecated endpoints
BREAKING CHANGE: The /v1/users endpoint has been removed.
UCL-456
</pre>
## Atomic Commits
- Each commit should represent a single logical change
- Keep commits small and focused
- If a change touches multiple concerns, split it into separate commits
7. Show me the commit message for approval before committing.
8. After approval, create the commit.- Remove any stale CI badges (CircleCI, Travis, etc.)
- Add a
## Commit Messagessection to the README (or update existing one) with this content:
## Commit Messages
We follow [Conventional Commits](https://www.conventionalcommits.org/). Commit messages are enforced by [commitlint](https://commitlint.js.org/) in CI.
To generate a commit message with Claude Code, run `/commit` after staging your changes. GitHub Copilot also follows these conventions automatically via the instructions in `.github/instructions/`.
### Format
<pre>
<type>(<optional scope>): <description>
<optional body>
<issue reference>
</pre>
### Example
<pre>
feat(form): Add co-applicant income validation
The validation now checks that co-applicant income is within acceptable
range before submission. This prevents invalid applications from being
sent to the backend and provides immediate user feedback.
UCL-123
</pre>
### Rules
- Keep header within 72 characters (aim for 50 when possible)
- Word wrap body at 72 characters
- Use imperative mood: "Add feature" not "Added feature"
- Capitalize the first letter of the description
- Add a body only when the change needs explanation (what and why)
- One clear purpose per commit -- each commit should do one thing
- End with a Jira issue reference on its own line
### Types
| Type | Description | Version Bump |
| -------- | --------------------------------------------------------------------- | ------------ |
| feat | Add or remove a feature | Minor |
| fix | A bug fix | Patch |
| docs | Documentation only changes | Patch |
| style | Changes that do not affect the meaning of the code (formatting, etc.) | Patch |
| refactor | A code change that neither fixes a bug nor adds a feature | Patch |
| perf | A code change that improves performance | Patch |
| test | Adding missing tests or correcting existing tests | Patch |
| build | Changes that affect the build system or external dependencies | Patch |
| ci | Changes to CI configuration files and scripts | Patch |
| chore | Changes which don't change source code or tests | Patch |
| revert | Revert a previous commit | Varies |
### Breaking Changes
Indicate breaking changes with `!` after the type/scope or by adding `BREAKING CHANGE:` in the commit body. This triggers a major version bump.
### Jira Issue Reference
Every commit must reference a Jira issue. Accepted project prefixes: **UCL**, **INS**, **MYS**, **NV**.- Run
npx commitlint --from HEAD~1 --to HEAD --verboseto confirm the commitlint config loads correctly - Run
git statusto review all changes - Present a summary of everything that was created/modified
When creating commits for this work, ensure every commit passes CI independently. The recommended order:
- Infrastructure commits first (e.g.
.node-version) — no CI workflow exists yet, so nothing runs - Tooling/lint commits next (e.g. ESLint, Prettier, code formatting) — still no CI workflow to fail
- CI workflow commit last —
verify.ymlandrelease.ymlare added only after everything they validate (lint, commitlint) is already in place
This ensures that if someone bisects, every commit is green.
Validate your own commit messages against the rules in the commit skill (.claude/skills/commit/SKILL.md). In particular, ensure every header is 72 characters or fewer.