diff --git a/.agents/skills/ngit/SKILL.md b/.agents/skills/ngit/SKILL.md index b55dc347..b9457b90 100644 --- a/.agents/skills/ngit/SKILL.md +++ b/.agents/skills/ngit/SKILL.md @@ -1,32 +1,39 @@ --- name: ngit -description: Commands and workflows for NIP-34 git collaboration over Nostr with the ngit CLI and git-remote-nostr. Use in any repository with a nostr:// remote for generic collaboration requests (open an Issue, create or review a Pull Request (PR), comment, merge, clone) and whenever a task involves nostr:// URLs, ngit commands, Grasp servers, gitworkshop.dev, Nostr CI status and workflows, software releases and Zapstore publication, OCI container images, or nsite static sites published through Blossom. +description: + Commands and workflows for NIP-34 git collaboration over Nostr with the ngit + CLI and git-remote-nostr. Use in any repository with a nostr:// remote for + generic collaboration requests (open an Issue, create or review a Pull Request + (PR), comment, merge, clone) and whenever a task involves nostr:// URLs, ngit + commands, Grasp servers, gitworkshop.dev, Nostr CI status and workflows, + software releases and Zapstore publication, OCI container images, or nsite + static sites published through Blossom. license: CC-BY-SA-4.0 metadata: - version: "1.17" + version: "1.18" --- # ngit — Nostr Plugin for Git -ngit makes `git clone`, `fetch`, and `push` work with `nostr://` URLs and adds -a CLI for pull requests, issues, membership, CI results, releases, OCI -containers, and nsites. Repository state (which commit each ref points to) is -published as signed Nostr events and is the source of truth; git objects live -on ordinary git servers, so servers are interchangeable. A grasp server bundles -a relay and a git server and creates the repository automatically when an -announcement lists it. Explanation: https://ngit.dev/how-it-works +ngit makes `git clone`, `fetch`, and `push` work with `nostr://` URLs and adds a +CLI for pull requests, issues, membership, CI results, releases, OCI containers, +and nsites. Repository state (which commit each ref points to) is published as +signed Nostr events and is the source of truth; git objects live on ordinary git +servers, so servers are interchangeable. A grasp server bundles a relay and a +git server and creates the repository automatically when an announcement lists +it. Explanation: https://ngit.dev/how-it-works ## Where to look - **This skill documents ngit v3.** Run `ngit --version` first; the commands - here need 3.0.0 or later. If ngit is missing or older, report that and - offer an install or update: `curl -fsSL https://ngit.dev/install.sh | bash` - installs or replaces `ngit` and `git-remote-nostr`, and `ngit update` works - on v3 or later. Other methods: https://ngit.dev/install -- **`ngit --help`** is the authority for the installed version's - flags and defaults. -- **https://ngit.dev** holds the guides. Any page is available as raw - Markdown at `https://ngit.dev/markdown/.md`; the index is + here need 3.0.0 or later. If ngit is missing or older, report that and offer + an install or update: `curl -fsSL https://ngit.dev/install.sh | bash` installs + or replaces `ngit` and `git-remote-nostr`, and `ngit update` works on v3 or + later. Other methods: https://ngit.dev/install +- **`ngit --help`** is the authority for the installed version's flags + and defaults. +- **https://ngit.dev** holds the guides. Any page is available as raw Markdown + at `https://ngit.dev/markdown/.md`; the index is https://ngit.dev/llms.txt. Web UI: https://gitworkshop.dev ## Rules @@ -35,44 +42,40 @@ announcement lists it. Explanation: https://ngit.dev/how-it-works policy. Carry through the selected signer, target, hosting, CI, and replication settings; do not add gates, waits, workflow edits, or configuration changes that the task or repository did not choose. -- **PR branches MUST start with `pr/`** (e.g. `pr/my-feature`). Any other - branch name is a plain push and never creates a PR. +- **PR branches MUST start with `pr/`** (e.g. `pr/my-feature`). Any other branch + name is a plain push and never creates a PR. - **Read ngit output with `--json`.** It is a global option and works at any - position. Stdout is exactly one JSON document; progress and diagnostics go - to stderr. `git` commands have no `--json`. Top-level `command_status` is - `ok` for exit 0 and `error` otherwise; it never describes a nested domain - result (`ngit ci status --json` reports `ok` with - `ci.conclusion: "failure"` unless a gate was requested). + position. Stdout is exactly one JSON document; progress and diagnostics go to + stderr. `git` commands have no `--json`. Top-level `command_status` is `ok` + for exit 0 and `error` otherwise; it never describes a nested domain result + (`ngit ci status --json` reports `ok` with `ci.conclusion: "failure"` unless a + gate was requested). - **Add `--offline` after the first network read** in a session, on commands that support it. `git fetch origin` also refreshes the cache. - **Identifiers.** `` accepts `nevent1…`, a 64-char hex ID, or a unique hex prefix with an optional `#` (quote it: `'#deadbeef'`). JSON `id` and `reply_to` fields are already `nevent1…`; container publication instead returns a raw-hex `event_id` plus the repository `naddr`. Reference events - inside `--body` text as `nostr:nevent1…` or `nostr:naddr1…`, never as raw - hex. Never construct a NIP-05 address (`user@domain`); use `npub1…` unless - a NIP-05 address was given to you. -- **Multiline text.** `ngit` options such as `--body` and `--description` - accept real newlines: `--body "$(cat note.md)"`. Git push options cannot - carry newlines: write literal `\n` in a short inline `-o description=…`, and - never convert a file into a push option (open the PR with `ngit send` - instead). + inside `--body` text as `nostr:nevent1…` or `nostr:naddr1…`, never as raw hex. + Never construct a NIP-05 address (`user@domain`); use `npub1…` unless a NIP-05 + address was given to you. +- **Multiline text.** `ngit` options such as `--body` and `--description` accept + real newlines: `--body "$(cat note.md)"`. Git push options cannot carry + newlines: write literal `\n` in a short inline `-o description=…`, and never + convert a file into a push option (open the PR with `ngit send` instead). - **Signers.** `--signer ` selects a stored identity - for one `ngit` command; `git -c nostr.signer= - push …` does the same for one git command. Neither changes the configured - login. Never export or pass an nsec merely to switch between configured - accounts. -- **CI.** A successful push says nothing about CI. Nostr CI runs workflows - from `.ngit/act/workflows/`; another provider's directory is not evidence. - When CI matters, query the exact commit or PR with - `ngit ci status --json` and read `ci.state` and `ci.conclusion`, - not `command_status`. + for one `ngit` command; `git -c nostr.signer= push …` + does the same for one git command. Neither changes the configured login. Never + export or pass an nsec merely to switch between configured accounts. +- **CI.** A successful push says nothing about CI. Nostr CI runs workflows from + `.ngit/act/workflows/`; another provider's directory is not evidence. When CI + matters, query the exact commit or PR with `ngit ci status --json` + and read `ci.state` and `ci.conclusion`, not `command_status`. - **Target repository.** With several `nostr://` remotes, pass global - `--repo `; a configured remote name, an naddr, and - a nostr:// URL are all accepted. Without it ngit - infers the target from config and branch tracking and fails rather than - guesses. Before a signing command, check the - `target repository: (source: …)` line on stderr. + `--repo `; a configured remote name, an naddr, and a + nostr:// URL are all accepted. Without it ngit infers the target from config + and branch tracking and fails rather than guesses. Before a signing command, + check the `target repository: (source: …)` line on stderr. ## Detecting a nostr repo @@ -81,11 +84,11 @@ git remote -v | grep -q 'nostr://' # primary check, no cache needed ngit repo --json --offline # full metadata when needed ``` -`ngit repo` always exits 0, and `is_nostr_repo: false` can be a cold-cache -false negative: if a remote shows `nostr://`, run `git fetch origin` and -retry. The output includes the roster (`members`, `lead_source`, `lead_path`, -`pending_actions`, `health`); read `reference/repositories.md` before -changing membership or hosting. +`ngit repo` always exits 0, and `is_nostr_repo: false` can be a cold-cache false +negative: if a remote shows `nostr://`, run `git fetch origin` and retry. The +output includes the roster (`members`, `lead_source`, `lead_path`, +`pending_actions`, `health`); read `reference/repositories.md` before changing +membership or hosting. ## nostr:// URLs @@ -100,18 +103,18 @@ Standard git commands accept these URLs directly. ## Task index -Read the bundled reference before performing that slice of work; the guide -adds tutorials and background. +Read the bundled reference before performing that slice of work; the guide adds +tutorials and background. -| Task | Bundled reference | ngit.dev guide | -| ---- | ----------------- | -------------- | -| Publish, clone, host repositories; maintainers, moderators | `reference/repositories.md` | `/repositories`, `/maintainers` | -| Open, update, stack, review, merge PRs | `reference/prs.md` | `/pull-requests` | -| Issues | `reference/issues.md` | `/issues` | -| CI results, trust, workflows, ngit in CI jobs | `reference/ci.md` | `/ci`, `/ci/workflows/` | -| Accounts, login, signers, secrets | `reference/accounts.md` | `/accounts` | -| Sync, global flags, git config | `reference/sync-config.md` | `/configuration`, `/troubleshooting` | -| Publish nsites (static sites) | `reference/nsites.md` | `/releases/nsites` | -| Publish OCI containers | `reference/containers.md` | `/releases` | -| Software releases | `ngit release --help` | `/releases` | -| Automation contract, machine-readable docs | this file | `/agents/` | +| Task | Bundled reference | ngit.dev guide | +| ---------------------------------------------------------- | --------------------------- | ------------------------------------ | +| Publish, clone, host repositories; maintainers, moderators | `reference/repositories.md` | `/repositories`, `/maintainers` | +| Open, update, stack, review, merge PRs | `reference/prs.md` | `/pull-requests` | +| Issues | `reference/issues.md` | `/issues` | +| CI results, trust, workflows, ngit in CI jobs | `reference/ci.md` | `/ci`, `/ci/workflows/` | +| Accounts, login, signers, secrets | `reference/accounts.md` | `/accounts` | +| Sync, global flags, git config | `reference/sync-config.md` | `/configuration`, `/troubleshooting` | +| Publish nsites (static sites) | `reference/nsites.md` | `/releases/nsites` | +| Publish OCI containers | `reference/containers.md` | `/releases` | +| Software releases | `ngit release --help` | `/releases` | +| Automation contract, machine-readable docs | this file | `/agents/` | diff --git a/.agents/skills/ngit/reference/accounts.md b/.agents/skills/ngit/reference/accounts.md index de04a6ca..134ab8cc 100644 --- a/.agents/skills/ngit/reference/accounts.md +++ b/.agents/skills/ngit/reference/accounts.md @@ -1,8 +1,8 @@ # Accounts — identity, login, secrets -Read when managing accounts, logins, or credential storage. -Guide: https://ngit.dev/accounts (storage modes, pairing a remote signer for -CI, rotation). +Read when managing accounts, logins, or credential storage. Guide: +https://ngit.dev/accounts (storage modes, pairing a remote signer for CI, +rotation). ```bash ngit account whoami --json --offline # every usable signer with npub, aliases, scope, active state; `account list` is an alias @@ -40,8 +40,8 @@ unaliased connection. Log in with `--alias` to keep an extra connection and select it by alias. Older ngit versions ignore the exact-session binding and select the identity's default connection. -**nbunksec** is a portable established connection: remote-signer pubkey, -client secret, relays, and optional pairing secret. It holds no npub, so -one-shot use resolves the identity from the signer. The `--nbunksec-file` and -`--nsec-file` forms keep secrets out of process arguments. A fresh pairing -needs interactive approval, so unattended runs use a stored connection. +**nbunksec** is a portable established connection: remote-signer pubkey, client +secret, relays, and optional pairing secret. It holds no npub, so one-shot use +resolves the identity from the signer. The `--nbunksec-file` and `--nsec-file` +forms keep secrets out of process arguments. A fresh pairing needs interactive +approval, so unattended runs use a stored connection. diff --git a/.agents/skills/ngit/reference/ci.md b/.agents/skills/ngit/reference/ci.md index bae037f6..acd87e45 100644 --- a/.agents/skills/ngit/reference/ci.md +++ b/.agents/skills/ngit/reference/ci.md @@ -1,18 +1,18 @@ # Nostr CI -Read when checking whether CI ran, interpreting a result, or writing a -workflow that uses ngit. Guides: https://ngit.dev/ci (coordinators, results, -trust, secrets) and https://ngit.dev/ci/workflows/ (what the coordinator -accepts, refuses, and adds compared with GitHub Actions). +Read when checking whether CI ran, interpreting a result, or writing a workflow +that uses ngit. Guides: https://ngit.dev/ci (coordinators, results, trust, +secrets) and https://ngit.dev/ci/workflows/ (what the coordinator accepts, +refuses, and adds compared with GitHub Actions). ## Workflows -Nostr CI (ngit-ci) runs workflows from `.ngit/act/workflows/` with -GitHub Actions syntax in Linux containers. `.github/workflows/` is run only by -GitHub Actions on a mirror; the directories are independent, so a check that -must run in both systems needs a file in each. ngit-ci refuses macOS and -Windows `runs-on` labels and job-level `uses:` (reusable workflows); composite -actions in steps work in both systems. +Nostr CI (ngit-ci) runs workflows from `.ngit/act/workflows/` with GitHub +Actions syntax in Linux containers. `.github/workflows/` is run only by GitHub +Actions on a mirror; the directories are independent, so a check that must run +in both systems needs a file in each. ngit-ci refuses macOS and Windows +`runs-on` labels and job-level `uses:` (reusable workflows); composite actions +in steps work in both systems. Read the workflow at the commit under investigation and confirm that its triggers and steps cover the check in question: @@ -28,7 +28,7 @@ checksum-pinned manifest: ```yaml - uses: danconwaydev/setup-ngit@v3 with: - version: 3.0.0 # optional exact pin; the default `latest` resolves against the action's manifest, not the network + version: 3.0.0 # optional exact pin; the default `latest` resolves against the action's manifest, not the network ``` Source: @@ -43,25 +43,25 @@ ngit ci status --json --offline # later cache ngit ci status --require-ci-trust maintainer-directed --json # exit non-zero unless green at this floor ``` -Query the exact commit that introduced the change. A PR target reports only -its latest revision. Read: +Query the exact commit that introduced the change. A PR target reports only its +latest revision. Read: -- `ci.state`: pending, running, or concluded. `ci.conclusion` counts only - once the state is concluded. +- `ci.state`: pending, running, or concluded. `ci.conclusion` counts only once + the state is concluded. - `ci.conclusion`: success, failure, cancellation, or another outcome. `command_status: "ok"` means only that the query worked. - `ci.runs[].workflow` and `ci.runs[].jobs`: which workflow and job passed or failed. - `ci.runs[].integrity`: the commit is present locally and the workflow hash matches. -- `coverage` and each run's classification and evidence: how completely and - why the result is trusted. Partial coverage is not success. +- `coverage` and each run's classification and evidence: how completely and why + the result is trusted. Partial coverage is not success. -If no run appears, report that no matching Nostr CI event was found. Then -check that the workflow existed at that commit, its trigger matched, a -coordinator serves the repository, and the query refreshed the relays before -concluding that CI did not run. +If no run appears, report that no matching Nostr CI event was found. Then check +that the workflow existed at that commit, its trigger matched, a coordinator +serves the repository, and the query refreshed the relays before concluding that +CI did not run. Trust floors are `maintainer-directed` and `operationally-associated`. -`ngit pr merge --require-ci-trust ` applies the same gate to a merge -when the caller wants one. +`ngit pr merge --require-ci-trust ` applies the same gate to a merge when +the caller wants one. diff --git a/.agents/skills/ngit/reference/containers.md b/.agents/skills/ngit/reference/containers.md index 471e2c92..60d1559e 100644 --- a/.agents/skills/ngit/reference/containers.md +++ b/.agents/skills/ngit/reference/containers.md @@ -1,16 +1,16 @@ # Containers — publish OCI images -Read before publishing an OCI image, updating a container tag, choosing -Blossom storage, or constructing a gateway pull reference. Protocol -background: https://ngit.dev/protocol/software-publishing +Read before publishing an OCI image, updating a container tag, choosing Blossom +storage, or constructing a gateway pull reference. Protocol background: +https://ngit.dev/protocol/software-publishing ## Model `ngit container publish` (alias `ngit oci publish`) uploads the OCI blobs -reachable from the tagged entries of an OCI image layout to Blossom, then -signs a kind-30624 addressable event mapping tags to manifest digests. The -event is bound to the current kind-30617 git repository, so run it inside that -repository with a signer who is a confirmed maintainer. Gateways are read-only: +reachable from the tagged entries of an OCI image layout to Blossom, then signs +a kind-30624 addressable event mapping tags to manifest digests. The event is +bound to the current kind-30617 git repository, so run it inside that repository +with a signer who is a confirmed maintainer. Gateways are read-only: ```bash docker pull ncontainer.io//: @@ -31,8 +31,8 @@ ngit container publish myimage \ --json ``` -A checked-in `.ngit/containers.yaml` lets `ngit container publish myimage ---json` select an entry: +A checked-in `.ngit/containers.yaml` lets +`ngit container publish myimage --json` select an entry: ```yaml schema: 1 @@ -47,10 +47,10 @@ containers: Relative paths resolve from the repository root. `--manifest PATH` selects another file; `--no-manifest` ignores the default and requires `--layout`. A -loaded manifest must define `NAME`. CLI layout and metadata override the -entry, a non-empty CLI Blossom list replaces the configured list, and CLI -relays extend configured relays. Signer selection, `--replace`, and output -mode stay on the command line. +loaded manifest must define `NAME`. CLI layout and metadata override the entry, +a non-empty CLI Blossom list replaces the configured list, and CLI relays extend +configured relays. Signer selection, `--replace`, and output mode stay on the +command line. Behaviour to know: @@ -59,44 +59,43 @@ Behaviour to know: `index.json`; filenames and git tags are irrelevant. `index.json` itself is never uploaded; ngit merges the layout's tags into the tag map fetched from the latest kind-30624 event. -- Without `--blossom-server`, ngit uses the publisher's latest kind-10063 - server list. A single server means no redundancy. Every blob is checked on - every server, missing copies are uploaded with bounded retries and - verified, and the event is signed once each blob has at least one confirmed - copy; incomplete replication is reported per server. -- `--relay` extends the repository's relays; account and default relays are - not added. ngit reads the repository relays before and after uploading and - needs at least one success each time. A total preflight failure or a +- Without `--blossom-server`, ngit uses the publisher's latest kind-10063 server + list. A single server means no redundancy. Every blob is checked on every + server, missing copies are uploaded with bounded retries and verified, and the + event is signed once each blob has at least one confirmed copy; incomplete + replication is reported per server. +- `--relay` extends the repository's relays; account and default relays are not + added. ngit reads the repository relays before and after uploading and needs + at least one success each time. A total preflight failure or a concurrent-update refusal is safe to retry: uploaded blobs are - content-addressed. Keep a known state-bearing repository relay reachable - when changing relay sets, because a healthy empty relay cannot reveal an - event stranded elsewhere and a publish could then omit old tags. + content-addressed. Keep a known state-bearing repository relay reachable when + changing relay sets, because a healthy empty relay cannot reveal an event + stranded elsewhere and a publish could then omit old tags. ## Merge versus replace -Ordinary publication updates the tags found in the new layout and retains -older tags, previous server hints, omitted metadata, and unknown event tags. +Ordinary publication updates the tags found in the new layout and retains older +tags, previous server hints, omitted metadata, and unknown event tags. `--replace` publishes only the new layout's tags and selected servers, drops -omitted description, source, and unknown tags, and sets the title to -`--title` or `NAME`. Use it only when the user explicitly wants complete -replacement. +omitted description, source, and unknown tags, and sets the title to `--title` +or `NAME`. Use it only when the user explicitly wants complete replacement. ## JSON -A successful result has `command: "container.publish"`, a `warnings` array, -and `result` fields: `repository`, `git_repository`, `npub`, `name`, `naddr`, -`manifest_path` (or `null`), raw-hex `event_id` (unlike collaboration -commands' `nevent` ids), `tags` and `updated_tags`, per-blob SHA-256, size, -and per-server placement, final `blossom_servers`, and per-relay `accepted`. -Success means at least one relay accepted the event; inspect every -`result.relays[].accepted` when full fanout matters. Failures use -`command_status: "error"` with `error.details` holding per-blob and -per-server outcomes and possible orphan blobs. +A successful result has `command: "container.publish"`, a `warnings` array, and +`result` fields: `repository`, `git_repository`, `npub`, `name`, `naddr`, +`manifest_path` (or `null`), raw-hex `event_id` (unlike collaboration commands' +`nevent` ids), `tags` and `updated_tags`, per-blob SHA-256, size, and per-server +placement, final `blossom_servers`, and per-relay `accepted`. Success means at +least one relay accepted the event; inspect every `result.relays[].accepted` +when full fanout matters. Failures use `command_status: "error"` with +`error.details` holding per-blob and per-server outcomes and possible orphan +blobs. ## Limits -ngit accepts OCI and Docker v2 manifests and indexes using SHA-256, uploads -only blobs reachable from tagged roots, and rejects missing, oversized, deeply +ngit accepts OCI and Docker v2 manifests and indexes using SHA-256, uploads only +blobs reachable from tagged roots, and rejects missing, oversized, deeply nested, or mismatched graphs. It snapshots one blob at a time, so allow temporary disk roughly equal to the largest layer. It does not build images, push to registries, run a gateway, chunk layers, pull, list, or delete remote diff --git a/.agents/skills/ngit/reference/issues.md b/.agents/skills/ngit/reference/issues.md index 7dc86ecb..d31f4aba 100644 --- a/.agents/skills/ngit/reference/issues.md +++ b/.agents/skills/ngit/reference/issues.md @@ -17,13 +17,13 @@ ngit issue set-subject --subject "New title" --json ngit issue set-cover-note --body "$(cat cover-note.md)" --json ``` -`resolved` records that the problem was fixed; `close` records that it will -not be. Reference other events in `--body` as `nostr:nevent1…`. +`resolved` records that the problem was fixed; `close` records that it will not +be. Reference other events in `--body` as `nostr:nevent1…`. ## Auto-resolve from commits A commit pushed to the declared default branch resolves an issue when its -message contains a form of `close`, `fix`, `resolve`, or `implement` followed -by a unique hex ID or prefix or a `nostr:nevent1…` reference, for example +message contains a form of `close`, `fix`, `resolve`, or `implement` followed by +a unique hex ID or prefix or a `nostr:nevent1…` reference, for example `Fixes #deadbeef`. The status is published only when the pusher is the issue author or a confirmed repository member. diff --git a/.agents/skills/ngit/reference/nsites.md b/.agents/skills/ngit/reference/nsites.md index 04972b7f..601ab10c 100644 --- a/.agents/skills/ngit/reference/nsites.md +++ b/.agents/skills/ngit/reference/nsites.md @@ -1,14 +1,14 @@ # Nsites — publish static sites -Read before publishing an already-built website with `ngit nsite` or -diagnosing its Blossom uploads and NIP-5A manifest. -Guide: https://ngit.dev/releases/nsites (nsyte comparison, PR previews). +Read before publishing an already-built website with `ngit nsite` or diagnosing +its Blossom uploads and NIP-5A manifest. Guide: https://ngit.dev/releases/nsites +(nsyte comparison, PR previews). ## Publish -Pass the build output directory, not the source tree. ngit uploads every -regular file, runs no build, applies no ignore files, and rejects symlinks, -unsafe paths, and filenames without extensions. +Pass the build output directory, not the source tree. ngit uploads every regular +file, runs no build, applies no ignore files, and rejects symlinks, unsafe +paths, and filenames without extensions. ```bash ngit nsite publish dist --json # reads nsyte's .nsite/config.json when present @@ -26,33 +26,32 @@ ngit --nbunksec-file /run/secrets/publisher-nbunksec nsite publish dist --json - Config: `.nsite/config.json` (JSON, not YAML) fields `id`, `title`, `description`, `source`, `fallback`, `servers`, and `relays` are read; `--config PATH` selects another file and `--no-config` ignores it. Explicit - CLI values win, and any repeated `--blossom-server` or `--relay` replaces - that whole config array. Unsupported nsyte publication options - (`publishProfile`, `publishRelayList`, `publishServerList`, - `publishAppHandler`) produce a warning; nsyte signer fields are ignored. -- Metadata: `--title`, `--description` or `--description-file`, and - `--source` (`https://` or `nostr://`; omitted, ngit infers the selected - public repository and never a private one). NIP-5A has no logo tag; ship a - `favicon.ico` or `favicon.svg` in the build output. + CLI values win, and any repeated `--blossom-server` or `--relay` replaces that + whole config array. Unsupported nsyte publication options (`publishProfile`, + `publishRelayList`, `publishServerList`, `publishAppHandler`) produce a + warning; nsyte signer fields are ignored. +- Metadata: `--title`, `--description` or `--description-file`, and `--source` + (`https://` or `nostr://`; omitted, ngit infers the selected public repository + and never a private one). NIP-5A has no logo tag; ship a `favicon.ico` or + `favicon.svg` in the build output. - `--fallback SITE_PATH` (or config `fallback`) maps an existing HTML file in the output to `/404.html` without another upload. -- Servers: omit `--blossom-server` to use the account's latest kind-10063 - list; repeat it for replication. `--concurrency` (default 4, range 1–64) is - a global limit across presence checks and uploads. +- Servers: omit `--blossom-server` to use the account's latest kind-10063 list; + repeat it for replication. `--concurrency` (default 4, range 1–64) is a global + limit across presence checks and uploads. ## Guarantees ngit snapshots the directory before network work, deduplicates content, checks every blob on every selected server, and uploads missing copies with BUD-11 authorization. It signs the manifest only after every blob has at least one -confirmed copy, so a failed deployment cannot point the live manifest at -missing content. A server that fails three consecutive initial checks is -skipped for the rest of that pass while the others continue. +confirmed copy, so a failed deployment cannot point the live manifest at missing +content. A server that fails three consecutive initial checks is skipped for the +rest of that pass while the others continue. -Rerun the same command after a failure: blobs already on a server are -confirmed with `HEAD` and skipped, so continuation is per blob and server. An -unchanged deployment reuses the current manifest without a new signature or -relay write. +Rerun the same command after a failure: blobs already on a server are confirmed +with `HEAD` and skipped, so continuation is per blob and server. An unchanged +deployment reuses the current manifest without a new signature or relay write. ## JSON @@ -61,10 +60,10 @@ Check `command_status`, then: - `result.changed`: publication versus an unchanged no-op; - `result.config_path`, `result.fallback`, `result.relays`: resolved settings; - `result.blossom.blobs[].servers[]`: each blob and server outcome; -- `result.publication.relays[]`: manifest acknowledgements (at least one - relay must accept); -- `warnings[]`: unknown MIME types, unsupported config publications, and - failed uploads or post-upload verification per server. +- `result.publication.relays[]`: manifest acknowledgements (at least one relay + must accept); +- `warnings[]`: unknown MIME types, unsupported config publications, and failed + uploads or post-upload verification per server. On a Blossom failure inspect `error.details.blobs` and `error.details.possible_orphan_blobs`, fix the server or signer problem, and diff --git a/.agents/skills/ngit/reference/prs.md b/.agents/skills/ngit/reference/prs.md index 2a00fcfa..424d24dd 100644 --- a/.agents/skills/ngit/reference/prs.md +++ b/.agents/skills/ngit/reference/prs.md @@ -1,12 +1,12 @@ # Pull requests — open, update, stack, review, merge -Read before opening, updating, reviewing, or merging PRs. -Guide: https://ngit.dev/pull-requests +Read before opening, updating, reviewing, or merging PRs. Guide: +https://ngit.dev/pull-requests ## Open or update a PR -The branch name MUST start with `pr/`. No push option turns another branch -into a PR. +The branch name MUST start with `pr/`. No push option turns another branch into +a PR. ```bash git checkout -b pr/my-feature @@ -21,18 +21,18 @@ git push --force origin pr/my-feature # update the PR after amend - `-d`/`--defaults` accepts the single-commit title and description without a prompt. -- Do not use `$'…\n…'` for push options, and do not pre-escape a Markdown - file into `-o description=`; open the PR with `ngit send` instead. +- Do not use `$'…\n…'` for push options, and do not pre-escape a Markdown file + into `-o description=`; open the PR with `ngit send` instead. - Stacks are inferred: a branch that contains the unique latest tip of one of - your other open or draft PRs becomes that PR's child and follows the parent - as it advances. Rebase the child onto the parent's latest tip before updating - it; ngit refuses stale children and ambiguous candidates rather than - guessing. Use `base=` for a cross-author, historical, or ambiguous parent, - and repeat it on each update if the child should stay pinned. + your other open or draft PRs becomes that PR's child and follows the parent as + it advances. Rebase the child onto the parent's latest tip before updating it; + ngit refuses stale children and ambiguous candidates rather than guessing. Use + `base=` for a cross-author, historical, or ambiguous parent, and repeat it on + each update if the child should stay pinned. - To push as another stored identity, use - `git -c nostr.signer= push …`; `--signer` applies - to `ngit` commands only. `ngit account login --local ` makes an - identity the repository default instead. + `git -c nostr.signer= push …`; `--signer` applies to + `ngit` commands only. `ngit account login --local ` makes an identity + the repository default instead. ## ngit send @@ -70,13 +70,12 @@ ngit pr merge --exclude-description --json # summary line and git push origin # publishes the merge and the applied status ``` -`ngit merge` is a compatibility alias with the same options. The merge lands -on the PR's declared target, or the default branch, resolved against the -latest Nostr repository state rather than a local tracking ref, with the -message `Merge #<8-hex>: `. Closed and applied PRs are refused -before any git change. On conflicts, resolve them and run `git commit`; the -message is already prepared, and JSON reports `action: "conflicted"` instead -of `"merged"`. +`ngit merge` is a compatibility alias with the same options. The merge lands on +the PR's declared target, or the default branch, resolved against the latest +Nostr repository state rather than a local tracking ref, with the message +`Merge #<8-hex>: `. Closed and applied PRs are refused before any git +change. On conflicts, resolve them and run `git commit`; the message is already +prepared, and JSON reports `action: "conflicted"` instead of `"merged"`. Before merging or adding maintainer fixes, run `git log --merges --oneline origin/..HEAD`. A prior `Merge #…` means a diff --git a/.agents/skills/ngit/reference/repositories.md b/.agents/skills/ngit/reference/repositories.md index 7e73060b..cdd4deb0 100644 --- a/.agents/skills/ngit/reference/repositories.md +++ b/.agents/skills/ngit/reference/repositories.md @@ -1,9 +1,9 @@ # Repositories — publish, clone, hosting, membership -Read when publishing or cloning a repository, resolving `nostr://` URL forms, -or changing an announcement's hosting, metadata, or roster. Guides: -https://ngit.dev/repositories (hosting choices, migrating from a forge, -mirrors, private repositories), https://ngit.dev/maintainers, and +Read when publishing or cloning a repository, resolving `nostr://` URL forms, or +changing an announcement's hosting, metadata, or roster. Guides: +https://ngit.dev/repositories (hosting choices, migrating from a forge, mirrors, +private repositories), https://ngit.dev/maintainers, and https://ngit.dev/maintainers/going-deeper (leadless repositories, delegated trust, removal, roster repair). @@ -36,9 +36,9 @@ ngit repo --json --offline # run git fetch origin first when the cache may The output reports `nostr_url`, effective `git_servers`, `relays`, `hashtags`, and `grasp_servers` detected from paired clone and relay entries, plus the -roster: `members`, `lead_source`, `lead_path`, `pending_actions`, and -`health`. Follow the actionable error or `pending_actions` rather than -replacing an announcement wholesale. +roster: `members`, `lead_source`, `lead_path`, `pending_actions`, and `health`. +Follow the actionable error or `pending_actions` rather than replacing an +announcement wholesale. ## Publish and host @@ -66,30 +66,30 @@ Every announcement needs at least one relay and one git server; `init` and announcement that already lacks one half. Repair it in the same command, e.g. `ngit repo edit --name "New name" --add-grasp-server grasp.example.com`. -`--identifier` is set at initial publication only: changing the `d` tag -creates a different repository coordinate. +`--identifier` is set at initial publication only: changing the `d` tag creates +a different repository coordinate. ## Edit `ngit repo edit` preserves omitted settings. Collections use targeted, repeatable actions that can be combined in one command: -| Setting | Add | Remove | -| ------- | --- | ------ | -| Grasp server | `--add-grasp-server URL` | `--remove-grasp-server URL` | +| Setting | Add | Remove | +| ---------------- | ---------------------------- | ------------------------------- | +| Grasp server | `--add-grasp-server URL` | `--remove-grasp-server URL` | | Additional relay | `--add-additional-relay URL` | `--remove-additional-relay URL` | | Additional clone | `--add-additional-clone URL` | `--remove-additional-clone URL` | -| Hashtag | `--add-hashtag TAG` | `--remove-hashtag TAG` | +| Hashtag | `--add-hashtag TAG` | `--remove-hashtag TAG` | Scalars use replacement flags: `--name`, `--description`, `--web`, `--u`, -`--earliest-unique-commit`. A grasp-derived relay or clone cannot be removed -as an additional entry; remove the grasp server and its pair goes with it. To -empty a collection, remove every value currently reported. +`--earliest-unique-commit`. A grasp-derived relay or clone cannot be removed as +an additional entry; remove the grasp server and its pair goes with it. To empty +a collection, remove every value currently reported. -Each successful edit publishes a fresh announcement and, when the repository -has Nostr state, republishes that state once so new relays and servers hold -the authoritative refs. If that fails, follow the reported `ngit sync` -recovery guidance. +Each successful edit publishes a fresh announcement and, when the repository has +Nostr state, republishes that state once so new relays and servers hold the +authoritative refs. If that fails, follow the reported `ngit sync` recovery +guidance. ## Roles and membership @@ -101,9 +101,9 @@ recovery guidance. - **Moderator**: publishes issue, PR, and patch status events (including recording an existing merge) but cannot publish git state or merge. -Membership is reciprocal: a listing is an invitation until the invitee -publishes an announcement acknowledging the role, and an invited member's -events are not authoritative until then. +Membership is reciprocal: a listing is an invitation until the invitee publishes +an announcement acknowledging the role, and an invited member's events are not +authoritative until then. ```bash ngit repo edit --add-maintainer --json # a sole maintainer's first add makes them lead diff --git a/.agents/skills/ngit/reference/sync-config.md b/.agents/skills/ngit/reference/sync-config.md index 8993e879..13b5bee4 100644 --- a/.agents/skills/ngit/reference/sync-config.md +++ b/.agents/skills/ngit/reference/sync-config.md @@ -1,7 +1,7 @@ # Sync, flags, and configuration -Read when syncing refs, choosing flags, or tuning git config. -Guides: https://ngit.dev/configuration and https://ngit.dev/troubleshooting +Read when syncing refs, choosing flags, or tuning git config. Guides: +https://ngit.dev/configuration and https://ngit.dev/troubleshooting ## Sync @@ -15,16 +15,16 @@ ngit sync --ref-name main --json # one ref These accept any command position. `--offline` is per command; check `ngit --help`. -| Flag | Description | -| ---- | ----------- | -| `--json` | One JSON document on stdout (ngit commands only) | -| `-d`, `--defaults` | Non-interactive; accept defaults | -| `-q`, `--quiet` | Hide non-essential stderr progress (not combinable with `-v`) | -| `--repo ` | Select the target repository | -| `--signer ` | Use a stored signer for this command | +| Flag | Description | +| --------------------------------------- | ---------------------------------------------------------------------------------------------- | +| `--json` | One JSON document on stdout (ngit commands only) | +| `-d`, `--defaults` | Non-interactive; accept defaults | +| `-q`, `--quiet` | Hide non-essential stderr progress (not combinable with `-v`) | +| `--repo ` | Select the target repository | +| `--signer ` | Use a stored signer for this command | | `--nsec-file`, `--nbunksec-file ` | One-shot key or bunker session from a private file (`--nsec`, `--nbunksec` take inline values) | -| `--repo-relay-only` | Publish only to repository relays | -| `-f`, `--force` | Bypass safety guards | +| `--repo-relay-only` | Publish only to repository relays | +| `-f`, `--force` | Bypass safety guards | ## git config @@ -39,11 +39,11 @@ git config nostr.http-io-timeout-ms 600000 # allow large grasp pushes NGIT_CACHE_DIR=/writable/path ngit repo --json # override the global event-cache directory ``` -`nostr.auto-pr-branches` follows normal git config precedence. With the -default `false`, PRs appear as branches only after `ngit pr checkout`; run +`nostr.auto-pr-branches` follows normal git config precedence. With the default +`false`, PRs appear as branches only after `ngit pr checkout`; run `git fetch --prune` once to drop branches fetched by an older version, or use -`git clone --config nostr.auto-pr-branches=true ` to opt in from -the start. +`git clone --config nostr.auto-pr-branches=true ` to opt in from the +start. If the global cache directory is unavailable ngit falls back to an in-memory cache; the repository's git common directory must still be writable. diff --git a/.claude/skills/ngit/SKILL.md b/.claude/skills/ngit/SKILL.md index b55dc347..b9457b90 100644 --- a/.claude/skills/ngit/SKILL.md +++ b/.claude/skills/ngit/SKILL.md @@ -1,32 +1,39 @@ --- name: ngit -description: Commands and workflows for NIP-34 git collaboration over Nostr with the ngit CLI and git-remote-nostr. Use in any repository with a nostr:// remote for generic collaboration requests (open an Issue, create or review a Pull Request (PR), comment, merge, clone) and whenever a task involves nostr:// URLs, ngit commands, Grasp servers, gitworkshop.dev, Nostr CI status and workflows, software releases and Zapstore publication, OCI container images, or nsite static sites published through Blossom. +description: + Commands and workflows for NIP-34 git collaboration over Nostr with the ngit + CLI and git-remote-nostr. Use in any repository with a nostr:// remote for + generic collaboration requests (open an Issue, create or review a Pull Request + (PR), comment, merge, clone) and whenever a task involves nostr:// URLs, ngit + commands, Grasp servers, gitworkshop.dev, Nostr CI status and workflows, + software releases and Zapstore publication, OCI container images, or nsite + static sites published through Blossom. license: CC-BY-SA-4.0 metadata: - version: "1.17" + version: "1.18" --- # ngit — Nostr Plugin for Git -ngit makes `git clone`, `fetch`, and `push` work with `nostr://` URLs and adds -a CLI for pull requests, issues, membership, CI results, releases, OCI -containers, and nsites. Repository state (which commit each ref points to) is -published as signed Nostr events and is the source of truth; git objects live -on ordinary git servers, so servers are interchangeable. A grasp server bundles -a relay and a git server and creates the repository automatically when an -announcement lists it. Explanation: https://ngit.dev/how-it-works +ngit makes `git clone`, `fetch`, and `push` work with `nostr://` URLs and adds a +CLI for pull requests, issues, membership, CI results, releases, OCI containers, +and nsites. Repository state (which commit each ref points to) is published as +signed Nostr events and is the source of truth; git objects live on ordinary git +servers, so servers are interchangeable. A grasp server bundles a relay and a +git server and creates the repository automatically when an announcement lists +it. Explanation: https://ngit.dev/how-it-works ## Where to look - **This skill documents ngit v3.** Run `ngit --version` first; the commands - here need 3.0.0 or later. If ngit is missing or older, report that and - offer an install or update: `curl -fsSL https://ngit.dev/install.sh | bash` - installs or replaces `ngit` and `git-remote-nostr`, and `ngit update` works - on v3 or later. Other methods: https://ngit.dev/install -- **`ngit --help`** is the authority for the installed version's - flags and defaults. -- **https://ngit.dev** holds the guides. Any page is available as raw - Markdown at `https://ngit.dev/markdown/.md`; the index is + here need 3.0.0 or later. If ngit is missing or older, report that and offer + an install or update: `curl -fsSL https://ngit.dev/install.sh | bash` installs + or replaces `ngit` and `git-remote-nostr`, and `ngit update` works on v3 or + later. Other methods: https://ngit.dev/install +- **`ngit --help`** is the authority for the installed version's flags + and defaults. +- **https://ngit.dev** holds the guides. Any page is available as raw Markdown + at `https://ngit.dev/markdown/.md`; the index is https://ngit.dev/llms.txt. Web UI: https://gitworkshop.dev ## Rules @@ -35,44 +42,40 @@ announcement lists it. Explanation: https://ngit.dev/how-it-works policy. Carry through the selected signer, target, hosting, CI, and replication settings; do not add gates, waits, workflow edits, or configuration changes that the task or repository did not choose. -- **PR branches MUST start with `pr/`** (e.g. `pr/my-feature`). Any other - branch name is a plain push and never creates a PR. +- **PR branches MUST start with `pr/`** (e.g. `pr/my-feature`). Any other branch + name is a plain push and never creates a PR. - **Read ngit output with `--json`.** It is a global option and works at any - position. Stdout is exactly one JSON document; progress and diagnostics go - to stderr. `git` commands have no `--json`. Top-level `command_status` is - `ok` for exit 0 and `error` otherwise; it never describes a nested domain - result (`ngit ci status --json` reports `ok` with - `ci.conclusion: "failure"` unless a gate was requested). + position. Stdout is exactly one JSON document; progress and diagnostics go to + stderr. `git` commands have no `--json`. Top-level `command_status` is `ok` + for exit 0 and `error` otherwise; it never describes a nested domain result + (`ngit ci status --json` reports `ok` with `ci.conclusion: "failure"` unless a + gate was requested). - **Add `--offline` after the first network read** in a session, on commands that support it. `git fetch origin` also refreshes the cache. - **Identifiers.** `` accepts `nevent1…`, a 64-char hex ID, or a unique hex prefix with an optional `#` (quote it: `'#deadbeef'`). JSON `id` and `reply_to` fields are already `nevent1…`; container publication instead returns a raw-hex `event_id` plus the repository `naddr`. Reference events - inside `--body` text as `nostr:nevent1…` or `nostr:naddr1…`, never as raw - hex. Never construct a NIP-05 address (`user@domain`); use `npub1…` unless - a NIP-05 address was given to you. -- **Multiline text.** `ngit` options such as `--body` and `--description` - accept real newlines: `--body "$(cat note.md)"`. Git push options cannot - carry newlines: write literal `\n` in a short inline `-o description=…`, and - never convert a file into a push option (open the PR with `ngit send` - instead). + inside `--body` text as `nostr:nevent1…` or `nostr:naddr1…`, never as raw hex. + Never construct a NIP-05 address (`user@domain`); use `npub1…` unless a NIP-05 + address was given to you. +- **Multiline text.** `ngit` options such as `--body` and `--description` accept + real newlines: `--body "$(cat note.md)"`. Git push options cannot carry + newlines: write literal `\n` in a short inline `-o description=…`, and never + convert a file into a push option (open the PR with `ngit send` instead). - **Signers.** `--signer ` selects a stored identity - for one `ngit` command; `git -c nostr.signer= - push …` does the same for one git command. Neither changes the configured - login. Never export or pass an nsec merely to switch between configured - accounts. -- **CI.** A successful push says nothing about CI. Nostr CI runs workflows - from `.ngit/act/workflows/`; another provider's directory is not evidence. - When CI matters, query the exact commit or PR with - `ngit ci status --json` and read `ci.state` and `ci.conclusion`, - not `command_status`. + for one `ngit` command; `git -c nostr.signer= push …` + does the same for one git command. Neither changes the configured login. Never + export or pass an nsec merely to switch between configured accounts. +- **CI.** A successful push says nothing about CI. Nostr CI runs workflows from + `.ngit/act/workflows/`; another provider's directory is not evidence. When CI + matters, query the exact commit or PR with `ngit ci status --json` + and read `ci.state` and `ci.conclusion`, not `command_status`. - **Target repository.** With several `nostr://` remotes, pass global - `--repo `; a configured remote name, an naddr, and - a nostr:// URL are all accepted. Without it ngit - infers the target from config and branch tracking and fails rather than - guesses. Before a signing command, check the - `target repository: (source: …)` line on stderr. + `--repo `; a configured remote name, an naddr, and a + nostr:// URL are all accepted. Without it ngit infers the target from config + and branch tracking and fails rather than guesses. Before a signing command, + check the `target repository: (source: …)` line on stderr. ## Detecting a nostr repo @@ -81,11 +84,11 @@ git remote -v | grep -q 'nostr://' # primary check, no cache needed ngit repo --json --offline # full metadata when needed ``` -`ngit repo` always exits 0, and `is_nostr_repo: false` can be a cold-cache -false negative: if a remote shows `nostr://`, run `git fetch origin` and -retry. The output includes the roster (`members`, `lead_source`, `lead_path`, -`pending_actions`, `health`); read `reference/repositories.md` before -changing membership or hosting. +`ngit repo` always exits 0, and `is_nostr_repo: false` can be a cold-cache false +negative: if a remote shows `nostr://`, run `git fetch origin` and retry. The +output includes the roster (`members`, `lead_source`, `lead_path`, +`pending_actions`, `health`); read `reference/repositories.md` before changing +membership or hosting. ## nostr:// URLs @@ -100,18 +103,18 @@ Standard git commands accept these URLs directly. ## Task index -Read the bundled reference before performing that slice of work; the guide -adds tutorials and background. +Read the bundled reference before performing that slice of work; the guide adds +tutorials and background. -| Task | Bundled reference | ngit.dev guide | -| ---- | ----------------- | -------------- | -| Publish, clone, host repositories; maintainers, moderators | `reference/repositories.md` | `/repositories`, `/maintainers` | -| Open, update, stack, review, merge PRs | `reference/prs.md` | `/pull-requests` | -| Issues | `reference/issues.md` | `/issues` | -| CI results, trust, workflows, ngit in CI jobs | `reference/ci.md` | `/ci`, `/ci/workflows/` | -| Accounts, login, signers, secrets | `reference/accounts.md` | `/accounts` | -| Sync, global flags, git config | `reference/sync-config.md` | `/configuration`, `/troubleshooting` | -| Publish nsites (static sites) | `reference/nsites.md` | `/releases/nsites` | -| Publish OCI containers | `reference/containers.md` | `/releases` | -| Software releases | `ngit release --help` | `/releases` | -| Automation contract, machine-readable docs | this file | `/agents/` | +| Task | Bundled reference | ngit.dev guide | +| ---------------------------------------------------------- | --------------------------- | ------------------------------------ | +| Publish, clone, host repositories; maintainers, moderators | `reference/repositories.md` | `/repositories`, `/maintainers` | +| Open, update, stack, review, merge PRs | `reference/prs.md` | `/pull-requests` | +| Issues | `reference/issues.md` | `/issues` | +| CI results, trust, workflows, ngit in CI jobs | `reference/ci.md` | `/ci`, `/ci/workflows/` | +| Accounts, login, signers, secrets | `reference/accounts.md` | `/accounts` | +| Sync, global flags, git config | `reference/sync-config.md` | `/configuration`, `/troubleshooting` | +| Publish nsites (static sites) | `reference/nsites.md` | `/releases/nsites` | +| Publish OCI containers | `reference/containers.md` | `/releases` | +| Software releases | `ngit release --help` | `/releases` | +| Automation contract, machine-readable docs | this file | `/agents/` | diff --git a/.claude/skills/ngit/reference/accounts.md b/.claude/skills/ngit/reference/accounts.md index de04a6ca..134ab8cc 100644 --- a/.claude/skills/ngit/reference/accounts.md +++ b/.claude/skills/ngit/reference/accounts.md @@ -1,8 +1,8 @@ # Accounts — identity, login, secrets -Read when managing accounts, logins, or credential storage. -Guide: https://ngit.dev/accounts (storage modes, pairing a remote signer for -CI, rotation). +Read when managing accounts, logins, or credential storage. Guide: +https://ngit.dev/accounts (storage modes, pairing a remote signer for CI, +rotation). ```bash ngit account whoami --json --offline # every usable signer with npub, aliases, scope, active state; `account list` is an alias @@ -40,8 +40,8 @@ unaliased connection. Log in with `--alias` to keep an extra connection and select it by alias. Older ngit versions ignore the exact-session binding and select the identity's default connection. -**nbunksec** is a portable established connection: remote-signer pubkey, -client secret, relays, and optional pairing secret. It holds no npub, so -one-shot use resolves the identity from the signer. The `--nbunksec-file` and -`--nsec-file` forms keep secrets out of process arguments. A fresh pairing -needs interactive approval, so unattended runs use a stored connection. +**nbunksec** is a portable established connection: remote-signer pubkey, client +secret, relays, and optional pairing secret. It holds no npub, so one-shot use +resolves the identity from the signer. The `--nbunksec-file` and `--nsec-file` +forms keep secrets out of process arguments. A fresh pairing needs interactive +approval, so unattended runs use a stored connection. diff --git a/.claude/skills/ngit/reference/ci.md b/.claude/skills/ngit/reference/ci.md index bae037f6..acd87e45 100644 --- a/.claude/skills/ngit/reference/ci.md +++ b/.claude/skills/ngit/reference/ci.md @@ -1,18 +1,18 @@ # Nostr CI -Read when checking whether CI ran, interpreting a result, or writing a -workflow that uses ngit. Guides: https://ngit.dev/ci (coordinators, results, -trust, secrets) and https://ngit.dev/ci/workflows/ (what the coordinator -accepts, refuses, and adds compared with GitHub Actions). +Read when checking whether CI ran, interpreting a result, or writing a workflow +that uses ngit. Guides: https://ngit.dev/ci (coordinators, results, trust, +secrets) and https://ngit.dev/ci/workflows/ (what the coordinator accepts, +refuses, and adds compared with GitHub Actions). ## Workflows -Nostr CI (ngit-ci) runs workflows from `.ngit/act/workflows/` with -GitHub Actions syntax in Linux containers. `.github/workflows/` is run only by -GitHub Actions on a mirror; the directories are independent, so a check that -must run in both systems needs a file in each. ngit-ci refuses macOS and -Windows `runs-on` labels and job-level `uses:` (reusable workflows); composite -actions in steps work in both systems. +Nostr CI (ngit-ci) runs workflows from `.ngit/act/workflows/` with GitHub +Actions syntax in Linux containers. `.github/workflows/` is run only by GitHub +Actions on a mirror; the directories are independent, so a check that must run +in both systems needs a file in each. ngit-ci refuses macOS and Windows +`runs-on` labels and job-level `uses:` (reusable workflows); composite actions +in steps work in both systems. Read the workflow at the commit under investigation and confirm that its triggers and steps cover the check in question: @@ -28,7 +28,7 @@ checksum-pinned manifest: ```yaml - uses: danconwaydev/setup-ngit@v3 with: - version: 3.0.0 # optional exact pin; the default `latest` resolves against the action's manifest, not the network + version: 3.0.0 # optional exact pin; the default `latest` resolves against the action's manifest, not the network ``` Source: @@ -43,25 +43,25 @@ ngit ci status --json --offline # later cache ngit ci status --require-ci-trust maintainer-directed --json # exit non-zero unless green at this floor ``` -Query the exact commit that introduced the change. A PR target reports only -its latest revision. Read: +Query the exact commit that introduced the change. A PR target reports only its +latest revision. Read: -- `ci.state`: pending, running, or concluded. `ci.conclusion` counts only - once the state is concluded. +- `ci.state`: pending, running, or concluded. `ci.conclusion` counts only once + the state is concluded. - `ci.conclusion`: success, failure, cancellation, or another outcome. `command_status: "ok"` means only that the query worked. - `ci.runs[].workflow` and `ci.runs[].jobs`: which workflow and job passed or failed. - `ci.runs[].integrity`: the commit is present locally and the workflow hash matches. -- `coverage` and each run's classification and evidence: how completely and - why the result is trusted. Partial coverage is not success. +- `coverage` and each run's classification and evidence: how completely and why + the result is trusted. Partial coverage is not success. -If no run appears, report that no matching Nostr CI event was found. Then -check that the workflow existed at that commit, its trigger matched, a -coordinator serves the repository, and the query refreshed the relays before -concluding that CI did not run. +If no run appears, report that no matching Nostr CI event was found. Then check +that the workflow existed at that commit, its trigger matched, a coordinator +serves the repository, and the query refreshed the relays before concluding that +CI did not run. Trust floors are `maintainer-directed` and `operationally-associated`. -`ngit pr merge --require-ci-trust ` applies the same gate to a merge -when the caller wants one. +`ngit pr merge --require-ci-trust ` applies the same gate to a merge when +the caller wants one. diff --git a/.claude/skills/ngit/reference/containers.md b/.claude/skills/ngit/reference/containers.md index 471e2c92..60d1559e 100644 --- a/.claude/skills/ngit/reference/containers.md +++ b/.claude/skills/ngit/reference/containers.md @@ -1,16 +1,16 @@ # Containers — publish OCI images -Read before publishing an OCI image, updating a container tag, choosing -Blossom storage, or constructing a gateway pull reference. Protocol -background: https://ngit.dev/protocol/software-publishing +Read before publishing an OCI image, updating a container tag, choosing Blossom +storage, or constructing a gateway pull reference. Protocol background: +https://ngit.dev/protocol/software-publishing ## Model `ngit container publish` (alias `ngit oci publish`) uploads the OCI blobs -reachable from the tagged entries of an OCI image layout to Blossom, then -signs a kind-30624 addressable event mapping tags to manifest digests. The -event is bound to the current kind-30617 git repository, so run it inside that -repository with a signer who is a confirmed maintainer. Gateways are read-only: +reachable from the tagged entries of an OCI image layout to Blossom, then signs +a kind-30624 addressable event mapping tags to manifest digests. The event is +bound to the current kind-30617 git repository, so run it inside that repository +with a signer who is a confirmed maintainer. Gateways are read-only: ```bash docker pull ncontainer.io//: @@ -31,8 +31,8 @@ ngit container publish myimage \ --json ``` -A checked-in `.ngit/containers.yaml` lets `ngit container publish myimage ---json` select an entry: +A checked-in `.ngit/containers.yaml` lets +`ngit container publish myimage --json` select an entry: ```yaml schema: 1 @@ -47,10 +47,10 @@ containers: Relative paths resolve from the repository root. `--manifest PATH` selects another file; `--no-manifest` ignores the default and requires `--layout`. A -loaded manifest must define `NAME`. CLI layout and metadata override the -entry, a non-empty CLI Blossom list replaces the configured list, and CLI -relays extend configured relays. Signer selection, `--replace`, and output -mode stay on the command line. +loaded manifest must define `NAME`. CLI layout and metadata override the entry, +a non-empty CLI Blossom list replaces the configured list, and CLI relays extend +configured relays. Signer selection, `--replace`, and output mode stay on the +command line. Behaviour to know: @@ -59,44 +59,43 @@ Behaviour to know: `index.json`; filenames and git tags are irrelevant. `index.json` itself is never uploaded; ngit merges the layout's tags into the tag map fetched from the latest kind-30624 event. -- Without `--blossom-server`, ngit uses the publisher's latest kind-10063 - server list. A single server means no redundancy. Every blob is checked on - every server, missing copies are uploaded with bounded retries and - verified, and the event is signed once each blob has at least one confirmed - copy; incomplete replication is reported per server. -- `--relay` extends the repository's relays; account and default relays are - not added. ngit reads the repository relays before and after uploading and - needs at least one success each time. A total preflight failure or a +- Without `--blossom-server`, ngit uses the publisher's latest kind-10063 server + list. A single server means no redundancy. Every blob is checked on every + server, missing copies are uploaded with bounded retries and verified, and the + event is signed once each blob has at least one confirmed copy; incomplete + replication is reported per server. +- `--relay` extends the repository's relays; account and default relays are not + added. ngit reads the repository relays before and after uploading and needs + at least one success each time. A total preflight failure or a concurrent-update refusal is safe to retry: uploaded blobs are - content-addressed. Keep a known state-bearing repository relay reachable - when changing relay sets, because a healthy empty relay cannot reveal an - event stranded elsewhere and a publish could then omit old tags. + content-addressed. Keep a known state-bearing repository relay reachable when + changing relay sets, because a healthy empty relay cannot reveal an event + stranded elsewhere and a publish could then omit old tags. ## Merge versus replace -Ordinary publication updates the tags found in the new layout and retains -older tags, previous server hints, omitted metadata, and unknown event tags. +Ordinary publication updates the tags found in the new layout and retains older +tags, previous server hints, omitted metadata, and unknown event tags. `--replace` publishes only the new layout's tags and selected servers, drops -omitted description, source, and unknown tags, and sets the title to -`--title` or `NAME`. Use it only when the user explicitly wants complete -replacement. +omitted description, source, and unknown tags, and sets the title to `--title` +or `NAME`. Use it only when the user explicitly wants complete replacement. ## JSON -A successful result has `command: "container.publish"`, a `warnings` array, -and `result` fields: `repository`, `git_repository`, `npub`, `name`, `naddr`, -`manifest_path` (or `null`), raw-hex `event_id` (unlike collaboration -commands' `nevent` ids), `tags` and `updated_tags`, per-blob SHA-256, size, -and per-server placement, final `blossom_servers`, and per-relay `accepted`. -Success means at least one relay accepted the event; inspect every -`result.relays[].accepted` when full fanout matters. Failures use -`command_status: "error"` with `error.details` holding per-blob and -per-server outcomes and possible orphan blobs. +A successful result has `command: "container.publish"`, a `warnings` array, and +`result` fields: `repository`, `git_repository`, `npub`, `name`, `naddr`, +`manifest_path` (or `null`), raw-hex `event_id` (unlike collaboration commands' +`nevent` ids), `tags` and `updated_tags`, per-blob SHA-256, size, and per-server +placement, final `blossom_servers`, and per-relay `accepted`. Success means at +least one relay accepted the event; inspect every `result.relays[].accepted` +when full fanout matters. Failures use `command_status: "error"` with +`error.details` holding per-blob and per-server outcomes and possible orphan +blobs. ## Limits -ngit accepts OCI and Docker v2 manifests and indexes using SHA-256, uploads -only blobs reachable from tagged roots, and rejects missing, oversized, deeply +ngit accepts OCI and Docker v2 manifests and indexes using SHA-256, uploads only +blobs reachable from tagged roots, and rejects missing, oversized, deeply nested, or mismatched graphs. It snapshots one blob at a time, so allow temporary disk roughly equal to the largest layer. It does not build images, push to registries, run a gateway, chunk layers, pull, list, or delete remote diff --git a/.claude/skills/ngit/reference/issues.md b/.claude/skills/ngit/reference/issues.md index 7dc86ecb..d31f4aba 100644 --- a/.claude/skills/ngit/reference/issues.md +++ b/.claude/skills/ngit/reference/issues.md @@ -17,13 +17,13 @@ ngit issue set-subject --subject "New title" --json ngit issue set-cover-note --body "$(cat cover-note.md)" --json ``` -`resolved` records that the problem was fixed; `close` records that it will -not be. Reference other events in `--body` as `nostr:nevent1…`. +`resolved` records that the problem was fixed; `close` records that it will not +be. Reference other events in `--body` as `nostr:nevent1…`. ## Auto-resolve from commits A commit pushed to the declared default branch resolves an issue when its -message contains a form of `close`, `fix`, `resolve`, or `implement` followed -by a unique hex ID or prefix or a `nostr:nevent1…` reference, for example +message contains a form of `close`, `fix`, `resolve`, or `implement` followed by +a unique hex ID or prefix or a `nostr:nevent1…` reference, for example `Fixes #deadbeef`. The status is published only when the pusher is the issue author or a confirmed repository member. diff --git a/.claude/skills/ngit/reference/nsites.md b/.claude/skills/ngit/reference/nsites.md index 04972b7f..601ab10c 100644 --- a/.claude/skills/ngit/reference/nsites.md +++ b/.claude/skills/ngit/reference/nsites.md @@ -1,14 +1,14 @@ # Nsites — publish static sites -Read before publishing an already-built website with `ngit nsite` or -diagnosing its Blossom uploads and NIP-5A manifest. -Guide: https://ngit.dev/releases/nsites (nsyte comparison, PR previews). +Read before publishing an already-built website with `ngit nsite` or diagnosing +its Blossom uploads and NIP-5A manifest. Guide: https://ngit.dev/releases/nsites +(nsyte comparison, PR previews). ## Publish -Pass the build output directory, not the source tree. ngit uploads every -regular file, runs no build, applies no ignore files, and rejects symlinks, -unsafe paths, and filenames without extensions. +Pass the build output directory, not the source tree. ngit uploads every regular +file, runs no build, applies no ignore files, and rejects symlinks, unsafe +paths, and filenames without extensions. ```bash ngit nsite publish dist --json # reads nsyte's .nsite/config.json when present @@ -26,33 +26,32 @@ ngit --nbunksec-file /run/secrets/publisher-nbunksec nsite publish dist --json - Config: `.nsite/config.json` (JSON, not YAML) fields `id`, `title`, `description`, `source`, `fallback`, `servers`, and `relays` are read; `--config PATH` selects another file and `--no-config` ignores it. Explicit - CLI values win, and any repeated `--blossom-server` or `--relay` replaces - that whole config array. Unsupported nsyte publication options - (`publishProfile`, `publishRelayList`, `publishServerList`, - `publishAppHandler`) produce a warning; nsyte signer fields are ignored. -- Metadata: `--title`, `--description` or `--description-file`, and - `--source` (`https://` or `nostr://`; omitted, ngit infers the selected - public repository and never a private one). NIP-5A has no logo tag; ship a - `favicon.ico` or `favicon.svg` in the build output. + CLI values win, and any repeated `--blossom-server` or `--relay` replaces that + whole config array. Unsupported nsyte publication options (`publishProfile`, + `publishRelayList`, `publishServerList`, `publishAppHandler`) produce a + warning; nsyte signer fields are ignored. +- Metadata: `--title`, `--description` or `--description-file`, and `--source` + (`https://` or `nostr://`; omitted, ngit infers the selected public repository + and never a private one). NIP-5A has no logo tag; ship a `favicon.ico` or + `favicon.svg` in the build output. - `--fallback SITE_PATH` (or config `fallback`) maps an existing HTML file in the output to `/404.html` without another upload. -- Servers: omit `--blossom-server` to use the account's latest kind-10063 - list; repeat it for replication. `--concurrency` (default 4, range 1–64) is - a global limit across presence checks and uploads. +- Servers: omit `--blossom-server` to use the account's latest kind-10063 list; + repeat it for replication. `--concurrency` (default 4, range 1–64) is a global + limit across presence checks and uploads. ## Guarantees ngit snapshots the directory before network work, deduplicates content, checks every blob on every selected server, and uploads missing copies with BUD-11 authorization. It signs the manifest only after every blob has at least one -confirmed copy, so a failed deployment cannot point the live manifest at -missing content. A server that fails three consecutive initial checks is -skipped for the rest of that pass while the others continue. +confirmed copy, so a failed deployment cannot point the live manifest at missing +content. A server that fails three consecutive initial checks is skipped for the +rest of that pass while the others continue. -Rerun the same command after a failure: blobs already on a server are -confirmed with `HEAD` and skipped, so continuation is per blob and server. An -unchanged deployment reuses the current manifest without a new signature or -relay write. +Rerun the same command after a failure: blobs already on a server are confirmed +with `HEAD` and skipped, so continuation is per blob and server. An unchanged +deployment reuses the current manifest without a new signature or relay write. ## JSON @@ -61,10 +60,10 @@ Check `command_status`, then: - `result.changed`: publication versus an unchanged no-op; - `result.config_path`, `result.fallback`, `result.relays`: resolved settings; - `result.blossom.blobs[].servers[]`: each blob and server outcome; -- `result.publication.relays[]`: manifest acknowledgements (at least one - relay must accept); -- `warnings[]`: unknown MIME types, unsupported config publications, and - failed uploads or post-upload verification per server. +- `result.publication.relays[]`: manifest acknowledgements (at least one relay + must accept); +- `warnings[]`: unknown MIME types, unsupported config publications, and failed + uploads or post-upload verification per server. On a Blossom failure inspect `error.details.blobs` and `error.details.possible_orphan_blobs`, fix the server or signer problem, and diff --git a/.claude/skills/ngit/reference/prs.md b/.claude/skills/ngit/reference/prs.md index 2a00fcfa..424d24dd 100644 --- a/.claude/skills/ngit/reference/prs.md +++ b/.claude/skills/ngit/reference/prs.md @@ -1,12 +1,12 @@ # Pull requests — open, update, stack, review, merge -Read before opening, updating, reviewing, or merging PRs. -Guide: https://ngit.dev/pull-requests +Read before opening, updating, reviewing, or merging PRs. Guide: +https://ngit.dev/pull-requests ## Open or update a PR -The branch name MUST start with `pr/`. No push option turns another branch -into a PR. +The branch name MUST start with `pr/`. No push option turns another branch into +a PR. ```bash git checkout -b pr/my-feature @@ -21,18 +21,18 @@ git push --force origin pr/my-feature # update the PR after amend - `-d`/`--defaults` accepts the single-commit title and description without a prompt. -- Do not use `$'…\n…'` for push options, and do not pre-escape a Markdown - file into `-o description=`; open the PR with `ngit send` instead. +- Do not use `$'…\n…'` for push options, and do not pre-escape a Markdown file + into `-o description=`; open the PR with `ngit send` instead. - Stacks are inferred: a branch that contains the unique latest tip of one of - your other open or draft PRs becomes that PR's child and follows the parent - as it advances. Rebase the child onto the parent's latest tip before updating - it; ngit refuses stale children and ambiguous candidates rather than - guessing. Use `base=` for a cross-author, historical, or ambiguous parent, - and repeat it on each update if the child should stay pinned. + your other open or draft PRs becomes that PR's child and follows the parent as + it advances. Rebase the child onto the parent's latest tip before updating it; + ngit refuses stale children and ambiguous candidates rather than guessing. Use + `base=` for a cross-author, historical, or ambiguous parent, and repeat it on + each update if the child should stay pinned. - To push as another stored identity, use - `git -c nostr.signer= push …`; `--signer` applies - to `ngit` commands only. `ngit account login --local ` makes an - identity the repository default instead. + `git -c nostr.signer= push …`; `--signer` applies to + `ngit` commands only. `ngit account login --local ` makes an identity + the repository default instead. ## ngit send @@ -70,13 +70,12 @@ ngit pr merge --exclude-description --json # summary line and git push origin # publishes the merge and the applied status ``` -`ngit merge` is a compatibility alias with the same options. The merge lands -on the PR's declared target, or the default branch, resolved against the -latest Nostr repository state rather than a local tracking ref, with the -message `Merge #<8-hex>: `. Closed and applied PRs are refused -before any git change. On conflicts, resolve them and run `git commit`; the -message is already prepared, and JSON reports `action: "conflicted"` instead -of `"merged"`. +`ngit merge` is a compatibility alias with the same options. The merge lands on +the PR's declared target, or the default branch, resolved against the latest +Nostr repository state rather than a local tracking ref, with the message +`Merge #<8-hex>: `. Closed and applied PRs are refused before any git +change. On conflicts, resolve them and run `git commit`; the message is already +prepared, and JSON reports `action: "conflicted"` instead of `"merged"`. Before merging or adding maintainer fixes, run `git log --merges --oneline origin/..HEAD`. A prior `Merge #…` means a diff --git a/.claude/skills/ngit/reference/repositories.md b/.claude/skills/ngit/reference/repositories.md index 7e73060b..cdd4deb0 100644 --- a/.claude/skills/ngit/reference/repositories.md +++ b/.claude/skills/ngit/reference/repositories.md @@ -1,9 +1,9 @@ # Repositories — publish, clone, hosting, membership -Read when publishing or cloning a repository, resolving `nostr://` URL forms, -or changing an announcement's hosting, metadata, or roster. Guides: -https://ngit.dev/repositories (hosting choices, migrating from a forge, -mirrors, private repositories), https://ngit.dev/maintainers, and +Read when publishing or cloning a repository, resolving `nostr://` URL forms, or +changing an announcement's hosting, metadata, or roster. Guides: +https://ngit.dev/repositories (hosting choices, migrating from a forge, mirrors, +private repositories), https://ngit.dev/maintainers, and https://ngit.dev/maintainers/going-deeper (leadless repositories, delegated trust, removal, roster repair). @@ -36,9 +36,9 @@ ngit repo --json --offline # run git fetch origin first when the cache may The output reports `nostr_url`, effective `git_servers`, `relays`, `hashtags`, and `grasp_servers` detected from paired clone and relay entries, plus the -roster: `members`, `lead_source`, `lead_path`, `pending_actions`, and -`health`. Follow the actionable error or `pending_actions` rather than -replacing an announcement wholesale. +roster: `members`, `lead_source`, `lead_path`, `pending_actions`, and `health`. +Follow the actionable error or `pending_actions` rather than replacing an +announcement wholesale. ## Publish and host @@ -66,30 +66,30 @@ Every announcement needs at least one relay and one git server; `init` and announcement that already lacks one half. Repair it in the same command, e.g. `ngit repo edit --name "New name" --add-grasp-server grasp.example.com`. -`--identifier` is set at initial publication only: changing the `d` tag -creates a different repository coordinate. +`--identifier` is set at initial publication only: changing the `d` tag creates +a different repository coordinate. ## Edit `ngit repo edit` preserves omitted settings. Collections use targeted, repeatable actions that can be combined in one command: -| Setting | Add | Remove | -| ------- | --- | ------ | -| Grasp server | `--add-grasp-server URL` | `--remove-grasp-server URL` | +| Setting | Add | Remove | +| ---------------- | ---------------------------- | ------------------------------- | +| Grasp server | `--add-grasp-server URL` | `--remove-grasp-server URL` | | Additional relay | `--add-additional-relay URL` | `--remove-additional-relay URL` | | Additional clone | `--add-additional-clone URL` | `--remove-additional-clone URL` | -| Hashtag | `--add-hashtag TAG` | `--remove-hashtag TAG` | +| Hashtag | `--add-hashtag TAG` | `--remove-hashtag TAG` | Scalars use replacement flags: `--name`, `--description`, `--web`, `--u`, -`--earliest-unique-commit`. A grasp-derived relay or clone cannot be removed -as an additional entry; remove the grasp server and its pair goes with it. To -empty a collection, remove every value currently reported. +`--earliest-unique-commit`. A grasp-derived relay or clone cannot be removed as +an additional entry; remove the grasp server and its pair goes with it. To empty +a collection, remove every value currently reported. -Each successful edit publishes a fresh announcement and, when the repository -has Nostr state, republishes that state once so new relays and servers hold -the authoritative refs. If that fails, follow the reported `ngit sync` -recovery guidance. +Each successful edit publishes a fresh announcement and, when the repository has +Nostr state, republishes that state once so new relays and servers hold the +authoritative refs. If that fails, follow the reported `ngit sync` recovery +guidance. ## Roles and membership @@ -101,9 +101,9 @@ recovery guidance. - **Moderator**: publishes issue, PR, and patch status events (including recording an existing merge) but cannot publish git state or merge. -Membership is reciprocal: a listing is an invitation until the invitee -publishes an announcement acknowledging the role, and an invited member's -events are not authoritative until then. +Membership is reciprocal: a listing is an invitation until the invitee publishes +an announcement acknowledging the role, and an invited member's events are not +authoritative until then. ```bash ngit repo edit --add-maintainer --json # a sole maintainer's first add makes them lead diff --git a/.claude/skills/ngit/reference/sync-config.md b/.claude/skills/ngit/reference/sync-config.md index 8993e879..13b5bee4 100644 --- a/.claude/skills/ngit/reference/sync-config.md +++ b/.claude/skills/ngit/reference/sync-config.md @@ -1,7 +1,7 @@ # Sync, flags, and configuration -Read when syncing refs, choosing flags, or tuning git config. -Guides: https://ngit.dev/configuration and https://ngit.dev/troubleshooting +Read when syncing refs, choosing flags, or tuning git config. Guides: +https://ngit.dev/configuration and https://ngit.dev/troubleshooting ## Sync @@ -15,16 +15,16 @@ ngit sync --ref-name main --json # one ref These accept any command position. `--offline` is per command; check `ngit --help`. -| Flag | Description | -| ---- | ----------- | -| `--json` | One JSON document on stdout (ngit commands only) | -| `-d`, `--defaults` | Non-interactive; accept defaults | -| `-q`, `--quiet` | Hide non-essential stderr progress (not combinable with `-v`) | -| `--repo ` | Select the target repository | -| `--signer ` | Use a stored signer for this command | +| Flag | Description | +| --------------------------------------- | ---------------------------------------------------------------------------------------------- | +| `--json` | One JSON document on stdout (ngit commands only) | +| `-d`, `--defaults` | Non-interactive; accept defaults | +| `-q`, `--quiet` | Hide non-essential stderr progress (not combinable with `-v`) | +| `--repo ` | Select the target repository | +| `--signer ` | Use a stored signer for this command | | `--nsec-file`, `--nbunksec-file ` | One-shot key or bunker session from a private file (`--nsec`, `--nbunksec` take inline values) | -| `--repo-relay-only` | Publish only to repository relays | -| `-f`, `--force` | Bypass safety guards | +| `--repo-relay-only` | Publish only to repository relays | +| `-f`, `--force` | Bypass safety guards | ## git config @@ -39,11 +39,11 @@ git config nostr.http-io-timeout-ms 600000 # allow large grasp pushes NGIT_CACHE_DIR=/writable/path ngit repo --json # override the global event-cache directory ``` -`nostr.auto-pr-branches` follows normal git config precedence. With the -default `false`, PRs appear as branches only after `ngit pr checkout`; run +`nostr.auto-pr-branches` follows normal git config precedence. With the default +`false`, PRs appear as branches only after `ngit pr checkout`; run `git fetch --prune` once to drop branches fetched by an older version, or use -`git clone --config nostr.auto-pr-branches=true ` to opt in from -the start. +`git clone --config nostr.auto-pr-branches=true ` to opt in from the +start. If the global cache directory is unavailable ngit falls back to an in-memory cache; the repository's git common directory must still be writable.