upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--docs/architecture/maintainer-model.md84
2 files changed, 85 insertions, 1 deletions
diff --git a/README.md b/README.md
index 3d172a2..074cde3 100644
--- a/README.md
+++ b/README.md
@@ -41,7 +41,7 @@ for code collaboration, nostr is used for:
41- state (ie. git refs) 41- state (ie. git refs)
42- proposals (PRs), issues and related discussion 42- proposals (PRs), issues and related discussion
43 43
44a git server is still required for data storage and syncing state. multiple git servers can be used for reduncancy and they can be seemlessly swapped out by maintainers just like nostr relays. 44a git server is still required for data storage and syncing state. multiple git servers can be used for reduncancy and they can be seemlessly swapped out by maintainers just like nostr relays. see [maintainer model](docs/architecture/maintainer-model.md) for details on how multi-maintainer repositories work.
45 45
46eg self-hosted, github, codeberg, etc. 46eg self-hosted, github, codeberg, etc.
47 47
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 @@
1# Maintainer Model
2
3How ngit handles multi-maintainer repositories: coordinate discovery, maintainer sets, and the distinction between shared metadata and personal infrastructure.
4
5## Coordinate Discovery
6
7A **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).
8
9ngit discovers the coordinate locally from (in priority order):
10
111. `nostr://` git remotes
122. `nostr.repo` git config
133. `maintainers.yaml`
14
15No network access is required to find the coordinate. The coordinate may exist without a corresponding announcement event on relays.
16
17## Maintainer Set
18
19Each 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.
20
21Each maintainer independently decides who they list. Adding someone to your maintainers tag is an invitation to co-maintain.
22
23## Consuming vs Publishing
24
25The key architectural distinction is between **consuming** repository data (fetching, cloning, listing) and **publishing** it (`ngit init`).
26
27### Consuming: Union Across Maintainers
28
29When 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.
30
31### Publishing: Personal Infrastructure, Shared Metadata
32
33When publishing via `ngit init`, fields are sourced differently depending on their type:
34
35#### Shared Metadata
36
37Sourced from the **latest event** (by `created_at`) across the maintainer set:
38
39- `name`
40- `description`
41- `web`
42- `hashtags`
43
44Rationale: these are shared identity. If any maintainer updates the project name, all subsequent re-announcements should pick it up.
45
46#### Infrastructure (Personal)
47
48Each maintainer has their own infrastructure preferences. When publishing, infrastructure comes from **my own announcement only**, not the union:
49
50- **Grasp servers** -- where my git+nostr data is hosted. Each grasp server derives:
51 - Clone URL: `https://{server}/{npub}/{identifier}.git`
52 - Relay URL: `wss://{server}`
53 - Blossom URL: `https://{server}`
54- **Additional relays, git servers, blossoms** -- beyond what grasp servers provide
55
56Grasp-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.
57
58#### Maintainers
59
60Sourced from **my own announcement only**. Each maintainer independently decides who they list.
61
62If I don't have an existing announcement (first time co-maintaining), the default is `[me, trusted_maintainer]`.
63
64#### Earliest Unique Commit
65
66Cascade: my own event's value, then other maintainers' values, then the local root commit. A mismatch between maintainers may indicate a fork.
67
68#### Identifier
69
70From the existing coordinate. Cannot change without `--force` (changing it creates a new repository).
71
72## Init States
73
74When `ngit init` runs, there are 5 possible states based on what exists locally and on relays:
75
76| State | Condition | Behavior |
77|-------|-----------|----------|
78| **Fresh** | No coordinate found | Must provide name + server infrastructure |
79| **Coordinate Only** | Coordinate exists, no announcement on relays | Requires `--force` (could be a relay/network issue) |
80| **My Announcement** | Announcement exists, I'm the trusted maintainer | Re-publish/update, no force needed |
81| **Co-Maintainer** | Announcement exists, I'm listed as maintainer | Publish own announcement, no force needed |
82| **Not Listed** | Announcement exists, I'm not in maintainer set | Requires `--force` |
83
84See `src/bin/ngit/sub_commands/init.rs` (`InitState` enum) and `tests/ngit_init.rs` for the implementation and test coverage.