Skip to content
Back to skills

Open Pull Request

ASecurity

Publish branches and create or update PRs with correct bases, metadata, readiness, and handoff. Load when shipping changes; use monitor-ci through the checks' conclusion.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 7, 2026
developmentrustgobashdockergitfrontendsecurity

Works with

  • terminal
  • cli

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned November 7, 2026

npx -y skills add a-novel-kit/stack --skill open-pull-request --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Open Pull Request?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Open Pull Request
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/a-novel-kit-open-pull-request/badge)](https://www.skillsdirectory.com/skills/a-novel-kit-open-pull-request)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: open-pull-request
description: >
  Publish branches and create or update PRs with correct bases, metadata, readiness, and handoff.
  Load when shipping changes; use monitor-ci through the checks' conclusion.
---

# Open Pull Request

Load [develop-feature](../develop-feature/SKILL.md) before publishing. Keep an exploratory draft
local until direction agreement, unless publication was explicitly requested. After agreement,
feature-branch pushes and PRs within scope need no repeated permission. Clear, simple tasks may
take the shorter path defined there. That freedom stops at the `a-novel` and `a-novel-kit`
organizations: never open a PR or an issue on another repository
([working principles](../../../AGENTS.md)).

**Ready means ready for review, not ready to merge.** A draft only backs up dirty, unfinished
work; mark a PR ready as soon as anyone other than you should look at it. Scope approval, the full
relevant tests and the final cleanup gate the merge, not the ready flag
([Phase 3](#phase-3-decide-pr-status-ready-vs-draft)). Every PR follows repository safeguards and
history rules. Never push to `master`/`main` without explicit consent (`git-conventions`).

Every PR in this repo follows the same contract: Conventional-Commits title, structured
body, correct base, its Task's milestone, and no manual reviewer/assignee assignment (workflows
handle that).

---

## Choose the publication path

Use the checks and stage rules below before publication. Inspect the existing branch/PR first;
update an open PR rather than recreating it.

- Before creating or editing a PR, or changing draft/ready status,
  read [authoring and metadata](references/authoring.md).
- After every push to an existing draft PR, recheck its draft reason using the
  [readiness rule](references/authoring.md#61-mark-ready-the-moment-you-want-review-mandatory).
  Mark it ready in the same turn once you want it reviewed.
- Before a final code/issue handoff, read [the session recap contract](references/handoff.md).
  Include every outstanding session item and, when the operator is an admin of the repository,
  each PR's admin-only approval command after review.
- After a push, use `monitor-ci` through green or a documented escalation, and inspect feedback
  with `resolve-pr-feedback`. Publication alone does not complete the task.

Local rendered-UI links belong in the handoff, never the PR body. Keep all approval, readiness,
identity, history, and layer-specific verification rules when taking a shorter publication path.

## Phase 1: Pre-Flight Checks

Before any push or PR creation, confirm that `develop-feature` permits publication and apply the
stage-appropriate checks below. Fix failures within scope; surface genuine blockers.

### 1.1 You are on a feature branch

```bash
git rev-parse --abbrev-ref HEAD
```

Must return something like `feat/dao/revoke-keys`, not `master` or `main`. If on `master`,
stop — you do not open PRs from master.

### 1.2 Working tree is clean

```bash
git status --porcelain
```

Must return empty. Uncommitted changes mean the branch is not ready. Either commit them
(follow `git-conventions`) or surface them to the user.

### 1.3 Commits follow Conventional Commits

```bash
# <base> is master, or the parent feature branch for a stacked PR (see Phase 2.3):
# master there would pull in the parent's commits and validate/rewrite commits that
# aren't this branch's responsibility.
# %s emits the commit subject only — no hash prefix — so each line is directly
# comparable against the Conventional Commits grammar below.
git log <base>..HEAD --format=%s
```

Every line must parse as a `git-conventions`-compliant Conventional Commit: either
`<type>(<scope>): <description>` or, for genuinely cross-cutting commits where scope is
intentionally omitted, `<type>: <description>`. If any commit is malformed, fix it
**before the branch's first push**. Use `git commit --amend` only when the malformed
commit is the last one on the branch _and_ unpushed; once the branch is pushed,
`git-conventions`' "never amend a pushed commit" rule applies and the fix becomes a
follow-up commit (or, for a cosmetic title fix, a PR-title adjustment the author can
squash at merge time). For any earlier malformed commit — even if unpushed — ask the
user before rewriting history.

### 1.4 Validate for the current stage

**Opening for review:** run focused existing checks and the lint/build checks needed to validate the
changed path. Describe new regression coverage deferred until issue scope approval. Do not demand
the full test suite to publish agreed work, disable CI, or weaken existing assertions.

**Before merge:** after scope approval, complete and run the full relevant regression suite, review
coverage, and finish code cleanup. Client-side changes include affected Playwright tests and
reviewed screenshot comparisons. Run applicable lint, type, test, and build checks; skip targets
the change cannot affect. CI confirms local verification.

```bash
# 1. LINT — pnpm scripts (lint/format/generate are NOT a-novel CLI verbs):
pnpm lint:go            # Go (golangci-lint); pnpm lint:proto for .proto, pnpm lint for JS/TS

# 2. TESTS — a-novel CLI, narrowest target that covers the branch's layer
#    (see implement-feature for the layer-to-target mapping):
a-novel test --type=go -y       # Go internal + pkg/go
a-novel test --type=pnpm -y     # pkg/js
a-novel test -y                 # everything (final pre-push validation)

# 3. BUILD — a-novel CLI, only the artifact kinds your change can break:
a-novel build --type=go -y      # Go binaries
a-novel build --type=pnpm -y    # pnpm build
a-novel build --type=podman -y  # images — only if you touched builds/ or what they copy

# 4. SEMGREP, when the repo's CI runs lint-semgrep (the services), from the repo root.
#    <version> is the tag@digest its lint-semgrep job pins. From a git worktree, also mount the
#    main checkout's .git at its own path.
podman run --rm -v "$PWD:/src:ro,z" -w /src \
  -v "<workspace>/kit/workflows/security-actions/lint-semgrep/rules:/rules:ro,z" \
  "docker.io/semgrep/semgrep:<version>" semgrep --config=/rules/service.yaml --metrics=off --error /src
```

**Lint is not formatting.** `gofmt` / `gofumpt` / `gci` (and `pnpm format:go`) only check
_formatting_ — they do **not** run the linters CI enforces (`goconst`, `usestdlibvars`,
`errcheck`, `gocritic`, …). A format-clean diff can still fail the `lint-go` check, so run
the linter, not just the formatter. Where a repo exposes no local Go-lint runner (no
`pnpm lint:go` script), invoke golangci-lint directly from the module directory:

```bash
go tool -modfile=golangci-lint.mod golangci-lint run ./...
```

That form resolves the version the repo pins, so local and CI run the identical linter. Pulling
`@latest` instead invites a disagreement that is pure version drift.

Fix failures in the applicable checks before pushing; disclose any verification blocker.

### 1.5 Generated files are in sync

If the branch touches `.proto` files or Go interfaces that have mocks:

```bash
pnpm generate:go
git status --porcelain
```

Any newly-modified files under `internal/handlers/protogen/`, `internal/handlers/mocks/`, or
`internal/core/mocks/` belong with the source change that caused them. Before the branch's
first push, amend them into the relevant commit. Once pushed, do not rewrite published
history — add a follow-up `chore(gen): ...` commit instead (per `monitor-ci`). CI's
`generated-go` job fails when these are stale.

### 1.6 Layer-specific review surfaces are ready

Honor every active layer skill's review-artifact gate before opening a ready PR. In particular,
`write-frontend` requires a locally running, freshly inspected Storybook plus direct story links
ready for the final completion report, and screenshots of the changed screens sent in the
conversation. Local-only review links must not enter the PR body. A
screenshot, static build, stale URL, or Storybook root link does not satisfy a direct rendered-UI
review route.

---

## Phase 2: Push the Branch

Push over the shared GitHub connection, opened first as
[git-conventions](../git-conventions/SKILL.md#reuse-the-github-ssh-connection) shows.

### 2.1 First push — set upstream

```bash
git push -u origin $(git rev-parse --abbrev-ref HEAD)
```

`-u` sets the upstream so later `git push` / `git pull` need no arguments.

### 2.2 Subsequent push

```bash
git push
```

If the branch has been rebased (e.g., during backtracking — see `implement-feature` Phase 4),
force-push **with lease** to avoid clobbering anyone else's work:

```bash
git push --force-with-lease
```

Never use plain `--force`. Never force-push to `master` or `main`.

### 2.3 Stacked branches

If this branch depends on another open PR (e.g., `feat/core/jwk-revoke` depends on
`feat/dao/jwk-revoke`), the base of the PR must be the parent branch, not master. Push the
parent first and make sure its PR is open.

---

## Phase 3: Decide PR Status (Ready vs. Draft)

The status tells peers what deserves their attention:

- **Draft:** pushed only so the work is not lost. It is dirty and unfinished, and looking at it is
  useless for now.
- **Ready for review:** anyone other than you may look at it now, for feedback, an audit or an
  approval. GitHub refuses approvals on drafts, so a PR waiting on the developer is ready.

Open the PR ready, or mark it ready the moment someone else should look. It need not be ready to
merge: list what still gates the merge in the body, such as issue scope approval, a blocking design
discussion, deferred test coverage or Playwright/screenshot verification, final cleanup, or a
stacked dependency. Review feedback on the issue and the PR in parallel with `resolve-pr-feedback`.

```bash
gh pr create --draft ...   # draft
gh pr create ...           # ready for review
```

---

## Phase 4: Check for Existing PR

Before creating a new PR, check whether one already exists for this branch:

```bash
gh pr view --json number,state,url 2>/dev/null
```

- If it returns a PR in `OPEN` state → **do not** create a new one. Update it instead
  (see Phase 6).
- If it returns a PR in `CLOSED` or `MERGED` state → the branch was reused. Surface this
  to the user before doing anything else; they probably want a new branch.
- If the command exits non-zero ("no pull requests found") → proceed to Phase 5.

---

## Phase 7: Hand-Off to monitor-ci (mandatory — gates task completion)

After `gh pr create` or `git push` succeeds, CI starts. **Opening the PR does not
finish the task.** Invoke `monitor-ci` and follow it to a terminal state. The task is
complete only once you have reported one of:

- **CI green** — every gating check `completed` + `success`, reported to the user, OR
- **A blocked/escalated state** — `monitor-ci`'s retry budget exhausted or an escalate
  condition hit, with the failing job(s), root-cause hypothesis, and what was tried
  surfaced to the user (per `monitor-ci` Phase 4).

Start `monitor-ci`'s background watch (Phase 1.2) and keep working while it runs. Once only its
result is left, you may end the turn: the watch's exit resumes you, and you report then. Never
close out without that report.

While CI runs, inspect both linked issue discussions and PR feedback with `resolve-pr-feedback`,
and prepare the task's next step. Review the branch's diff before pushing (`monitor-ci` Phase 1.2).
Full coverage and merge readiness still depend on the current `develop-feature` stage. Green CI does
not approve a PR's scope or complete the task. If no checks apply or are configured, report that
accurately.

Do not merge — merges are a developer decision unless explicitly delegated.

---

## Common Mistakes

- **Publishing before draft agreement.** Local checkpoint commits stay local unless publication
  was explicitly requested. After agreement, do not ask again for already-authorized publication.
- **Holding reviewable work in draft.** A draft is only a backup of dirty, unfinished work. Once
  anyone else should look at the PR, mark it ready: nobody can approve a draft.
- **Treating ready as mergeable.** Scope approval, full relevant coverage, visual verification, and
  final cleanup gate the merge; list the remaining ones in the PR body.
- **Ending a code/issue turn without the recap table.** Close with the Phase 8 table linking
  everything still outstanding this session, with the admin-only approval command, when the
  operator may run it, inside each open PR's row rather than in adjacent prose.
- **Trying to author a PR as the bot.** There is no bot path — `a-novel core bot-comment`
  only posts comments (5.0).
- **Treating "PR opened" as task-done.** Carry `monitor-ci` through to CI green or an
  escalated/blocked state (Phase 7).
- **Skipping stage-appropriate verification.** Apply 1.4, keep existing checks intact, and record
  deferred coverage in the PR body; the formatter is not the linter.
- **Opening a PR from master.** Branch first, then PR.
- **Closing and re-creating a PR to "fix" the title.** Use `gh pr edit --title` instead.
- **Putting a local Storybook link in a PR body.** Local review URLs are session-scoped and belong in
  the completion report, not durable GitHub metadata.
- **Handing off completed UI work without Storybook beside the PR and task links.** The final report
  needs a freshly verified direct Storybook link; see `write-frontend`.
- **Manual reviewer/assignee flags.** Automation handles these (5.4).
- **A PR without its Task's milestone or Tracking section.** The reader then cannot trace the PR to
  its Task and Epic (5.5).
- **`--force` without `--lease`.** Always `--force-with-lease` after a rebase.
- **Missing `BREAKING CHANGE:` footer.** If any commit on the branch is breaking, the PR
  body's Breaking Changes section must list it. Mismatches between commits and PR body are
  bugs — readers trust the body.
- **Bare `Closes #<n>` for a planning issue in a `.github` repo.** It links nothing, so the
  issue freezes on the board. Use `Closes a-novel-kit/.github#<n>` (5.5).
- **PR title that does not match the primary commit scope.** If the branch is `feat/dao/*`,
  the PR title scope should be `dao`, not `services`.
- **Linking the wrong base branch on a stacked PR.** If the parent is already merged, rebase
  onto master and change the base to master before pushing.

---

## Quick Reference

| Situation                           | Command                                                                                                    |
| ----------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| Pre-flight: lint (scoped)           | `pnpm lint:go` / `go tool -modfile=golangci-lint.mod golangci-lint run ./...`                              |
| Pre-flight: tests (scoped)          | `a-novel test --type=go -y` / `a-novel test -y`                                                            |
| Pre-flight: build (scoped)          | `a-novel build --type=go -y` (`--type=` matches changes)                                                   |
| First push                          | `git push -u origin <branch>`                                                                              |
| Push after rebase                   | `git push --force-with-lease`                                                                              |
| Check for existing PR               | `gh pr view --json number,state,url`                                                                       |
| Create ready PR                     | `gh pr create --title "..." --body "$(cat <<'EOF' ... )"`                                                  |
| Create draft PR                     | `gh pr create --draft --title ...`                                                                         |
| Trace the PR to its Task and Epic   | `gh pr create --milestone "<Task milestone>"`, body `## Tracking` with full refs (see 5.5)                 |
| Stacked PR (base is another branch) | `gh pr create --base feat/<parent-area>/... ...`                                                           |
| Update title on existing PR         | `gh pr edit --title "..."`                                                                                 |
| Flip draft → ready                  | `gh pr ready`                                                                                              |
| Flip ready → draft                  | `gh pr ready --undo`                                                                                       |
| Admin approval after review         | `gh workflow run approve-pr.yaml --repo <org>/<repo> --ref <default-branch> --field pull_request=<PR-URL>` |

Files in this skill

  • SKILL.md16.4 KB
  • references/authoring.md9.4 KB
  • references/handoff.md3.7 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.