From aae452697d152694a8f163219f707356e84b420b Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Tue, 10 Feb 2026 12:52:32 +0000 Subject: docs: update documentation for non-interactive mode Add maintainer-model architecture documentation. Update README to reflect non-interactive default behavior. --- docs/architecture/maintainer-model.md | 84 +++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 docs/architecture/maintainer-model.md (limited to 'docs/architecture/maintainer-model.md') diff --git a/docs/architecture/maintainer-model.md b/docs/architecture/maintainer-model.md new file mode 100644 index 0000000..9aebea7 --- /dev/null +++ b/docs/architecture/maintainer-model.md @@ -0,0 +1,84 @@ +# Maintainer Model + +How ngit handles multi-maintainer repositories: coordinate discovery, maintainer sets, and the distinction between shared metadata and personal infrastructure. + +## Coordinate Discovery + +A **coordinate** is a `(kind, pubkey, identifier)` tuple that uniquely identifies a repository on nostr. The pubkey in the coordinate is the **trusted maintainer** (typically the original creator). + +ngit discovers the coordinate locally from (in priority order): + +1. `nostr://` git remotes +2. `nostr.repo` git config +3. `maintainers.yaml` + +No network access is required to find the coordinate. The coordinate may exist without a corresponding announcement event on relays. + +## Maintainer Set + +Each repository announcement (kind 30617) contains a `maintainers` tag listing public keys. These form a recursive set: if Alice lists Bob, and Bob lists Carol, then {Alice, Bob, Carol} are all in the maintainer set. + +Each maintainer independently decides who they list. Adding someone to your maintainers tag is an invitation to co-maintain. + +## Consuming vs Publishing + +The key architectural distinction is between **consuming** repository data (fetching, cloning, listing) and **publishing** it (`ngit init`). + +### Consuming: Union Across Maintainers + +When consuming repo data, `relays`, `clone` (git server URLs), and `blossoms` are **unioned** across all maintainers' announcement events. This means any maintainer can add a mirror git server or relay and all users benefit automatically. + +### Publishing: Personal Infrastructure, Shared Metadata + +When publishing via `ngit init`, fields are sourced differently depending on their type: + +#### Shared Metadata + +Sourced from the **latest event** (by `created_at`) across the maintainer set: + +- `name` +- `description` +- `web` +- `hashtags` + +Rationale: these are shared identity. If any maintainer updates the project name, all subsequent re-announcements should pick it up. + +#### Infrastructure (Personal) + +Each maintainer has their own infrastructure preferences. When publishing, infrastructure comes from **my own announcement only**, not the union: + +- **Grasp servers** -- where my git+nostr data is hosted. Each grasp server derives: + - Clone URL: `https://{server}/{npub}/{identifier}.git` + - Relay URL: `wss://{server}` + - Blossom URL: `https://{server}` +- **Additional relays, git servers, blossoms** -- beyond what grasp servers provide + +Grasp-format clone URLs belonging to other maintainers are kept as additional git servers (they're part of the union for consumers) but are not treated as my grasp servers. + +#### Maintainers + +Sourced from **my own announcement only**. Each maintainer independently decides who they list. + +If I don't have an existing announcement (first time co-maintaining), the default is `[me, trusted_maintainer]`. + +#### Earliest Unique Commit + +Cascade: my own event's value, then other maintainers' values, then the local root commit. A mismatch between maintainers may indicate a fork. + +#### Identifier + +From the existing coordinate. Cannot change without `--force` (changing it creates a new repository). + +## Init States + +When `ngit init` runs, there are 5 possible states based on what exists locally and on relays: + +| State | Condition | Behavior | +|-------|-----------|----------| +| **Fresh** | No coordinate found | Must provide name + server infrastructure | +| **Coordinate Only** | Coordinate exists, no announcement on relays | Requires `--force` (could be a relay/network issue) | +| **My Announcement** | Announcement exists, I'm the trusted maintainer | Re-publish/update, no force needed | +| **Co-Maintainer** | Announcement exists, I'm listed as maintainer | Publish own announcement, no force needed | +| **Not Listed** | Announcement exists, I'm not in maintainer set | Requires `--force` | + +See `src/bin/ngit/sub_commands/init.rs` (`InitState` enum) and `tests/ngit_init.rs` for the implementation and test coverage. -- cgit v1.2.3