Maintainer authority in ngit v3
ngit v3, ngit-grasp v3, and GitWorkshop v4 introduce several maintainer improvements and one narrow breaking change (the SemVer reason for their major-version bumps). Explicit leads, role history, and moderators make repositories easier for maintainers and users to work with. Read Maintainers for the everyday model and commands.
If your repository already used multiple maintainers before v3, no action is required. It can continue using its existing maintainer setup. To adopt the new model and establish an explicit lead now, agree which existing maintainer will lead, then run these commands in order:
bash
# The chosen lead runs this first.
ngit repo edit --lead-maintainer <own-npub>
# Every other maintainer then runs this.
ngit repo follow-leadThe rest of this page explains the motivation and details for readers who are interested. The breaking change affects only the period before an invited maintainer accepts. When v3 was introduced, only a small minority of repositories had an invitation still pending, and we contacted the maintainers of every affected repository directly.
The breaking change
The SemVer reason for both v3 releases is one deliberate change to maintainer authority: listing somebody as a maintainer no longer makes their Git state authoritative before they accept the invitation. The rule applies only during that temporary interval; confirmed maintainer relationships are unaffected:
| Point in the invitation | Before v3 | v3 |
|---|---|---|
| Before somebody is invited | No authority | No authority |
| Listed, but not yet accepted | Their state could be treated as authoritative | Invitation only; their state is not authoritative |
| After they accept | Their state is authoritative | Their state is authoritative |
Only the middle row differs. Before the invitation and, in the ordinary case, after acceptance, both models authorize the same people.
What could go wrong before v3
Each maintainer publishes a repository address resembling <npub>/<repository>. A personal fork commonly keeps the original repository name but has a different maintainer address. ngit combines addresses that belong to one project into a working view. Protocol documentation calls that combined view a virtual repository.
Before v3, merely inviting a maintainer who already had such a fork could make the fork's state authoritative in the inviting repository before they agreed to join. Their next ordinary push to their fork could replace the refs users saw for the inviting repository. A later push by an existing maintainer could switch them back again.
No one had to run git push --force. The invitee merely pushed to their fork as usual. The refs changed because pre-v3 software treated state from an unaccepted invitation as authoritative for the inviting repository.
Stale invitations also damaged the collaboration view. Because an unaccepted invitee could be treated as part of the virtual repository, users opening the repository through that invitee's coordinate could see an incomplete view if their announcement omitted existing maintainers. Issues and pull requests associated with those missing coordinates would be absent. The need for one coordinate to follow is explained in Repository coordinates now follow the lead.
How v3 fixes it
In v3, being listed is only an invitation. The invitee's repository address does not join the inviting repository for state authorization until the invitee publishes their acceptance.
Acceptance is explicit. The invitee runs ngit repo accept; pushing state or running another maintainer command does not accept the invitation as a side effect.
Acceptance makes the relationship mutual. It is the invitee's signed decision to join that repository, so their existing relationships and Git state can be checked as part of the change. An unrelated repository can no longer absorb their state merely by naming them.
After acceptance, the new maintainer has the same state authority as the other maintainers. v3 does not turn co-maintainers into a weaker role, and a lead maintainer does not gain stronger Git authority.
Why ngit, ngit-grasp, and GitWorkshop move together
This coordination is specific to three projects maintained in tandem. Other NIP-34 clients and services can implement the same event rules and choose their own release boundaries.
A major version warns that old and new software can interpret the same data differently. During a pending invitation, software from before v3 may accept state that v3 correctly excludes.
That decision is shared by the command-line client and the repository service. ngit decides which signed state users see and publish. ngit-grasp receives that state, synchronizes the corresponding Git data, and serves repository refs. They need to agree about whose state is authoritative, so both projects mark the change with the same major-version boundary.
GitWorkshop v4 uses the same model when it builds a repository view and decides which state and maintainer actions to trust. GitWorkshop has its own release history, so its aligned release is v4 rather than v3; the compatibility boundary is the same.
The short duration of the disagreement does not make it harmless. Branch and tag authority is the repository's source of truth, so even a temporary difference deserves an explicit compatibility break.
The much-needed, backward-compatible improvements
The broader maintainer work addresses three long-standing needs. Existing repositories, confirmed maintainer relationships, and signed data remain valid when these features are adopted.
Repository coordinates now follow the lead
When maintainers first entered NIP-34, every maintainer was represented in the same way. There was no way to say that one of them was the lead. In practice, nearly every multi-maintainer repository has a clear lead. Other maintainers would often update the roster too, but would defer to the lead if asked. The announcements could not express that distinction.
That missing distinction made ordinary repository discovery confusing. A repository with four maintainers could appear as four search results: the same identifier under four different npubs. Tooling could combine those entries into one result, but that result still needed a link. Which maintainer's coordinate should that link use, and therefore which coordinate should users follow?
The choice could also change what users saw. Somebody invited later might already have a repository announcement that did not list every existing maintainer. Issues attached to the missing maintainers' coordinates could then be absent when the repository was opened through the invitee's coordinate. What people understood as one repository fractured into overlapping, incomplete views.
This was also part of the reason for the invitation boundary described above. In v3, being listed is only an invitation. Until the invitee accepts, they have no authority and their coordinate is not part of the virtual repository. An unconfirmed, partial announcement therefore cannot create another repository view.
Without a protocol field for that relationship, ngit's unsatisfactory answer was to manufacture lead behaviour from the existing listings with a voting-like rule. Each maintainer listing another maintainer counted as a vote, and a unique highest count selected the lead whose coordinate became the link target. Tooling could then present one search result and forward every maintainer's coordinate to the winner.
This sort of worked when a larger roster produced one clear winner, but roster listings were not stable ballots. Non-leads also updated the roster while still deferring to the practical lead, so an ordinary roster change could affect the inferred result. The ordinary two-maintainer case could not choose a lead at all: Alice listing Bob and Bob listing Alice gave them one vote each.
Removal was equally unintuitive. If several maintainers listed the same new maintainer, removing that person from one maintainer's announcement did not remove them from the virtual repository. Every maintainer who had listed them had to publish another announcement without them. People expected the clear lead to make one roster decision, not to coordinate the deletion of several independent copies.
An explicit lead gives a multi-maintainer repository one recommended address and a clear person to coordinate roster changes. The implemented lead flow matches that expectation: the lead publishes the coordinated change and tooling guides the other maintainers to follow it.
For backward compatibility, every maintainer still has the protocol-level authority to invite another maintainer. Lead-aware tooling should prevent non-leads from exercising that authority during the normal lead flow and route roster changes through the lead. This is a tooling restriction, not a weaker maintainer role. Every maintainer's repository coordinate can forward to the chosen lead, and the lead still has the same Git authority as every co-maintainer.
Role history keeps past decisions intact
Following one lead coordinate makes the repository view consistent across its maintainers. Before role history, clients still checked past actions against the current roster. That made the repository view change over time because clients knew who was a maintainer now, but not who was authorized when an action happened.
When a maintainer closed an issue or pull request and later left the repository, their signed closure lost its authorization. Clients stopped trusting the status event, so the issue or pull request appeared open again even though nobody reopened it.
Role history solves this by recording when maintainers and moderators join, leave, or change roles. A past action remains authorized when its signer held the required role, while leaving ends their permission to act now. The repository keeps its valid history instead of rewriting the view whenever its roster changes.
Moderators let repositories scale
Larger repositories need people who can triage issues and proposals without receiving authority over every branch and tag. Moderators can manage that collaboration work and record a merge already present in maintainer-published Git state. They cannot publish repository state or create and push the merge themselves.
This gives projects room to grow their moderation team without turning every trusted contributor into a maintainer with full Git authority.
Backward compatibility has limits
Aside from the pending-invitation breaking change described above, existing clients continue to identify the correct set of maintainers whose Git state is authoritative in every healthy path. New announcements retain a simpler maintainer list for older clients, and legacy repositories can continue using their inferred lead until they deliberately adopt the explicit roles.
It does not mean old and new clients interpret every possible announcement in the same way. An older client cannot see explicit lead routing, role history, or moderator authority. It may ignore moderator actions or lose the historical reason that an event from a former maintainer was authorized.
There be dragons in implementing lead-maintainer transitions. A client that handles a lead-maintainer transition in the wrong order, points to a missing lead, or creates conflicting or cyclic lead relationships can leave the repository with an unhealthy maintainer setup. Any client can produce these states if it has a bug or does not follow the transition rules, even though ngit's normal workflow avoids them.
ngit, ngit-grasp, and GitWorkshop fail closed when they encounter an unhealthy maintainer setup. They do not guess which signer should have authority, and role-dependent operations remain unavailable until a maintainer publishes a valid replacement announcement. This does not delete repository announcements, Git objects, issues, pull requests, or history.
Run ngit repo to see the specific problem and guidance for repairing the announcement. Builders of clients that implement this maintainer model should read How the NIP-34 maintainer protocol works. The exhaustive Maintainer protocol for AI implementers is particularly important when a client creates or changes repository announcements.
The pending invitation remains the SemVer reason for v3 because it changes Git-state authority during an ordinary supported workflow.
Conclusion
Making a coordinated breaking change is painful. Here, the narrow pending-invitation break comes with a clearer, safer maintainer model: repositories can present one recommended address and an explicit lead, accepted roles carry deliberate authority, past decisions remain valid, and moderators can share collaboration work without receiving Git-state authority. Those improvements make the compatibility cost worthwhile for the ecosystem over the long term.