pull-request
pull-request
Turn the current branch into a pull request — on GitLab, a merge request — that follows the repo's own conventions: an umbrella Conventional-Commits title and a body filled from the repo's own template. Then create it after your confirmation, update your own existing one, or just show the exact command. The forge is chosen by the root forge key — GitHub via gh, GitLab via glab — and the host it talks to is resolved per repo, so a self-hosted instance is the ordinary case rather than an exception.
Opted out? If the repo config sets pr to false, this skill is disabled for the repo — stop immediately and tell the user the pull-request skill is turned off in .tituskirch-skills.json. An absent pr block is not disabled. Check .pr == false on the resolved config before any action. A missing jq or config exits non-zero too, so a pass is not evidence the config was read.
Workflow
1. Detect conventions (read the repo — never assume)
- Forge and host — from the root
forgekey (github→gh,gitlab→glab; anything else → say it isn't supported and stop) plus the host resolved per repo:forgeHost, else theoriginremote, else whatever the CLI is already authenticated against (REFERENCE.md). Confirm the repo is reachable —gh repo view --json nameWithOwner,defaultBranchRef, orglab repo viewagainst the resolved host. If it fails (no remote on that forge, wrong host, or the CLI not authenticated), stop with a clear message that names the host it tried. - Base ← head — base =
pr.basefrom.tituskirch-skills.jsonif set, elsedefaultBranchRef.name; head = current branch (git branch --show-current). Never hardcodemain/dev; showbase ← headin the plan and let the user override. - Stacked branch? — a branch built on another open PR's branch belongs on that branch, not the trunk: based on the trunk, its diff carries the other PR's unmerged commits as if this change had made them, and nothing errors to say so. So before settling the base, refresh
origin/*(agit fetchthat asks — it is deliberately not pre-approved — and degrades to the refs on hand when declined), then check whether an open PR's head branch is an ancestor of this one; the nearest such branch is the base. Where the chain can't be read cleanly — an ambiguous parent, or one rebased out from under this branch — stop and say so instead of opening a mis-based PR. A candidate that provably can't be the parent is skipped, never a refusal: cross-fork PRs (stacks are same-repo only), a branch still unfetchable, one whose tip is already on the trunk — refusing on those would block a branch stacked on nothing. A base the user named explicitly wins outright and needs no check. Detection, the refusal cases, and why this reads git rather than the stacks preview API: REFERENCE.md. - Template — the forge's own convention first: on GitHub
.github/pull_request_template.md,.github/PULL_REQUEST_TEMPLATE.md,.github/PULL_REQUEST_TEMPLATE/*.mdor a root/docs/variant; on GitLab.gitlab/merge_request_templates/*.md. Fall back to the other forge's directory only when the current forge's yields nothing — a migrated repo often keeps both. Use the file verbatim as the body skeleton and fill its sections; if none, fall back to Summary / Changes / Related issues. - Title convention — Conventional Commits when the repo uses them. Read it from the shared convention cache (
$(git rev-parse --git-common-dir)/tituskirch-skills/conventions, written byatomic-commitor by this skill — same detection, memoized); if the cache is missing/stale, detect it (commitlint config + history) and write the block yourself. Honor the cachedheader_max_lengthfor the title — PR titles are commonly linted too.pr.title.convention: plainin.tituskirch-skills.jsonforces a non-Conventional title. - Existing PR / MR —
gh pr list --head <branch> --state open, orglab mr list --source-branch <branch>, and check its author (step 5). - Config —
.tituskirch-skills.jsonat the repo root (optional, committed) can setpr.base,pr.title.convention,pr.instructions(free-text wording guidance for title/body),pr.language(a per-skill language override), the sharedlanguage, and the rootforge/forgeHostpair. Resolve it viatemplates/resolve-config.sh, never by reading the raw file (REFERENCE.md states how, missingjqincluded). Keys: REFERENCE.md.
Detection recipes and the shared cache: REFERENCE.md.