Name Branches & Create PRs (Transloco)
When to Use
- The user wants help naming a new branch before starting work.
- The user asks to create/open/submit a pull request for the current branch.
This skill enforces the branch-naming convention and the commit/PR rules from
CONTRIBUTING.md and commitlint.config.js.
Safety Rules (apply to every step)
These override any convenience shortcut — the developer reviews, then approves:
- Never stage, commit, push, or open a PR without explicit user approval. Each of
these is a separate confirmation; approving a commit is not approval to push.
- Never run
git add -A/git add .; stage explicit paths the user agreed to.
- Never chain staging and committing in a single command.
- Never amend, rebase, reset, or force-push unless the user explicitly asks.
- If the user only asked for part of the flow (e.g. "commit this"), stop there —
don't continue into pushing or PR creation on your own.
Wherever this skill says "ask the developer", use whatever interactive-question
mechanism your agent provides, and wait for the answer instead of guessing. The
mechanism is agent-specific, so no tool name is hardcoded here — this file lives under
.claude/, but other assistants (e.g. GitHub Copilot CLI) discover skills from that
directory too.
Branch Naming Convention
<prefix>/<scope>-<kebab-case-description>
<prefix>/<kebab-case-description> (no scope, for repo-wide changes)
<prefix>: one of feature, tech, bug, release, hotfix, e2e, docs, ci
<scope>: optional, a package/library scope (see Scopes below). Omit it for
changes that aren't tied to one package (root config, CI, docs, monorepo tooling).
<kebab-case-description>: short, human-readable summary of the change.
Prefix meaning & matching commit type
| Branch prefix |
Use for |
Commit/PR type |
feature |
New functionality |
feat |
bug |
Bug fix |
fix |
hotfix |
Urgent production fix |
fix |
tech |
Refactors, tooling, chores, deps |
chore (or refactor/build/ci if clearly a better fit) |
docs |
Documentation-only changes |
docs |
ci |
CI/workflow-only changes |
ci |
release |
Release preparation |
chore |
e2e |
Playwright e2e-only changes |
test |
Prefer the most specific prefix: a documentation-only change belongs on docs (not
tech), and a workflow-only change on ci. Because this repo squash-merges, the PR
title becomes the changelog entry — filing docs work as chore hides it there.
commitlint.config.js only allows these commit types: build, chore, ci, docs,
feat, fix, perf, refactor, revert, style, test, plugin. Always pick from
this list.
Scopes
Scope is the package name, without the transloco- prefix (matches libs/ folder
names and commit-message convention).
changelog.config.js is the source of truth — it's the same list npm run commit
offers. Read it at runtime rather than trusting the snapshot below:
node -p "require('./changelog.config.js').scopes.filter(Boolean).join(', ')"
At the time of writing that yields: transloco (core, no suffix), keys-manager,
locale, messageformat, optimize, persist-lang, persist-translations,
preload-langs, scoped-libs, utils, validator, schematics. If the command
output differs, the command wins.
Note the empty string in that array is the "no scope" option — filter it out, and omit
the scope entirely for changes that aren't tied to one package.
Examples
| Branch |
PR/commit title |
bug/locale-drop-conflicting-date-options |
fix(locale): drop conflicting date options when merging the global config |
feature/keys-manager-support-yaml-output |
feat(keys-manager): support yaml output |
tech/persist-lang-upgrade-nx |
chore(persist-lang): upgrade nx |
tech/upgrade-nx (root-level, no single package scope) |
chore: upgrade nx |
tech/optimize-build-times (touches no libs/transloco-optimize/) |
chore: optimize build times — not chore(optimize): |
e2e/scoped-libs-stabilize-lazy-load-scenario |
test(scoped-libs): stabilize lazy load scenario |
docs/locale-document-date-format-options |
docs(locale): document date format options |
ci/cache-playwright-browsers |
ci: cache playwright browsers |
Procedure
1. Naming a new branch (if that's what's being asked)
- Ask (or infer from context) what the change is about, pick the right
<prefix>
from the table above, determine the <scope> (or omit it), and propose the
<prefix>/<scope>-<description> branch name. Create it with
git checkout -b <name> once confirmed.
2. Creating a PR
Resolve the base branch first — never assume master.
- Default: the repo's default branch, read at runtime rather than hardcoded:
gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name'.
- Exception:
CONTRIBUTING.md routes GitBook documentation contributions to the
gitbook-docs branch. If the change edits that documentation content, the base
is gitbook-docs, not the default branch. (Repo-level docs that live on the
default branch — README.md, CONTRIBUTING.md, docs/ — still target the
default branch.) If it's ambiguous, ask the user rather than guessing.
- Make sure the remote ref is current before diffing —
git fetch origin <base> —
and always diff against origin/<base>, never the local ref. A local master
can be stale or entirely absent in a fresh clone or a fork, which silently
yields a wrong changed-file list with no error.
- Use this resolved
<base> everywhere below: origin/<base>...HEAD for diffs and
--base <base> when creating the PR.
Commit any pending work first
- Check
git status --porcelain. If there are staged/unstaged/untracked changes,
show the list of affected files to the user and get explicit confirmation
before staging anything — never run git add -A (or stage any file)
automatically. This avoids committing files the user hasn't reviewed
(including accidentally sensitive/local files).
- Broad wording (e.g. "stage everything") is not itself permission to run
git add -A or git add . — it still requires enumerating the candidate
files from git status --porcelain, displaying the exact paths to the user,
and getting explicit approval before staging. Only skip re-asking when the
user has already named the specific files/paths to stage.
- Once confirmed, stage only the agreed-upon files by explicit path (never
git add -A / git add .) and proceed.
- Determine
<type> and <scope> (see below), then build the message:
<type>(<scope>): <description> — generated from the actual diff content, not a
generic message. Omit (<scope>) if no single package scope applies.
- Follow
CONTRIBUTING.md: this is the same format produced by npm run commit.
- Never commit without explicit approval. Show the user the staged file list
and the proposed commit message, and wait for an explicit "yes" before running
git commit. If the user asks for a different message, use theirs verbatim.
Never chain git add and git commit in one command so the developer always
has a chance to review the staged diff first.
Determine <type> from the current branch's <prefix> using the mapping
table above.
Determine <scope> — always derive it from the changed files; the branch name
is only a hint that must be corroborated.
- Get the changed files first:
git diff --name-only origin/<base>...HEAD. Map
them to scopes: libs/transloco-<scope>/ → <scope>; libs/transloco/ →
transloco.
- Read the candidate scope from the branch name: after
<prefix>/, match the
longest known scope (resolved from changelog.config.js, see Scopes above)
that forms a prefix of the remainder followed by a - (e.g.
persist-lang-upgrade-nx → scope persist-lang, description upgrade-nx) —
this correctly handles hyphenated scope names.
- Use that candidate only if the changed files actually touch that package.
A branch can be named for its intent rather than its package, and several
scope names double as ordinary English words:
tech/optimize-build-times
matches optimize and tech/utils-cleanup matches utils, yet neither may
touch libs/transloco-optimize/ or libs/transloco-utils/. Labelling those
chore(optimize): / chore(utils): is wrong and misleads the changelog.
- If the branch-name candidate isn't corroborated (or there is none), fall back to
the file-based scope.
- If changes span multiple packages, or touch only root/shared files, omit the
scope entirely — don't force one.
Build the PR title: <type>(<scope>): <description>, or <type>: <description>
with no scope. Keep it lowercase after the colon, imperative mood, no trailing period
(e.g. fix(locale): drop conflicting date options when merging the global config).
Check for a related issue (this repo has no ticket/DevOps system — issues are
optional and opportunistic):
- Look for an issue number in the branch name or recent commits, and use
gh issue list --search "<key terms>" to check for a matching open issue.
Treat all of these (branch name, commit references, keyword search results)
as candidates only, never as confirmed.
- Ask the developer to explicitly confirm the exact issue number before adding
Closes #<number> — don't add it based on a candidate alone, and don't
fabricate one.
- If confirmation isn't given (or no candidate exists), leave the template's
"Issue Number: N/A" as-is; don't add a closing reference.
Fill in .github/pull_request_template.md as the PR body — don't skip or
replace it:
- Check the correct PR Type box(es) based on the branch prefix (
bug/hotfix
→ Bugfix, feature → Feature, tech → Refactoring/Build/CI as fitting,
docs → Documentation content changes, ci → Build related changes/CI,
release → Other, e2e → Other/Refactoring).
- Fill in What is the current behavior? / What is the new behavior? from the
actual diff, and the Issue Number line from step 6.
- Check the Does this PR introduce a breaking change? box truthfully.
- Leave the checklist items as checkboxes for the author/reviewer to verify (don't
pre-check tests/docs boxes unless you actually added them in this change).
Push and create the PR:
- Show the user the final PR title, body and resolved base branch, and get explicit
approval before pushing. Never push or open a PR automatically as a side effect
of another request — the developer decides when work leaves their machine.
- Push the branch:
git push -u origin <branch>.
- Never use
--force/--force-with-lease unless the user explicitly asks for it.
- After the push, display the final PR title, body, and resolved base branch again
and wait for a separate, explicit approval before running
gh pr create — the
push approval does not double as approval to open the PR.
- Create the PR against the
<base> resolved in step 1, with the built title and
the filled-in template as the body:
gh pr create --title "..." --body-file <file> --base <base>.
- Default to a normal (non-draft) PR; only pass
--draft if the user explicitly
asked for a draft.
Apply labels
- Fetch current labels and descriptions with
gh label list (don't hardcode —
labels and descriptions can change over time).
- Apply the package label matching
<scope>, if one exists (e.g. locale,
keys-manager, persist-lang) — these are named exactly after the scope.
- Apply a type label only when one clearly matches:
bug/hotfix → bug,
feature → enhancement, docs → documentation. There's no dedicated label
for tech, ci, release, or e2e — skip a type label rather than guessing
one for those prefixes.
- Optionally add one
area: <topic> label, but only when the change content
clearly matches that label's description with high confidence (e.g. a change to
the transpiler → area: transpiler). Skip it if uncertain.
- Apply labels with
gh pr edit <number> --add-label "<label1>,<label2>".
1---2name: create-branch-or-pr3description: Name branches correctly and create a pull request for the current branch in the Transloco repo. Use when the user asks to 'create a branch', 'name my branch', 'create a PR', 'open a pull request', or 'submit a PR'. Enforces the branch-naming convention, derives a conventional-commit PR title (type(scope): description), fills in .github/pull_request_template.md, and auto-applies matching repo labels.4---56# Name Branches & Create PRs (Transloco)78## When to Use910- The user wants help naming a new branch before starting work.11- The user asks to create/open/submit a pull request for the current branch.1213This skill enforces the branch-naming convention and the commit/PR rules from14`CONTRIBUTING.md` and `commitlint.config.js`.1516## Safety Rules (apply to every step)1718These override any convenience shortcut — the developer reviews, then approves:1920- **Never stage, commit, push, or open a PR without explicit user approval.** Each of21 these is a separate confirmation; approving a commit is not approval to push.22- Never run `git add -A`/`git add .`; stage explicit paths the user agreed to.23- Never chain staging and committing in a single command.24- Never amend, rebase, reset, or force-push unless the user explicitly asks.25- If the user only asked for part of the flow (e.g. "commit this"), stop there —26 don't continue into pushing or PR creation on your own.2728Wherever this skill says "ask the developer", use whatever interactive-question29mechanism your agent provides, and wait for the answer instead of guessing. The30mechanism is agent-specific, so no tool name is hardcoded here — this file lives under31`.claude/`, but other assistants (e.g. GitHub Copilot CLI) discover skills from that32directory too.3334## Branch Naming Convention3536```text37<prefix>/<scope>-<kebab-case-description>38<prefix>/<kebab-case-description> (no scope, for repo-wide changes)39```4041- `<prefix>`: one of `feature`, `tech`, `bug`, `release`, `hotfix`, `e2e`, `docs`, `ci`42- `<scope>`: optional, a package/library scope (see **Scopes** below). Omit it for43 changes that aren't tied to one package (root config, CI, docs, monorepo tooling).44- `<kebab-case-description>`: short, human-readable summary of the change.4546### Prefix meaning & matching commit type4748| Branch prefix | Use for | Commit/PR type |49| ------------- | -------------------------------- | ------------------------------------------------------------ |50| `feature` | New functionality | `feat` |51| `bug` | Bug fix | `fix` |52| `hotfix` | Urgent production fix | `fix` |53| `tech` | Refactors, tooling, chores, deps | `chore` (or `refactor`/`build`/`ci` if clearly a better fit) |54| `docs` | Documentation-only changes | `docs` |55| `ci` | CI/workflow-only changes | `ci` |56| `release` | Release preparation | `chore` |57| `e2e` | Playwright e2e-only changes | `test` |5859Prefer the most specific prefix: a documentation-only change belongs on `docs` (not60`tech`), and a workflow-only change on `ci`. Because this repo squash-merges, the PR61title becomes the changelog entry — filing docs work as `chore` hides it there.6263`commitlint.config.js` only allows these commit types: `build`, `chore`, `ci`, `docs`,64`feat`, `fix`, `perf`, `refactor`, `revert`, `style`, `test`, `plugin`. Always pick from65this list.6667### Scopes6869Scope is the package name, without the `transloco-` prefix (matches `libs/` folder70names and commit-message convention).7172`changelog.config.js` is the source of truth — it's the same list `npm run commit`73offers. Read it at runtime rather than trusting the snapshot below:7475```bash76node -p "require('./changelog.config.js').scopes.filter(Boolean).join(', ')"77```7879At the time of writing that yields: `transloco` (core, no suffix), `keys-manager`,80`locale`, `messageformat`, `optimize`, `persist-lang`, `persist-translations`,81`preload-langs`, `scoped-libs`, `utils`, `validator`, `schematics`. If the command82output differs, the command wins.8384Note the empty string in that array is the "no scope" option — filter it out, and omit85the scope entirely for changes that aren't tied to one package.8687### Examples8889| Branch | PR/commit title |90| ------------------------------------------------------------------- | --------------------------------------------------------------------------- |91| `bug/locale-drop-conflicting-date-options` | `fix(locale): drop conflicting date options when merging the global config` |92| `feature/keys-manager-support-yaml-output` | `feat(keys-manager): support yaml output` |93| `tech/persist-lang-upgrade-nx` | `chore(persist-lang): upgrade nx` |94| `tech/upgrade-nx` (root-level, no single package scope) | `chore: upgrade nx` |95| `tech/optimize-build-times` (touches no `libs/transloco-optimize/`) | `chore: optimize build times` — **not** `chore(optimize):` |96| `e2e/scoped-libs-stabilize-lazy-load-scenario` | `test(scoped-libs): stabilize lazy load scenario` |97| `docs/locale-document-date-format-options` | `docs(locale): document date format options` |98| `ci/cache-playwright-browsers` | `ci: cache playwright browsers` |99100## Procedure101102### 1. Naming a new branch (if that's what's being asked)103104- Ask (or infer from context) what the change is about, pick the right `<prefix>`105 from the table above, determine the `<scope>` (or omit it), and propose the106 `<prefix>/<scope>-<description>` branch name. Create it with107 `git checkout -b <name>` once confirmed.108109### 2. Creating a PR1101111. **Resolve the base branch first** — never assume `master`.112113 - Default: the repo's default branch, read at runtime rather than hardcoded:114 `gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name'`.115 - Exception: `CONTRIBUTING.md` routes GitBook documentation contributions to the116 `gitbook-docs` branch. If the change edits that documentation content, the base117 is `gitbook-docs`, not the default branch. (Repo-level docs that live on the118 default branch — `README.md`, `CONTRIBUTING.md`, `docs/` — still target the119 default branch.) If it's ambiguous, ask the user rather than guessing.120 - Make sure the remote ref is current before diffing — `git fetch origin <base>` —121 and always diff against `origin/<base>`, never the local ref. A local `master`122 can be stale or entirely absent in a fresh clone or a fork, which silently123 yields a wrong changed-file list with no error.124 - Use this resolved `<base>` everywhere below: `origin/<base>...HEAD` for diffs and125 `--base <base>` when creating the PR.1261272. **Commit any pending work first**128129 - Check `git status --porcelain`. If there are staged/unstaged/untracked changes,130 show the list of affected files to the user and get explicit confirmation131 before staging anything — never run `git add -A` (or stage any file)132 automatically. This avoids committing files the user hasn't reviewed133 (including accidentally sensitive/local files).134 - Broad wording (e.g. "stage everything") is not itself permission to run135 `git add -A` or `git add .` — it still requires enumerating the candidate136 files from `git status --porcelain`, displaying the exact paths to the user,137 and getting explicit approval before staging. Only skip re-asking when the138 user has already named the specific files/paths to stage.139 - Once confirmed, stage only the agreed-upon files by explicit path (never140 `git add -A` / `git add .`) and proceed.141 - Determine `<type>` and `<scope>` (see below), then build the message:142 `<type>(<scope>): <description>` — generated from the actual diff content, not a143 generic message. Omit `(<scope>)` if no single package scope applies.144 - Follow `CONTRIBUTING.md`: this is the same format produced by `npm run commit`.145 - **Never commit without explicit approval.** Show the user the staged file list146 and the proposed commit message, and wait for an explicit "yes" before running147 `git commit`. If the user asks for a different message, use theirs verbatim.148 Never chain `git add` and `git commit` in one command so the developer always149 has a chance to review the staged diff first.1501513. **Determine `<type>`** from the current branch's `<prefix>` using the mapping152 table above.1531544. **Determine `<scope>`** — always derive it from the changed files; the branch name155 is only a hint that must be corroborated.156157 - Get the changed files first: `git diff --name-only origin/<base>...HEAD`. Map158 them to scopes: `libs/transloco-<scope>/` → `<scope>`; `libs/transloco/` →159 `transloco`.160 - Read the candidate scope from the branch name: after `<prefix>/`, match the161 longest known scope (resolved from `changelog.config.js`, see **Scopes** above)162 that forms a prefix of the remainder followed by a `-` (e.g.163 `persist-lang-upgrade-nx` → scope `persist-lang`, description `upgrade-nx`) —164 this correctly handles hyphenated scope names.165 - Use that candidate **only if the changed files actually touch that package.**166 A branch can be named for its _intent_ rather than its package, and several167 scope names double as ordinary English words: `tech/optimize-build-times`168 matches `optimize` and `tech/utils-cleanup` matches `utils`, yet neither may169 touch `libs/transloco-optimize/` or `libs/transloco-utils/`. Labelling those170 `chore(optimize):` / `chore(utils):` is wrong and misleads the changelog.171 - If the branch-name candidate isn't corroborated (or there is none), fall back to172 the file-based scope.173 - If changes span multiple packages, or touch only root/shared files, omit the174 scope entirely — don't force one.1751765. **Build the PR title**: `<type>(<scope>): <description>`, or `<type>: <description>`177 with no scope. Keep it lowercase after the colon, imperative mood, no trailing period178 (e.g. `fix(locale): drop conflicting date options when merging the global config`).1791806. **Check for a related issue** (this repo has no ticket/DevOps system — issues are181 optional and opportunistic):182183 - Look for an issue number in the branch name or recent commits, and use184 `gh issue list --search "<key terms>"` to check for a matching open issue.185 Treat all of these (branch name, commit references, keyword search results)186 as candidates only, never as confirmed.187 - Ask the developer to explicitly confirm the exact issue number before adding188 `Closes #<number>` — don't add it based on a candidate alone, and don't189 fabricate one.190 - If confirmation isn't given (or no candidate exists), leave the template's191 "Issue Number: N/A" as-is; don't add a closing reference.1921937. **Fill in `.github/pull_request_template.md`** as the PR body — don't skip or194 replace it:195196 - Check the correct **PR Type** box(es) based on the branch prefix (`bug`/`hotfix`197 → Bugfix, `feature` → Feature, `tech` → Refactoring/Build/CI as fitting,198 `docs` → Documentation content changes, `ci` → Build related changes/CI,199 `release` → Other, `e2e` → Other/Refactoring).200 - Fill in **What is the current behavior?** / **What is the new behavior?** from the201 actual diff, and the **Issue Number** line from step 6.202 - Check the **Does this PR introduce a breaking change?** box truthfully.203 - Leave the checklist items as checkboxes for the author/reviewer to verify (don't204 pre-check tests/docs boxes unless you actually added them in this change).2052068. **Push and create the PR**:207208 - Show the user the final PR title, body and resolved base branch, and get explicit209 approval before pushing. Never push or open a PR automatically as a side effect210 of another request — the developer decides when work leaves their machine.211 - Push the branch: `git push -u origin <branch>`.212 - Never use `--force`/`--force-with-lease` unless the user explicitly asks for it.213 - After the push, display the final PR title, body, and resolved base branch again214 and wait for a separate, explicit approval before running `gh pr create` — the215 push approval does not double as approval to open the PR.216 - Create the PR against the `<base>` resolved in step 1, with the built title and217 the filled-in template as the body:218 `gh pr create --title "..." --body-file <file> --base <base>`.219 - Default to a normal (non-draft) PR; only pass `--draft` if the user explicitly220 asked for a draft.2212229. **Apply labels**223224 - Fetch current labels and descriptions with `gh label list` (don't hardcode —225 labels and descriptions can change over time).226 - Apply the package label matching `<scope>`, if one exists (e.g. `locale`,227 `keys-manager`, `persist-lang`) — these are named exactly after the scope.228 - Apply a type label only when one clearly matches: `bug`/`hotfix` → `bug`,229 `feature` → `enhancement`, `docs` → `documentation`. There's no dedicated label230 for `tech`, `ci`, `release`, or `e2e` — skip a type label rather than guessing231 one for those prefixes.232 - Optionally add one `area: <topic>` label, but only when the change content233 clearly matches that label's description with high confidence (e.g. a change to234 the transpiler → `area: transpiler`). Skip it if uncertain.235 - Apply labels with `gh pr edit <number> --add-label "<label1>,<label2>"`.