From slynk
Self-review a local branch, auto-fix what's safe, verify the repo's real CI checks pass, then open a pull/merge request with a human-sounding description. Detects GitHub (gh) or GitLab (glab) automatically and derives the checks to run from the repo's CI config — nothing hardcoded. Use when the user wants to open or create a PR/MR, ship a branch, or "review my changes before I push" — e.g. "open a PR for this", "create-pr", "self-review and ship this branch".
How this skill is triggered — by the user, by Claude, or both
Slash command
/slynk:create-prThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
A full pre-PR workflow for your own branches. Self-reviews the local diff for
A full pre-PR workflow for your own branches. Self-reviews the local diff for logic and correctness, auto-fixes what it safely can, verifies that the repo's actual CI checks pass (derived from its CI config, not assumed), then drafts and opens a pull request (GitHub) or merge request (GitLab).
Platform-agnostic: detects the git host and uses the matching CLI —
gh for GitHub (default), glab for GitLab (fallback). Throughout this doc,
"PR" means pull request on GitHub and merge request on GitLab.
Only works inside a git repository — exits early if run outside one.
Detect the platform once (Step 0) and use the matching column everywhere:
| Operation | GitHub (gh) | GitLab (glab) |
|---|---|---|
| Auth check | gh auth status | glab auth status |
| Current user | gh api user --jq .login | glab api user --jq .username |
| CI config | .github/workflows/*.{yml,yaml} | .gitlab-ci.yml (+ include:d files) |
| PR template | .github/pull_request_template.md / .github/PULL_REQUEST_TEMPLATE.md / .github/PULL_REQUEST_TEMPLATE/ | .gitlab/merge_request_templates/*.md |
| Create | gh pr create | glab mr create |
| Reviewers | auto via CODEOWNERS | auto via CODEOWNERS (Premium) — don't assign manually |
Default branch detection is platform-neutral:
git remote show origin | sed -n '/HEAD branch/s/.*: //p'
Optionally provide a base branch after invoking this skill:
main — explicitly sets the base branchParallelism strategy: Steps 2, 3, and 4 have no dependency on each other and can all run concurrently once Step 1 has the diff. Within Step 6, the formatter must run first (it writes files), but every other check runs in parallel. The self-review (Step 5) is the only step that requires sequential user interaction before the pipeline can start.
Run all of the following before doing anything else:
# 1. Confirm we're inside a git repo
git rev-parse --is-inside-work-tree
# 2. Identify the git host
git remote get-url origin
# 3. Current branch
git branch --show-current
# 4. Default branch
git remote show origin | sed -n '/HEAD branch/s/.*: //p'
Detect the platform from the remote URL host:
github.com (or a known GitHub Enterprise host) → GitHub, use gh.gitlab (gitlab.com or a self-hosted gitlab.*) → GitLab, use glab..gitlab-ci.yml present → GitLab; .github/workflows/ present → GitHub.gh / glab is installed → use it.Set the matching CLI for all later steps. Then verify auth:
gh auth status # GitHub
# or
glab auth status # GitLab
Exit conditions (checked in this order):
Not in a git repo → stop: "This skill only works inside a git repository."
Matching CLI not authenticated → stop:
gh CLI is not authenticated. Run gh auth login first."glab CLI is not authenticated. Run glab auth login first."Matching CLI not installed → stop and tell the user to install it (gh from cli.github.com, glab from gitlab.com/gitlab-org/cli).
Currently on the default branch → ask the user:
"You're on
<branch>. PRs are opened from feature branches, not the default branch. Would you like to create a new branch now?"
Choices:
type/description convention — e.g. feat/add-widget — or type/TICKET-description if the repo uses ticket keys), run git checkout -b <name>, then continueDo not check for commits ahead of base yet — that happens at the end of Step 0b.
Capture the authenticated user login for later use (gh api user --jq .login or glab api user --jq .username).
Before gathering the diff, check the working tree state:
git status --short
Classify what's present:
A, M, D in the index column)M, D in the worktree column)??)If there are no staged or unstaged changes, proceed normally — the PR will cover only committed work.
If there are staged or unstaged changes, show a summary grouped by status and ask:
"You have uncommitted changes. What would you like to do with them?"
Staged:
M src/foo.ts
A src/bar.ts
Unstaged:
M src/baz.ts
Untracked:
?? src/new-file.ts
Choices:
git add -A and commit with an auto-generated message derived from the branch name/ticket, e.g. feat: add widget — user can edit before confirminggit stash to set aside all changes, continue with only committed work. Remind the user to git stash pop afterwards.If the user chooses Commit all or Choose what to include, confirm the commit message before committing:
"Commit message:
<proposed message>— use this, or type a different one?"
After committing, re-check for commits ahead of base:
git log origin/<base>...HEAD --oneline
If still nothing → stop: "No commits found ahead of <base>. Nothing to review."
Fetch everything needed in parallel:
# Full diff vs base
git diff origin/<base>...HEAD
# Commit list
git log origin/<base>...HEAD --oneline
# Repo root (for finding config files)
git rev-parse --show-toplevel
# Diff stat (line count for Step 5)
git diff origin/<base>...HEAD --stat
Read the PR template for the detected platform:
# GitHub
cat .github/pull_request_template.md 2>/dev/null \
|| cat .github/PULL_REQUEST_TEMPLATE.md 2>/dev/null \
|| ls .github/PULL_REQUEST_TEMPLATE/ 2>/dev/null
# GitLab
ls .gitlab/merge_request_templates/ 2>/dev/null && cat .gitlab/merge_request_templates/*.md 2>/dev/null
Read the CI config for the detected platform — this is the source of truth for Step 6:
# GitHub
ls .github/workflows/ 2>/dev/null
# GitLab
cat .gitlab-ci.yml 2>/dev/null
Parse the remote URL to extract owner/repo (GitHub) or the project path (GitLab) for later CLI commands.
Once Step 1 is complete, Steps 2, 3, and 4 can all run in parallel. Launch them concurrently and collect all results before Step 5.
Parse the current branch name into a PR title:
<type>: <short description>
…or, if the repo uses ticket keys in branch names:
<type>: <TICKET> - <short description>
Parsing rules:
<type>/<TICKET>-<description-words> or <type>/<description-words>type = segment before the first / (feat, fix, chore, …)TICKET = uppercase ticket key matching [A-Z]+-\d+ (e.g. ABC-123), if presentdescription = remaining words after stripping the ticket, hyphens → spacesExamples:
| Branch | Generated Title |
|---|---|
feat/add-widget | feat: add widget |
fix/null-deref-in-cart | fix: null deref in cart |
feat/ABC-123-new-flow | feat: ABC-123 - new flow |
chore/update-dependencies | chore: update dependencies |
If the branch name doesn't match (e.g. no /), ask:
"I couldn't parse a PR title from this branch name (
<branch>). What should the title be?"
Inspect git log origin/<base>...HEAD --oneline.
Skip commits created by this skill (chore: address self-review findings, chore: apply formatter, chore: add change file, the auto-generated Step 0b commit).
Flag remaining commits that look like work-in-progress or noise:
wip, fixup!, squash!, temp, tmp, test commit, asdf, single-word messages, messages that are just a file nameIf flagged, offer:
"Some commits look like work-in-progress. Want me to interactively rebase to clean them up before opening the PR?"
Choices:
git rebase -i origin/<base>Scan the diff for committed secrets before any review or push.
Try in order:
gitleaks (if installed):
git diff origin/<base>...HEAD | gitleaks detect --pipe --no-banner
Pattern grep fallback:
git diff origin/<base>...HEAD | grep -iE 'password\s*[:=]\s*["'"'"'][^"'"'"']{6,}|secret\s*[:=]\s*["'"'"'][^"'"'"']{6,}|api[_-]?key\s*[:=]\s*["'"'"'][^"'"'"']{10,}|token\s*[:=]\s*["'"'"'][^"'"'"']{10,}|BEGIN (RSA |EC |DSA |OPENSSH )?PRIVATE KEY|AKIA[0-9A-Z]{16}'
Note if falling back: "Full secrets scanning requires gitleaks. Using basic pattern matching — install gitleaks for more comprehensive coverage."
If any matches are found — hard stop. Show the matched lines and locations:
"Potential secrets detected in the diff. Resolve these before opening a PR. You may need to rotate any exposed credentials."
Do not proceed until the user confirms false positives or resolves them.
If the diff exceeds 500 changed lines (from Step 1's stat), note it first:
"This is a large diff (+X lines). Consider whether it could be split into smaller PRs."
Review the diff for logic and correctness only — this is your own code, so the review is constructive, not adversarial. Catch anything you'd be embarrassed to have a teammate point out later.
Scope: Logic and correctness, not style.
- ❌ Do NOT flag whitespace, indentation, quote style, semicolons, import ordering, or anything a linter/formatter would catch automatically.
- ✅ Do flag logic, correctness, security, type safety, and architectural concerns.
Identify findings across three severities:
🔴 Critical (must fix before merging)
any, unchecked as assertions, missing return types on exported functions, @ts-ignore/@ts-expect-error without justification🟡 Important (should address)
readonly, incorrect/missing generics🔵 Suggestions (nice to have)
Compile findings grouped by severity. Reference exact file paths and line numbers. Write each finding the way a thoughtful teammate would — short, direct, often phrased as a question ("Should this fail closed if address is missing?"). No severity labels in the finding body, no AI-sounding preambles.
After displaying the review, ask:
"Found [N critical / M important / K suggestions]. Fix these automatically, or skip straight to running the checks?"
Choices:
If fixing automatically: work most-to-least severe (Critical → Important → Suggestions). For each fix, apply the change; skip anything needing a broader architectural decision and note it. After all fixes:
git add -A
git commit -m "chore: address self-review findings"
Show a summary of what was fixed and what was intentionally skipped.
Don't assume npm run build/lint/test. Derive the exact checks this repo gates PRs on, then run them.
Detect the task runner / package manager. Check the lockfile:
package-lock.json→npm, yarn.lock→yarn, pnpm-lock.yaml→pnpm,
bun.lockb/bun.lock→bun. Also note non-JS runners if present:
Makefile targets, justfile recipes, Taskfile.yml, composer.json
scripts, pyproject.toml/tox.ini, etc.
Read the CI config (fetched in Step 1) — this is the source of truth for what must pass:
.github/workflows/*.{yml,yaml} triggered by
pull_request / merge_group / push, extract every run: command..gitlab-ci.yml (and include:d files), extract each
job's script: commands. Skip jobs whose rules:/only:/except:
scope them to branches/tags other than this PR.Reduce CI commands to local check commands. Drop setup/install steps
(actions/checkout, npm ci, bundle install, pip install, docker
build/push, deploy, coverage upload, etc.). Keep the verification commands:
lint, format-check, typecheck, build, unit/integration/e2e tests.
Prefer the canonical script name. If CI runs an inlined command that
maps to a named script (e.g. CI runs eslint . and package.json has
"lint": "eslint ."), run the named script via the detected package
manager (npm run lint, pnpm lint, bun run lint, …). This keeps you
aligned with how the repo expects checks to be invoked.
No CI config? Fall back to package.json scripts whose names match
check patterns: format/format:check, lint, typecheck/type-check/tsc,
build, test, test:*. For non-JS repos, fall back to obvious runner
targets (make lint, make test, just check, …).
Classify each derived check:
prettier --write, gofmt -w, black .,
eslint --fix, a format script) → Wave 1, runs alone, first.Show the user the derived list before running if it's non-obvious (e.g. unusual or many commands). Otherwise just proceed. Example:
Derived checks from .github/workflows/ci.yml + package.json:
format → npm run format (writes files, runs first)
lint → npm run lint
types → npm run typecheck
build → npm run build
test → npm run test
Run the formatter check first because it modifies files lint/tests will read. If any files changed, commit before continuing:
git diff --quiet || (git add -A && git commit -m "chore: apply formatter")
If no formatter was derived, skip Wave 1.
Launch every read-only check from the derived list simultaneously as background jobs, each logging to its own temp file. Build this dynamically from Step 6a — the commands below are illustrative, not fixed:
# One background job per derived check (example shape)
npm run lint > /tmp/pr_check_lint.log 2>&1 & PIDS+=($!)
npm run typecheck > /tmp/pr_check_types.log 2>&1 & PIDS+=($!)
npm run build > /tmp/pr_check_build.log 2>&1 & PIDS+=($!)
npm run test > /tmp/pr_check_test.log 2>&1 & PIDS+=($!)
# Wait for each, capture exit codes
for pid in "${PIDS[@]}"; do wait "$pid"; done
Show all results together once every job finishes — don't interrupt mid-run:
✅ lint (8s)
✅ types (5s)
❌ build (12s) — 1 error
✅ test (34s)
Handling failures: only prompt after all results are in. For each failed check:
"
<check>failed. Fix the issues and re-run, or skip this check and continue?"
Choices:
--fix), then re-run only that checkClean up temp logs once resolved:
rm -f /tmp/pr_check_*.log
Do not proceed to PR creation if any check failed and the user hasn't explicitly chosen to skip it.
Some repos use beachball for release management. Check:
REPO_ROOT=$(git rev-parse --show-toplevel)
node -e "const p=require('$REPO_ROOT/package.json'); console.log(!!p.scripts?.['release:change'])"
If no release:change script exists, skip this step entirely.
If beachball is found:
Infer a change type from the branch prefix:
| Branch prefix | Default |
|---|---|
feat/ | minor |
fix/ | patch |
chore/, docs/, ci/, refactor/ | none |
breaking/ or description implies breaking change | major |
| Anything else | patch |
Ask the user to confirm, inferred type first (marked Recommended): patch, minor, major, none.
Write the change file directly (skip the interactive npm run release:change) — beachball's format, filename change/<sanitized-package-name>-<uuid-v4>.json at the project root:
REPO_ROOT=$(git rev-parse --show-toplevel)
CHANGE_DIR="$REPO_ROOT/change"
mkdir -p "$CHANGE_DIR"
PACKAGE_NAME=$(node -e "console.log(require('./package.json').name)")
EMAIL=$(git config user.email)
UUID=$(node -e "console.log(require('crypto').randomUUID())")
FILE_SAFE=$(echo "$PACKAGE_NAME" | sed 's/[^a-zA-Z0-9@]/-/g')
cat > "$CHANGE_DIR/${FILE_SAFE}-${UUID}.json" << EOF
{
"type": "<confirmed-type>",
"comment": "<pr-title>",
"packageName": "$PACKAGE_NAME",
"email": "$EMAIL",
"dependentChangeType": "<confirmed-type>"
}
EOF
git add "$CHANGE_DIR/"
git commit -m "chore: add change file"
In monorepos: one change file per affected package (check which packages/*/package.json paths the diff touches), resolving ./package.json from each package dir.
Combine:
Default structure:
## What
[1–2 sentences describing what this PR does, written as if explaining to a teammate who hasn't seen the code — not a commit log]
## Why
[1–2 sentences on the motivation: what problem this solves or what value it adds]
## Notable Changes
[Bullet list of functional changes a reviewer needs to understand — new capabilities, changed behavior, updated integrations, new config options, removed functionality. Do NOT include: test additions, lint fixes, formatting changes, internal refactors with no behavior change, or CI tweaks.]
If a ticket/issue reference is present, add a link, sourced in this order:
#123) → link it (Closes #123).ABC-123) and the template shows an issue-tracker URL pattern → follow that pattern.Tone: Write it the way a senior engineer would — clear, direct, confident. No AI tells: no bullet-point breakdowns of obvious things, no over-explanation, no "This PR introduces…" or "In this PR, I have…". First person but natural, like Slack: "Adds X so that Y can Z." No em-dashes.
Notable Changes — what qualifies:
| ✅ Include | ❌ Exclude |
|---|---|
| New API endpoints or function signatures | Added/updated tests |
| Changed business logic or calculation | Lint fixes or formatting |
| New configuration options | Internal variable renames |
| New UI components or screens | Build script changes |
| New integrations or external dependencies | CI/CD pipeline tweaks |
| Removed or deprecated functionality | Minor code cleanup |
| Performance changes with observable impact | Comment-only changes |
Display the generated title and description together:
Title: feat: add widget
---
[full description]
Ask:
"Ready to open the PR?"
Choices:
If the user requests edits, apply them and re-display before asking again.
Push the branch:
git push origin <branch> --set-upstream
Create the PR using the detected platform's CLI. Write the description to a temp file first to avoid shell length limits:
cat > /tmp/pr_body.md << 'EOF'
<generated description>
EOF
GitHub:
gh pr create \
--title "<generated title>" \
--body-file /tmp/pr_body.md \
--base <base> \
--head <current branch> \
[--draft] # if draft was selected
GitLab:
glab mr create \
--title "<generated title>" \
--description "$(cat /tmp/pr_body.md)" \
--target-branch <base> \
--source-branch <current branch> \
[--draft] \
--remove-source-branch=false
rm /tmp/pr_body.md
Note: Don't manually assign reviewers — both platforms request reviews from CODEOWNERS automatically when the PR is opened.
Display the PR/MR URL after creation.
Check the diff for UI-layer changes — modified files in paths like:
**/components/**, **/views/**, **/pages/**, **/screens/**.css, .scss, .less, .styled.ts, .styled.tsxui, component, view, page, modal, drawer, button, form in the nameIf found, remind the user:
"Looks like this PR includes UI changes — don't forget to attach screenshots or a short screen recording before requesting review."
src/components/".The git host CLIs don't scan local diffs for secrets — that needs a dedicated tool. This skill uses gitleaks when installed and falls back to pattern-based grep otherwise. For reliable coverage:
brew install gitleaks # macOS
# or see https://github.com/gitleaks/gitleaks for Linux/Windows
Once installed, gitleaks is used automatically on every run.
Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub slinkardbrandon/slynk-toolkit --plugin slynk