upleb.uk

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

summaryrefslogtreecommitdiff
path: root/docs/architecture
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2026-02-10 12:52:32 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2026-02-10 13:03:40 +0000
commitaae452697d152694a8f163219f707356e84b420b (patch)
tree0f7e5fcaa5a005aeec7ae2d9f35b2c473ef8f785 /docs/architecture
parent3383477386916e82a19fa1e9c4d95b232ba0a40e (diff)
docs: update documentation for non-interactive mode
Add maintainer-model architecture documentation. Update README to reflect non-interactive default behavior.
Diffstat (limited to 'docs/architecture')
-rw-r--r--docs/architecture/maintainer-model.md84
1 files changed, 84 insertions, 0 deletions
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.