mirror of
https://github.com/greenart7c3/Amber.git
synced 2026-09-14 00:35:08 +00:00
chore: install ngit repository skill
Add repository guidance for supported coding agents.
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
---
|
||||
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.
|
||||
license: CC-BY-SA-4.0
|
||||
metadata:
|
||||
version: "1.17"
|
||||
---
|
||||
|
||||
# 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
|
||||
|
||||
## 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 <command> --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/<route>.md`; the index is
|
||||
https://ngit.dev/llms.txt. Web UI: https://gitworkshop.dev
|
||||
|
||||
## Rules
|
||||
|
||||
- **Preserve user and repository choices.** Examples here show syntax, not
|
||||
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.
|
||||
- **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).
|
||||
- **Add `--offline` after the first network read** in a session, on commands
|
||||
that support it. `git fetch origin` also refreshes the cache.
|
||||
- **Identifiers.** `<ID|nevent>` 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).
|
||||
- **Signers.** `--signer <alias|npub|profile-name>` selects a stored identity
|
||||
for one `ngit` command; `git -c nostr.signer=<alias|npub|profile-name>
|
||||
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 <target> --json` and read `ci.state` and `ci.conclusion`,
|
||||
not `command_status`.
|
||||
- **Target repository.** With several `nostr://` remotes, pass global
|
||||
`--repo <REMOTE|NADDR|NOSTR-URL>`; 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: <naddr> (source: …)` line on stderr.
|
||||
|
||||
## Detecting a nostr repo
|
||||
|
||||
```bash
|
||||
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.
|
||||
|
||||
## nostr:// URLs
|
||||
|
||||
```
|
||||
nostr://<npub>/<identifier>
|
||||
nostr://<npub>/<relay-hint>/<identifier> # relay-hint is a bare domain, e.g. relay.ngit.dev
|
||||
nostr://<user>@<domain>/<identifier> # NIP-05, only when explicitly provided
|
||||
nostr://<domain>/<repository-path> # NIP-AD: the full /path is sent URL-encoded to /.well-known/nostr.json?path=
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
| 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/` |
|
||||
@@ -0,0 +1,47 @@
|
||||
# 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).
|
||||
|
||||
```bash
|
||||
ngit account whoami --json --offline # every usable signer with npub, aliases, scope, active state; `account list` is an alias
|
||||
ngit account login # interactive; the secret goes to the OS credential store or ngit's user-only file store
|
||||
ngit account login alice # make a stored identity the global default (alias, npub, or exact profile name)
|
||||
ngit account login --local alice # …this repository's default, including for git push
|
||||
ngit account login --nsec-file /private/key --alias alice
|
||||
ngit account login --nbunksec-file /private/connection --alias alice # store an established NIP-46 session
|
||||
ngit account login --bunker-url bunker://... # pair a remote signer
|
||||
ngit account login --local -i --alias alice # pair a fresh signer and assign or replace this alias
|
||||
ngit account login --secret-storage file # bypass the OS store; `git-config` stores plaintext and must be explicit
|
||||
ngit account create --name "Alice" --json
|
||||
ngit account export-keys --secret # print only the nsec or nbunksec; --json adds the npub
|
||||
ngit account logout --json # keeps stored keys; add --forget to delete the secret
|
||||
ngit account forget-keys <entry> --json
|
||||
ngit --signer alice issue create --subject "Bug" --body "Details" --json # one ngit command as alice
|
||||
git -c nostr.signer=alice push origin pr/topic # one git command as alice
|
||||
ngit --nsec-file /private/key <command> # one-shot key for CI; --nbunksec-file for a bunker session
|
||||
```
|
||||
|
||||
**Storage.** `auto` (OS store, then the file store), `file`, or `git-config`,
|
||||
selected with `--secret-storage`, `NGIT_SECRET_STORAGE`, or
|
||||
`nostr.secret-storage`. Git config holds the credential entry name, not the
|
||||
secret. Existing plaintext values keep working.
|
||||
|
||||
**Selection.** `--signer` and `nostr.signer` accept an alias, an npub, or an
|
||||
exact cached profile name. A profile name must match exactly one account that
|
||||
holds stored credentials, and only the resolved npub is persisted. Selection
|
||||
fails closed when the selector is missing, ambiguous, or backed by invalid
|
||||
credentials.
|
||||
|
||||
**Several NIP-46 connections for one npub.** The first connection stays the
|
||||
default selected by the bare npub; ngit refuses to replace it with another
|
||||
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.
|
||||
@@ -0,0 +1,67 @@
|
||||
# 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).
|
||||
|
||||
## 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.
|
||||
|
||||
Read the workflow at the commit under investigation and confirm that its
|
||||
triggers and steps cover the check in question:
|
||||
|
||||
```bash
|
||||
git show <COMMIT>:.ngit/act/workflows/<WORKFLOW>.yaml
|
||||
```
|
||||
|
||||
Install `ngit` and `git-remote-nostr` inside an ngit-ci or GitHub Actions job
|
||||
with the step-level composite action, which verifies downloads against a
|
||||
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
|
||||
```
|
||||
|
||||
Source:
|
||||
`nostr://npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/relay.ngit.dev/setup-ngit`
|
||||
(GitHub mirror `DanConwayDev/setup-ngit`).
|
||||
|
||||
## Query a result
|
||||
|
||||
```bash
|
||||
ngit ci status <COMMIT|'#prefix'|nevent> --json # first query refreshes relays; no target means HEAD
|
||||
ngit ci status <target> --json --offline # later cache-only reads
|
||||
ngit ci status <target> --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:
|
||||
|
||||
- `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.
|
||||
|
||||
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 <LEVEL>` applies the same gate to a merge
|
||||
when the caller wants one.
|
||||
@@ -0,0 +1,103 @@
|
||||
# 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
|
||||
|
||||
## 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:
|
||||
|
||||
```bash
|
||||
docker pull ncontainer.io/<npub>/<repository>:<tag>
|
||||
```
|
||||
|
||||
## Publish
|
||||
|
||||
Export an OCI image layout first, for example
|
||||
`podman push myimage oci:/tmp/myimage:latest`, then publish every tagged root:
|
||||
|
||||
```bash
|
||||
ngit container publish myimage \
|
||||
--layout /tmp/myimage \
|
||||
--blossom-server https://blossom-one.example \
|
||||
--blossom-server https://blossom-two.example \
|
||||
--relay wss://relay.example \
|
||||
--source https://example.com/myimage \
|
||||
--json
|
||||
```
|
||||
|
||||
A checked-in `.ngit/containers.yaml` lets `ngit container publish myimage
|
||||
--json` select an entry:
|
||||
|
||||
```yaml
|
||||
schema: 1
|
||||
publication:
|
||||
blossom_servers: [https://blossom-one.example, https://blossom-two.example]
|
||||
relays: [wss://relay.example]
|
||||
containers:
|
||||
myimage:
|
||||
layout: artifacts/myimage
|
||||
source: https://example.com/myimage
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
Behaviour to know:
|
||||
|
||||
- `NAME` is one lowercase OCI repository-name component.
|
||||
- Tags come from `org.opencontainers.image.ref.name` annotations in
|
||||
`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
|
||||
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.
|
||||
|
||||
## 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.
|
||||
`--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.
|
||||
|
||||
## 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.
|
||||
|
||||
## 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
|
||||
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
|
||||
blobs or tags. Software release assets use the separate `ngit release` model.
|
||||
@@ -0,0 +1,29 @@
|
||||
# Issues — create, view, comment, close
|
||||
|
||||
Read when working with issues. Guide: https://ngit.dev/issues
|
||||
|
||||
```bash
|
||||
ngit issue create --subject "Bug title" --body "Details as markdown" --label bug --json
|
||||
ngit issue list --json # add --status closed or --label bug to filter
|
||||
ngit issue view <ID|nevent> --json --comments
|
||||
ngit issue view <ID|nevent> --json --history # subject, cover-note, label, and status changes
|
||||
ngit issue comment <ID|nevent> --body "Reproduced on v2.1" --json
|
||||
ngit issue comment <ID|nevent> --body "Thanks!" --reply-to <comment-ID|nevent> --json
|
||||
ngit issue close <ID|nevent> --reason "wontfix" --json
|
||||
ngit issue resolved <ID|nevent> --reason "fixed in abc123" --json
|
||||
ngit issue reopen <ID|nevent> --reason "regression in v2.3" --json
|
||||
ngit issue label <ID|nevent> --label bug --label enhancement --json
|
||||
ngit issue set-subject <ID|nevent> --subject "New title" --json
|
||||
ngit issue set-cover-note <ID|nevent> --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…`.
|
||||
|
||||
## 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
|
||||
`Fixes #deadbeef`. The status is published only when the pusher is the issue
|
||||
author or a confirmed repository member.
|
||||
@@ -0,0 +1,71 @@
|
||||
# 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).
|
||||
|
||||
## 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.
|
||||
|
||||
```bash
|
||||
ngit nsite publish dist --json # reads nsyte's .nsite/config.json when present
|
||||
ngit nsite publish dist --title "My site" --json # root kind-15128 site
|
||||
ngit nsite publish dist --id docs \
|
||||
--description-file site-description.txt \
|
||||
--source "nostr://<npub>/<identifier>" \
|
||||
--blossom-server https://blossom.example.com \
|
||||
--blossom-server https://mirror.example.com \
|
||||
--relay wss://relay.example.com --json # named kind-35128 site
|
||||
ngit --signer <alias> nsite publish dist --json
|
||||
ngit --nbunksec-file /run/secrets/publisher-nbunksec nsite publish dist --json # unattended NIP-46
|
||||
```
|
||||
|
||||
- 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.
|
||||
- `--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.
|
||||
|
||||
## 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.
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
On a Blossom failure inspect `error.details.blobs` and
|
||||
`error.details.possible_orphan_blobs`, fix the server or signer problem, and
|
||||
rerun.
|
||||
@@ -0,0 +1,96 @@
|
||||
# Pull requests — open, update, stack, review, merge
|
||||
|
||||
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.
|
||||
|
||||
```bash
|
||||
git checkout -b pr/my-feature
|
||||
git push -u origin pr/my-feature # one commit: its subject and body become title and description
|
||||
git push -u origin pr/my-feature \
|
||||
-o 'title=My feature' \
|
||||
-o 'description=First paragraph.\n\nSecond paragraph.' # literal \n; push options cannot carry real newlines
|
||||
git push -u origin pr/release-fix -o target-branch=release/2.x
|
||||
git push -u origin pr/second-part -o base=<commit|branch|nevent> # pin or override the stack parent
|
||||
git push --force origin pr/my-feature # update the PR after amending or rebasing
|
||||
```
|
||||
|
||||
- `-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.
|
||||
- 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.
|
||||
- To push as another stored identity, use
|
||||
`git -c nostr.signer=<alias|npub|profile-name> push …`; `--signer` applies
|
||||
to `ngit` commands only. `ngit account login --local <alias>` makes an
|
||||
identity the repository default instead.
|
||||
|
||||
## ngit send
|
||||
|
||||
`ngit send` takes ordinary shell arguments, so `--description` accepts real
|
||||
newlines from `$'…'` or `"$(cat file.md)"`. Inside double quotes `\n` stays a
|
||||
literal backslash-n.
|
||||
|
||||
```bash
|
||||
ngit send HEAD~2 --subject "My feature" --description "$(cat pr-description.md)" --json
|
||||
ngit send HEAD~2 --in-reply-to <PR-ID|nevent> --json # new revision of an existing PR
|
||||
ngit send --defaults --target-branch release/2.x --json
|
||||
ngit send --defaults --base <commit|branch|nevent> --json
|
||||
```
|
||||
|
||||
Do not also push a `pr/` branch for the same proposal.
|
||||
|
||||
## Read, comment, check out
|
||||
|
||||
```bash
|
||||
ngit pr list --json # default filter: open,draft
|
||||
ngit pr list --json --status open,draft,closed,applied --label bug
|
||||
ngit pr view <ID|nevent> --json --comments
|
||||
ngit pr comment <ID|nevent> --body "Looks good" --json
|
||||
ngit pr comment <ID|nevent> --body "Fixed!" --reply-to <comment-ID|nevent> --json
|
||||
ngit pr checkout <ID|nevent> --json # local tracking branch that git pull/push understand
|
||||
```
|
||||
|
||||
## Merge (maintainer)
|
||||
|
||||
```bash
|
||||
ngit pr merge <ID|nevent> --json # no-ff merge commit on the PR's target; does not push
|
||||
ngit pr merge --json # PR inferred from the checked-out pr/ branch
|
||||
ngit pr merge <ID|nevent> --require-ci-trust maintainer-directed --json # refuse unless CI is green at this trust floor
|
||||
ngit pr merge <ID|nevent> --exclude-description --json # summary line and PR reference only
|
||||
git push origin <target-branch> # 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>: <PR title>`. 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/<target>..HEAD`. A prior `Merge #…` means a
|
||||
merge would nest merge history; rebase or cherry-pick the PR commits onto the
|
||||
current target first unless that history is intentional.
|
||||
|
||||
## Lifecycle
|
||||
|
||||
```bash
|
||||
ngit pr close <ID|nevent> --reason "blocked by upstream" --json
|
||||
ngit pr reopen <ID|nevent> --reason "fix was incomplete" --json
|
||||
ngit pr ready <ID|nevent> --reason "addressed review feedback" --json
|
||||
ngit pr draft <ID|nevent> --reason "needs more work" --json
|
||||
ngit pr label <ID|nevent> --label bug --label enhancement --json
|
||||
ngit pr set-subject <ID|nevent> --subject "New title" --json
|
||||
ngit pr set-cover-note <ID|nevent> --body "Updated description. See nostr:nevent1abc…" --json
|
||||
```
|
||||
@@ -0,0 +1,119 @@
|
||||
# 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
|
||||
https://ngit.dev/maintainers/going-deeper (leadless repositories, delegated
|
||||
trust, removal, roster repair).
|
||||
|
||||
## URLs
|
||||
|
||||
```
|
||||
nostr://<npub>/<identifier>
|
||||
nostr://<npub>/<relay-hint>/<identifier> # relay-hint is a bare domain, e.g. relay.ngit.dev
|
||||
nostr://<user>@<domain>/<identifier> # NIP-05, only when explicitly provided
|
||||
nostr://<domain>/<repository-path> # NIP-AD: the full /path is sent URL-encoded to /.well-known/nostr.json?path=
|
||||
```
|
||||
|
||||
## Clone
|
||||
|
||||
```bash
|
||||
git clone nostr://<npub>/<relay-hint>/<identifier> # relay hint skips discovery
|
||||
git clone nostr://<npub>/<identifier>
|
||||
git clone nostr://user@domain.com/<identifier> # NIP-05, only if given to you
|
||||
git clone nostr://ngit.dev/ngit.git # NIP-AD bare-domain path
|
||||
```
|
||||
|
||||
Open and draft PRs are not fetched as branches unless `nostr.auto-pr-branches`
|
||||
is `true`; `ngit pr checkout <ID|nevent>` materialises one on demand.
|
||||
|
||||
## Inspect
|
||||
|
||||
```bash
|
||||
ngit repo --json --offline # run git fetch origin first when the cache may be stale
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
## Publish and host
|
||||
|
||||
`ngit init` declares the complete initial announcement. Grasp hosting supplies
|
||||
both a git server and a relay; additional infrastructure is explicit, empty by
|
||||
default, and supplements grasp hosting rather than replacing it:
|
||||
|
||||
```
|
||||
relays = grasp-derived relays + additional relays
|
||||
clones = grasp-derived clones + additional clones
|
||||
```
|
||||
|
||||
```bash
|
||||
ngit init --name "My Project" --description "What it does" --defaults --json # preferred grasp servers, else ngit defaults
|
||||
ngit init --name "My Project" --grasp-server grasp.example.com --defaults --json
|
||||
ngit init --name "My Project" --additional-relay wss://relay.example.com \
|
||||
--additional-clone https://git.example.com/my-project.git --defaults --json
|
||||
ngit init --name "My Project" --grasp-server "" \
|
||||
--additional-relay wss://relay.example.com \
|
||||
--additional-clone https://git.example.com/my-project.git --defaults --json # no grasp: both halves required
|
||||
```
|
||||
|
||||
Every announcement needs at least one relay and one git server; `init` and
|
||||
`repo edit` refuse to publish otherwise, including a metadata-only edit of an
|
||||
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.
|
||||
|
||||
## 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` |
|
||||
| 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` |
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
- **Co-maintainer**: publishes git state, merges, manages issues and PRs, and
|
||||
changes the roster at the protocol level.
|
||||
- **Lead maintainer**: the same authority plus responsibility for the roster.
|
||||
When a lead exists, ngit restricts routine roster changes to the lead
|
||||
workflow.
|
||||
- **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.
|
||||
|
||||
```bash
|
||||
ngit repo edit --add-maintainer <npub> --json # a sole maintainer's first add makes them lead
|
||||
ngit repo accept --json # invitee confirms the role and the lead; --grasp-server <url> also hosts the git data there
|
||||
ngit repo follow-lead --json # members retain history and follow a changed lead or roster
|
||||
ngit repo leave --json # end your own role and republish
|
||||
ngit repo edit --remove-maintainer <npub> --json
|
||||
ngit repo edit --lead-maintainer <npub> --json # handover: the new lead publishes the full roster first
|
||||
ngit repo edit --acknowledge-maintainer-change <npub> --json
|
||||
```
|
||||
|
||||
Change one relationship at a time. In the deliberately leadless case, pass
|
||||
`--no-lead-maintainer` with every `--add-maintainer` or `--remove-maintainer`.
|
||||
@@ -0,0 +1,49 @@
|
||||
# Sync, flags, and configuration
|
||||
|
||||
Read when syncing refs, choosing flags, or tuning git config.
|
||||
Guides: https://ngit.dev/configuration and https://ngit.dev/troubleshooting
|
||||
|
||||
## Sync
|
||||
|
||||
```bash
|
||||
ngit sync --json # make git servers reflect the Nostr state for every ref
|
||||
ngit sync --ref-name main --json # one ref
|
||||
```
|
||||
|
||||
## Global flags
|
||||
|
||||
These accept any command position. `--offline` is per command; check
|
||||
`ngit <command> --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 <REMOTE\|NADDR\|NOSTR-URL>` | Select the target repository |
|
||||
| `--signer <ALIAS\|NPUB\|NAME>` | Use a stored signer for this command |
|
||||
| `--nsec-file`, `--nbunksec-file <PATH>` | 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 |
|
||||
|
||||
## git config
|
||||
|
||||
```bash
|
||||
ngit --customize # list every option
|
||||
git config nostr.signer alice # repository signer, including for git push
|
||||
git config nostr.signer-alias.alice npub1... # portable alias-to-npub mapping
|
||||
git config nostr.secret-storage file # auto | file | git-config
|
||||
git config nostr.repo-relay-only true
|
||||
git config nostr.auto-pr-branches true # fetch every open and draft PR as a pr/* branch (default false)
|
||||
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
|
||||
`git fetch --prune` once to drop branches fetched by an older version, or use
|
||||
`git clone --config nostr.auto-pr-branches=true <nostr-url>` 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.
|
||||
@@ -0,0 +1,117 @@
|
||||
---
|
||||
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.
|
||||
license: CC-BY-SA-4.0
|
||||
metadata:
|
||||
version: "1.17"
|
||||
---
|
||||
|
||||
# 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
|
||||
|
||||
## 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 <command> --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/<route>.md`; the index is
|
||||
https://ngit.dev/llms.txt. Web UI: https://gitworkshop.dev
|
||||
|
||||
## Rules
|
||||
|
||||
- **Preserve user and repository choices.** Examples here show syntax, not
|
||||
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.
|
||||
- **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).
|
||||
- **Add `--offline` after the first network read** in a session, on commands
|
||||
that support it. `git fetch origin` also refreshes the cache.
|
||||
- **Identifiers.** `<ID|nevent>` 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).
|
||||
- **Signers.** `--signer <alias|npub|profile-name>` selects a stored identity
|
||||
for one `ngit` command; `git -c nostr.signer=<alias|npub|profile-name>
|
||||
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 <target> --json` and read `ci.state` and `ci.conclusion`,
|
||||
not `command_status`.
|
||||
- **Target repository.** With several `nostr://` remotes, pass global
|
||||
`--repo <REMOTE|NADDR|NOSTR-URL>`; 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: <naddr> (source: …)` line on stderr.
|
||||
|
||||
## Detecting a nostr repo
|
||||
|
||||
```bash
|
||||
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.
|
||||
|
||||
## nostr:// URLs
|
||||
|
||||
```
|
||||
nostr://<npub>/<identifier>
|
||||
nostr://<npub>/<relay-hint>/<identifier> # relay-hint is a bare domain, e.g. relay.ngit.dev
|
||||
nostr://<user>@<domain>/<identifier> # NIP-05, only when explicitly provided
|
||||
nostr://<domain>/<repository-path> # NIP-AD: the full /path is sent URL-encoded to /.well-known/nostr.json?path=
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
| 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/` |
|
||||
@@ -0,0 +1,47 @@
|
||||
# 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).
|
||||
|
||||
```bash
|
||||
ngit account whoami --json --offline # every usable signer with npub, aliases, scope, active state; `account list` is an alias
|
||||
ngit account login # interactive; the secret goes to the OS credential store or ngit's user-only file store
|
||||
ngit account login alice # make a stored identity the global default (alias, npub, or exact profile name)
|
||||
ngit account login --local alice # …this repository's default, including for git push
|
||||
ngit account login --nsec-file /private/key --alias alice
|
||||
ngit account login --nbunksec-file /private/connection --alias alice # store an established NIP-46 session
|
||||
ngit account login --bunker-url bunker://... # pair a remote signer
|
||||
ngit account login --local -i --alias alice # pair a fresh signer and assign or replace this alias
|
||||
ngit account login --secret-storage file # bypass the OS store; `git-config` stores plaintext and must be explicit
|
||||
ngit account create --name "Alice" --json
|
||||
ngit account export-keys --secret # print only the nsec or nbunksec; --json adds the npub
|
||||
ngit account logout --json # keeps stored keys; add --forget to delete the secret
|
||||
ngit account forget-keys <entry> --json
|
||||
ngit --signer alice issue create --subject "Bug" --body "Details" --json # one ngit command as alice
|
||||
git -c nostr.signer=alice push origin pr/topic # one git command as alice
|
||||
ngit --nsec-file /private/key <command> # one-shot key for CI; --nbunksec-file for a bunker session
|
||||
```
|
||||
|
||||
**Storage.** `auto` (OS store, then the file store), `file`, or `git-config`,
|
||||
selected with `--secret-storage`, `NGIT_SECRET_STORAGE`, or
|
||||
`nostr.secret-storage`. Git config holds the credential entry name, not the
|
||||
secret. Existing plaintext values keep working.
|
||||
|
||||
**Selection.** `--signer` and `nostr.signer` accept an alias, an npub, or an
|
||||
exact cached profile name. A profile name must match exactly one account that
|
||||
holds stored credentials, and only the resolved npub is persisted. Selection
|
||||
fails closed when the selector is missing, ambiguous, or backed by invalid
|
||||
credentials.
|
||||
|
||||
**Several NIP-46 connections for one npub.** The first connection stays the
|
||||
default selected by the bare npub; ngit refuses to replace it with another
|
||||
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.
|
||||
@@ -0,0 +1,67 @@
|
||||
# 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).
|
||||
|
||||
## 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.
|
||||
|
||||
Read the workflow at the commit under investigation and confirm that its
|
||||
triggers and steps cover the check in question:
|
||||
|
||||
```bash
|
||||
git show <COMMIT>:.ngit/act/workflows/<WORKFLOW>.yaml
|
||||
```
|
||||
|
||||
Install `ngit` and `git-remote-nostr` inside an ngit-ci or GitHub Actions job
|
||||
with the step-level composite action, which verifies downloads against a
|
||||
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
|
||||
```
|
||||
|
||||
Source:
|
||||
`nostr://npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/relay.ngit.dev/setup-ngit`
|
||||
(GitHub mirror `DanConwayDev/setup-ngit`).
|
||||
|
||||
## Query a result
|
||||
|
||||
```bash
|
||||
ngit ci status <COMMIT|'#prefix'|nevent> --json # first query refreshes relays; no target means HEAD
|
||||
ngit ci status <target> --json --offline # later cache-only reads
|
||||
ngit ci status <target> --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:
|
||||
|
||||
- `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.
|
||||
|
||||
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 <LEVEL>` applies the same gate to a merge
|
||||
when the caller wants one.
|
||||
@@ -0,0 +1,103 @@
|
||||
# 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
|
||||
|
||||
## 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:
|
||||
|
||||
```bash
|
||||
docker pull ncontainer.io/<npub>/<repository>:<tag>
|
||||
```
|
||||
|
||||
## Publish
|
||||
|
||||
Export an OCI image layout first, for example
|
||||
`podman push myimage oci:/tmp/myimage:latest`, then publish every tagged root:
|
||||
|
||||
```bash
|
||||
ngit container publish myimage \
|
||||
--layout /tmp/myimage \
|
||||
--blossom-server https://blossom-one.example \
|
||||
--blossom-server https://blossom-two.example \
|
||||
--relay wss://relay.example \
|
||||
--source https://example.com/myimage \
|
||||
--json
|
||||
```
|
||||
|
||||
A checked-in `.ngit/containers.yaml` lets `ngit container publish myimage
|
||||
--json` select an entry:
|
||||
|
||||
```yaml
|
||||
schema: 1
|
||||
publication:
|
||||
blossom_servers: [https://blossom-one.example, https://blossom-two.example]
|
||||
relays: [wss://relay.example]
|
||||
containers:
|
||||
myimage:
|
||||
layout: artifacts/myimage
|
||||
source: https://example.com/myimage
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
Behaviour to know:
|
||||
|
||||
- `NAME` is one lowercase OCI repository-name component.
|
||||
- Tags come from `org.opencontainers.image.ref.name` annotations in
|
||||
`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
|
||||
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.
|
||||
|
||||
## 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.
|
||||
`--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.
|
||||
|
||||
## 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.
|
||||
|
||||
## 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
|
||||
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
|
||||
blobs or tags. Software release assets use the separate `ngit release` model.
|
||||
@@ -0,0 +1,29 @@
|
||||
# Issues — create, view, comment, close
|
||||
|
||||
Read when working with issues. Guide: https://ngit.dev/issues
|
||||
|
||||
```bash
|
||||
ngit issue create --subject "Bug title" --body "Details as markdown" --label bug --json
|
||||
ngit issue list --json # add --status closed or --label bug to filter
|
||||
ngit issue view <ID|nevent> --json --comments
|
||||
ngit issue view <ID|nevent> --json --history # subject, cover-note, label, and status changes
|
||||
ngit issue comment <ID|nevent> --body "Reproduced on v2.1" --json
|
||||
ngit issue comment <ID|nevent> --body "Thanks!" --reply-to <comment-ID|nevent> --json
|
||||
ngit issue close <ID|nevent> --reason "wontfix" --json
|
||||
ngit issue resolved <ID|nevent> --reason "fixed in abc123" --json
|
||||
ngit issue reopen <ID|nevent> --reason "regression in v2.3" --json
|
||||
ngit issue label <ID|nevent> --label bug --label enhancement --json
|
||||
ngit issue set-subject <ID|nevent> --subject "New title" --json
|
||||
ngit issue set-cover-note <ID|nevent> --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…`.
|
||||
|
||||
## 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
|
||||
`Fixes #deadbeef`. The status is published only when the pusher is the issue
|
||||
author or a confirmed repository member.
|
||||
@@ -0,0 +1,71 @@
|
||||
# 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).
|
||||
|
||||
## 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.
|
||||
|
||||
```bash
|
||||
ngit nsite publish dist --json # reads nsyte's .nsite/config.json when present
|
||||
ngit nsite publish dist --title "My site" --json # root kind-15128 site
|
||||
ngit nsite publish dist --id docs \
|
||||
--description-file site-description.txt \
|
||||
--source "nostr://<npub>/<identifier>" \
|
||||
--blossom-server https://blossom.example.com \
|
||||
--blossom-server https://mirror.example.com \
|
||||
--relay wss://relay.example.com --json # named kind-35128 site
|
||||
ngit --signer <alias> nsite publish dist --json
|
||||
ngit --nbunksec-file /run/secrets/publisher-nbunksec nsite publish dist --json # unattended NIP-46
|
||||
```
|
||||
|
||||
- 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.
|
||||
- `--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.
|
||||
|
||||
## 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.
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
On a Blossom failure inspect `error.details.blobs` and
|
||||
`error.details.possible_orphan_blobs`, fix the server or signer problem, and
|
||||
rerun.
|
||||
@@ -0,0 +1,96 @@
|
||||
# Pull requests — open, update, stack, review, merge
|
||||
|
||||
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.
|
||||
|
||||
```bash
|
||||
git checkout -b pr/my-feature
|
||||
git push -u origin pr/my-feature # one commit: its subject and body become title and description
|
||||
git push -u origin pr/my-feature \
|
||||
-o 'title=My feature' \
|
||||
-o 'description=First paragraph.\n\nSecond paragraph.' # literal \n; push options cannot carry real newlines
|
||||
git push -u origin pr/release-fix -o target-branch=release/2.x
|
||||
git push -u origin pr/second-part -o base=<commit|branch|nevent> # pin or override the stack parent
|
||||
git push --force origin pr/my-feature # update the PR after amending or rebasing
|
||||
```
|
||||
|
||||
- `-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.
|
||||
- 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.
|
||||
- To push as another stored identity, use
|
||||
`git -c nostr.signer=<alias|npub|profile-name> push …`; `--signer` applies
|
||||
to `ngit` commands only. `ngit account login --local <alias>` makes an
|
||||
identity the repository default instead.
|
||||
|
||||
## ngit send
|
||||
|
||||
`ngit send` takes ordinary shell arguments, so `--description` accepts real
|
||||
newlines from `$'…'` or `"$(cat file.md)"`. Inside double quotes `\n` stays a
|
||||
literal backslash-n.
|
||||
|
||||
```bash
|
||||
ngit send HEAD~2 --subject "My feature" --description "$(cat pr-description.md)" --json
|
||||
ngit send HEAD~2 --in-reply-to <PR-ID|nevent> --json # new revision of an existing PR
|
||||
ngit send --defaults --target-branch release/2.x --json
|
||||
ngit send --defaults --base <commit|branch|nevent> --json
|
||||
```
|
||||
|
||||
Do not also push a `pr/` branch for the same proposal.
|
||||
|
||||
## Read, comment, check out
|
||||
|
||||
```bash
|
||||
ngit pr list --json # default filter: open,draft
|
||||
ngit pr list --json --status open,draft,closed,applied --label bug
|
||||
ngit pr view <ID|nevent> --json --comments
|
||||
ngit pr comment <ID|nevent> --body "Looks good" --json
|
||||
ngit pr comment <ID|nevent> --body "Fixed!" --reply-to <comment-ID|nevent> --json
|
||||
ngit pr checkout <ID|nevent> --json # local tracking branch that git pull/push understand
|
||||
```
|
||||
|
||||
## Merge (maintainer)
|
||||
|
||||
```bash
|
||||
ngit pr merge <ID|nevent> --json # no-ff merge commit on the PR's target; does not push
|
||||
ngit pr merge --json # PR inferred from the checked-out pr/ branch
|
||||
ngit pr merge <ID|nevent> --require-ci-trust maintainer-directed --json # refuse unless CI is green at this trust floor
|
||||
ngit pr merge <ID|nevent> --exclude-description --json # summary line and PR reference only
|
||||
git push origin <target-branch> # 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>: <PR title>`. 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/<target>..HEAD`. A prior `Merge #…` means a
|
||||
merge would nest merge history; rebase or cherry-pick the PR commits onto the
|
||||
current target first unless that history is intentional.
|
||||
|
||||
## Lifecycle
|
||||
|
||||
```bash
|
||||
ngit pr close <ID|nevent> --reason "blocked by upstream" --json
|
||||
ngit pr reopen <ID|nevent> --reason "fix was incomplete" --json
|
||||
ngit pr ready <ID|nevent> --reason "addressed review feedback" --json
|
||||
ngit pr draft <ID|nevent> --reason "needs more work" --json
|
||||
ngit pr label <ID|nevent> --label bug --label enhancement --json
|
||||
ngit pr set-subject <ID|nevent> --subject "New title" --json
|
||||
ngit pr set-cover-note <ID|nevent> --body "Updated description. See nostr:nevent1abc…" --json
|
||||
```
|
||||
@@ -0,0 +1,119 @@
|
||||
# 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
|
||||
https://ngit.dev/maintainers/going-deeper (leadless repositories, delegated
|
||||
trust, removal, roster repair).
|
||||
|
||||
## URLs
|
||||
|
||||
```
|
||||
nostr://<npub>/<identifier>
|
||||
nostr://<npub>/<relay-hint>/<identifier> # relay-hint is a bare domain, e.g. relay.ngit.dev
|
||||
nostr://<user>@<domain>/<identifier> # NIP-05, only when explicitly provided
|
||||
nostr://<domain>/<repository-path> # NIP-AD: the full /path is sent URL-encoded to /.well-known/nostr.json?path=
|
||||
```
|
||||
|
||||
## Clone
|
||||
|
||||
```bash
|
||||
git clone nostr://<npub>/<relay-hint>/<identifier> # relay hint skips discovery
|
||||
git clone nostr://<npub>/<identifier>
|
||||
git clone nostr://user@domain.com/<identifier> # NIP-05, only if given to you
|
||||
git clone nostr://ngit.dev/ngit.git # NIP-AD bare-domain path
|
||||
```
|
||||
|
||||
Open and draft PRs are not fetched as branches unless `nostr.auto-pr-branches`
|
||||
is `true`; `ngit pr checkout <ID|nevent>` materialises one on demand.
|
||||
|
||||
## Inspect
|
||||
|
||||
```bash
|
||||
ngit repo --json --offline # run git fetch origin first when the cache may be stale
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
## Publish and host
|
||||
|
||||
`ngit init` declares the complete initial announcement. Grasp hosting supplies
|
||||
both a git server and a relay; additional infrastructure is explicit, empty by
|
||||
default, and supplements grasp hosting rather than replacing it:
|
||||
|
||||
```
|
||||
relays = grasp-derived relays + additional relays
|
||||
clones = grasp-derived clones + additional clones
|
||||
```
|
||||
|
||||
```bash
|
||||
ngit init --name "My Project" --description "What it does" --defaults --json # preferred grasp servers, else ngit defaults
|
||||
ngit init --name "My Project" --grasp-server grasp.example.com --defaults --json
|
||||
ngit init --name "My Project" --additional-relay wss://relay.example.com \
|
||||
--additional-clone https://git.example.com/my-project.git --defaults --json
|
||||
ngit init --name "My Project" --grasp-server "" \
|
||||
--additional-relay wss://relay.example.com \
|
||||
--additional-clone https://git.example.com/my-project.git --defaults --json # no grasp: both halves required
|
||||
```
|
||||
|
||||
Every announcement needs at least one relay and one git server; `init` and
|
||||
`repo edit` refuse to publish otherwise, including a metadata-only edit of an
|
||||
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.
|
||||
|
||||
## 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` |
|
||||
| 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` |
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
- **Co-maintainer**: publishes git state, merges, manages issues and PRs, and
|
||||
changes the roster at the protocol level.
|
||||
- **Lead maintainer**: the same authority plus responsibility for the roster.
|
||||
When a lead exists, ngit restricts routine roster changes to the lead
|
||||
workflow.
|
||||
- **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.
|
||||
|
||||
```bash
|
||||
ngit repo edit --add-maintainer <npub> --json # a sole maintainer's first add makes them lead
|
||||
ngit repo accept --json # invitee confirms the role and the lead; --grasp-server <url> also hosts the git data there
|
||||
ngit repo follow-lead --json # members retain history and follow a changed lead or roster
|
||||
ngit repo leave --json # end your own role and republish
|
||||
ngit repo edit --remove-maintainer <npub> --json
|
||||
ngit repo edit --lead-maintainer <npub> --json # handover: the new lead publishes the full roster first
|
||||
ngit repo edit --acknowledge-maintainer-change <npub> --json
|
||||
```
|
||||
|
||||
Change one relationship at a time. In the deliberately leadless case, pass
|
||||
`--no-lead-maintainer` with every `--add-maintainer` or `--remove-maintainer`.
|
||||
@@ -0,0 +1,49 @@
|
||||
# Sync, flags, and configuration
|
||||
|
||||
Read when syncing refs, choosing flags, or tuning git config.
|
||||
Guides: https://ngit.dev/configuration and https://ngit.dev/troubleshooting
|
||||
|
||||
## Sync
|
||||
|
||||
```bash
|
||||
ngit sync --json # make git servers reflect the Nostr state for every ref
|
||||
ngit sync --ref-name main --json # one ref
|
||||
```
|
||||
|
||||
## Global flags
|
||||
|
||||
These accept any command position. `--offline` is per command; check
|
||||
`ngit <command> --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 <REMOTE\|NADDR\|NOSTR-URL>` | Select the target repository |
|
||||
| `--signer <ALIAS\|NPUB\|NAME>` | Use a stored signer for this command |
|
||||
| `--nsec-file`, `--nbunksec-file <PATH>` | 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 |
|
||||
|
||||
## git config
|
||||
|
||||
```bash
|
||||
ngit --customize # list every option
|
||||
git config nostr.signer alice # repository signer, including for git push
|
||||
git config nostr.signer-alias.alice npub1... # portable alias-to-npub mapping
|
||||
git config nostr.secret-storage file # auto | file | git-config
|
||||
git config nostr.repo-relay-only true
|
||||
git config nostr.auto-pr-branches true # fetch every open and draft PR as a pr/* branch (default false)
|
||||
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
|
||||
`git fetch --prune` once to drop branches fetched by an older version, or use
|
||||
`git clone --config nostr.auto-pr-branches=true <nostr-url>` 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.
|
||||
@@ -72,3 +72,5 @@ Use the committed scripts for cloud environments:
|
||||
## Reproducibility
|
||||
|
||||
`Dockerfile` + `apkdiff.py` verify reproducible builds: `docker build -t amber-repro --build-arg VERSION=vX.Y.Z --build-arg APK_TYPE=free-arm64-v8a .` then `docker run --rm amber-repro` (expect `APKs match!`).
|
||||
|
||||
- For repository collaboration, use ngit and follow `.agents/skills/ngit/SKILL.md`.
|
||||
|
||||
@@ -89,4 +89,6 @@ In other words, the lock controls who can open and navigate the app UI; it does
|
||||
| `ConnectivityService.kt` | Foreground service, network monitoring, relay reconnection |
|
||||
| `BiometricAuthScreen.kt` | UI-only app-launch lock (biometric/PIN); not a signing gate |
|
||||
| `Biometrics.kt` | Wraps `BiometricPrompt` / keyguard credential prompt |
|
||||
| `SecurityScreen.kt` | Toggles `useAuth` / `usePin` and the re-prompt interval |
|
||||
| `SecurityScreen.kt` | Toggles `useAuth` / `usePin` and the re-prompt interval |
|
||||
|
||||
- For repository collaboration, use ngit and follow `.claude/skills/ngit/SKILL.md`.
|
||||
|
||||
Reference in New Issue
Block a user