Skip to content
Development
Skill

/ngit-pr

How to create, review, revise, and merge pull requests in this repo, which can be published TWO ways — GitHub (the `gh` CLI) and git-over-nostr (the `ngit` CLI, where PRs are nostr **proposals** reviewed on gitworkshop.dev). Use whenever a task involves opening/updating/merging

From plugin
amethyst
1.6k30 skills3 commands
Install
$ npx -y skills add vitorpamplona/amethyst --skill ngit-pr --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/ngit-pr

Context preview

The summary Claude sees to decide when to auto-load this skill.

How to create, review, revise, and merge pull requests in this repo, which can be published TWO ways — GitHub (the `gh` CLI) and git-over-nostr (the `ngit` CLI, where PRs are nostr **proposals** reviewed on gitworkshop.dev). Use whenever a task involves opening/updating/merging

SKILL.md

ngit-pr.SKILL.md
name: ngit-pr
description: How to create, review, revise, and merge pull requests in this repo, which can be published TWO ways — GitHub (the `gh` CLI) and git-over-nostr (the `ngit` CLI, where PRs are nostr **proposals** reviewed on gitworkshop.dev). Use whenever a task involves opening/updating/merging a PR by either mechanism, the `pr/feat/*` branches, the `ngit` or `gh` CLIs, gitworkshop.dev, or a `nostr://` remote. Remote names vary per clone (and a collaborator may have only one) — this skill identifies remotes by URL, and covers the three-mains alignment gate the nostr flow depends on.

Pull requests: GitHub **and** git-over-nostr

This repo can be contributed to **two** ways, via **two kinds** of remote. Both end up in GitHub `main`.

| Remote kind | URL pattern | Role | |--|--|--| | **GitHub** | `github.com/vitorpamplona/amethyst` | **Canonical** `main`. Moves constantly (bots merge often) — a moving target. | | **git-over-nostr** | `nostr://…/relay.ngit.dev/amethyst` | `ngit`. A push fans out to GitHub **and** the GRASP git servers and publishes nostr events. PRs are **proposals**, reviewed on **gitworkshop.dev**. |

Step 0 — identify YOUR remotes (names are not universal)

Remote **names are per-clone**. In the maintainer's checkout the GitHub remote is `upstream` and the nostr remote is `origin`, but yours may differ, and **you may have only one of them** (e.g. cloned straight from `nostr://…`, so the nostr remote is your `origin` and there is no separate GitHub remote — pushing it still reaches GitHub via fan-out). Detect by **URL**, never assume a name:

git remote -v
GH_REMOTE=$(git remote -v    | awk '/github\.com/   {print $1; exit}')   # GitHub remote (may be empty)
NOSTR_REMOTE=$(git remote -v | awk '/nostr:\/\//     {print $1; exit}')  # git-over-nostr remote (may be empty)
echo "github=$GH_REMOTE  nostr=$NOSTR_REMOTE"

The examples below use `$GH_REMOTE` / `$NOSTR_REMOTE` — substitute whichever you have.

Which path?

| | **GitHub path** (`gh`) | **nostr path** (`ngit`) | |--|--|--| | Needs | a GitHub remote + `gh auth status` | a `nostr://` remote + `ngit` ≥ 2.5.0 | | PR lives on | GitHub only | nostr + GitHub + GRASP (fans out) | | Use when | Default; PR only needs to be on GitHub. Simplest, no alignment gate. | The PR must be visible/reviewable over nostr (gitworkshop), or you're revising/merging an existing **proposal** (a `pr/feat/*`). |

**Default to GitHub** unless the task is specifically about a nostr proposal (e.g. "the PRs on origin", a gitworkshop link, a `pr/feat/*` branch). If you only have one remote, that decides the path for you. Revise/merge a PR on **the same path it was created** — don't revise a GitHub PR via ngit or vice-versa.

---

GitHub path (`gh`)

The normal flow most of this repo's history uses ("Merge pull request #NNNN …"). Requires a GitHub remote (`$GH_REMOTE`) and `gh auth status` OK.

# create — branch off main, push, open the PR
git checkout -b feat/<slug> main
git push -u "$GH_REMOTE" feat/<slug>
gh pr create --repo vitorpamplona/amethyst --base main --head feat/<slug> \
  --title "feat: …" --body "…"

# review / list
gh pr list --repo vitorpamplona/amethyst
gh pr view <number> --repo vitorpamplona/amethyst   # --comments for the thread

# revise — push more commits to the same branch
git push "$GH_REMOTE" feat/<slug>

# merge (maintainer)
gh pr merge <number> --repo vitorpamplona/amethyst --merge   # or --squash

GitHub is the source of truth for this path — no three-mains gate. Standard Git Workflow rules from CLAUDE.md still apply (conventional commits, never `--no-verify`).

---

nostr path (`ngit`)

Requires a `nostr://` remote (`$NOSTR_REMOTE`) and `ngit` ≥ 2.5.0 (`ngit --version`).

**Mental model:** an ngit PR ("proposal") is a *linear patch series off `main`*, published as nostr events. A "revision" is a new version of that proposal. Merging applies the series to `main` and publishes a merged-status event. There is **no** GitHub PR number; `ngit pr merge` makes a plain merge commit (amend it to a readable message).

⚠ The three-mains alignment gate (the thing that breaks everything)

Up to **three** `main` heads drift apart:

  • GitHub main (`$GH_REMOTE/main` if you have it) — newest, moves every few minutes
  • nostr main (`$NOSTR_REMOTE/main` tracking ref) — **lags**, often far behind
  • local `main`

**Every create/revise/merge requires the proposal's base to equal the nostr `main`, and pushing `main` to the nostr remote requires GitHub's main to be an ancestor of what you push.** When misaligned, ngit **rejects pre-flight and publishes nothing** (safe — nothing half-breaks; realign and retry). Don't `--force` past it.

git fetch --all
echo "github=$([ -n "$GH_REMOTE" ] && git rev-parse "$GH_REMOTE/main")  \
nostr=$(git ls-remote "$NOSTR_REMOTE" -h refs/heads/main | awk '{print $1}')  \
local=$(git rev-parse main)"
# all present heads equal → proceed.
# local behind GitHub?  git merge --ff-only "$GH_REMOTE/main"  (or "$NOSTR_REMOTE/main" if that's all you have)
# nostr behind local?   git push "$NOSTR_REMOTE" main   (clean fast-forward only)

If you have **only** the nostr remote: align local `main` to `$NOSTR_REMOTE/main`; GitHub is handled by fan-out, and any GitHub/GRASP disagreement surfaces as an ngit rejection on push. If GitHub diverged from nostr (`out of sync with nostr` on push), that's a maintainer `ngit sync --ref-name refs/heads/main --force` situation — **stop and ask the human**, don't run a forced sync unprompted.

Pushes are slow — run them in the background

`git push "$NOSTR_REMOTE" …`, `ngit send`, and `ngit pr merge` fan out to relays + GRASP servers and **routinely exceed 2 minutes**. Run with `run_in_background: true` and poll (e.g. `git ls-remote "$NOSTR_REMOTE"` for the expected ref). A foreground call hits the 2-minute tool timeout even while the push is actually succeeding.

Identity

`ngit account whoami` shows the signing key; `ng

Read more
Ships withamethyst

Nostr client for Android

Get the whole plugin

Other skills on amethyst.