NIPs by PolleramaCommunity NIPs, surfaced by trustConnect
npub180psnwj48pe...

Constitutional Lineage for NIP-29 Groups

Published Aug 14, 2026
kind 39100 · Constitutionkind 9908 · Fork Declaration

draft optional addressable

This document defines two event kinds allowing a NIP-29 group to publish a constitution and to declare, checkably, what a fork of that constitution changed and which of its inherited decisions still carry force.

It is additive. A relay or client that does not implement it remains fully NIP-29 conformant, and nothing here modifies NIP-29 or asks a relay to enforce anything.

Motivation

NIP-29 describes more than one way a group can end up on a different relay, and they are not the same operation.

A group can be migrated, "as long as that new relay agrees to receive the old group and to continue enforcing the same rules and acknowledging the same admins". Or it can be forked: "a dissident faction within a group can take the group's history to a different relay that agrees to change the rules of that group and assign admin powers to a different set of users."

Forking is deliberate and endorsed:

Forks are not bugs. It's a feature of this NIP that the same id can simultaneously identify different communities with different governance, hosted by different relays, each with their own kind:39000 metadata event, their own kind:39001 admin list and their own message history.

The specification then concedes what it cannot do about the consequence. Where a kind:10009 entry for a group points to a different relay hint than the one a client was using, that client "SHOULD notify the user that the group may have moved or been forked".

May have. The agreement that distinguishes the two is made out of band and nothing in the events records it, so from outside a migration that preserved the rules and a fork that rewrote them are indistinguishable. A member asked to follow their community to a new relay cannot tell whether they are following their community or joining a different one wearing its id. A member ratifying a fork by reading it cannot tell whether the rules changed. A moderator citing a two-year-old decision cannot tell whether it is still evidence about anything.

This proposes the missing declaration layer, and nothing else.

Kinds

kindnamecategory
39100Constitutionaddressable
9908Fork Declarationregular

Both were checked against the NIPs README and against nostr-protocol/registry-of-kinds (schema.yaml, 257 entries) on 13 August 2026 and were unassigned in both.

The constitution (kind:39100)

An addressable event whose content is a JSON document with a dual layer: each clause carries both the prose members ratify and, optionally, a machine-readable rule. A clause with no rule block is non-justiciable by construction rather than by declaration.

This event is not relay-signed. NIP-29's 39000-39003 carry the group id in a d tag and "MUST be created by the relay master key only". 39100 also uses a d tag and sits in the same band, and the resemblance stops there: it is signed by whoever the community's constitution names, and a relay holds no special authority over it. Were it relay-signed the relay would own the constitution, which is the arrangement this document exists to replace.

{
  "kind": 39100,
  "tags": [
    ["d", "<group-id>"],
    ["h", "<nip29-group-id>"],
    ["prev", "39100:<pubkey>:<group-id>"],
    ["forked-from", "39100:<parent-pubkey>:<parent-group-id>"],
    ["version", "3"]
  ],
  "content": "{ \"clauses\": [ { \"id\": \"c1\", \"text\": \"...\", \"rule\": { ... } } ] }"
}

The dual layer is the point. A clause whose prose changed and whose rule did not has altered what members understand and not what is enforced. A clause whose rule changed and whose prose did not has altered what is enforced and not what members understand, and a member ratifying by reading would see nothing. That is the edit this whole scheme exists to make visible, and a client presenting a fork for ratification SHOULD render rule-only changes most prominently, not least.

Identity is the lineage, not the identifier

Neither the group id, nor the relay, nor the signing key identifies a community. Identity is the position in the lineage graph. Three relations follow, and a client MUST be able to distinguish them:

relationtestauthorisation
replicathe same eventnone; nothing happened
continuationprev names the predecessorREQUIRED, per the predecessor's own amendment rule
forkforked-from names a parentnone, by design

A document naming neither edge is unrelated, which is a statement about two documents rather than a relation between them.

The asymmetry is deliberate. A continuation asserts that it is the constitution now in force, so an unauthorised one is a coup rather than a version; clients MUST NOT treat a new 39100 as canonical merely because it is the latest addressable event. A fork asserts only descent and needs nobody's permission, because the right to leave is what a minority holds instead of a veto. Requiring consent to fork would hand the majority an instrument against departure.

Key rotation follows without further machinery: a continuation signed by a different key is a rotation, so identity does not depend on any key remaining constant.

Fork declaration (kind:9908)

{
  "kind": 9908,
  "tags": [
    ["h", "<parent-group-id>"],
    ["forked-from", "39100:<parent-pubkey>:<parent-group-id>"],
    ["destination", "39100:<child-pubkey>:<child-group-id>"],
    ["clause_delta", "c1:prose", "c8:rule", "c10:removed"],
    ["procedure_delta", "panel composition", "nomination rule"],
    ["decay_epoch", "<timestamp>"]
  ],
  "content": "Reasons for the fork."
}

Every declaration is checkable against the documents. Any party holding both constitutions can recompute the deltas and compare them with what was claimed. A fork whose declared delta does not match is making a false statement about its own descent, and that is detectable by anybody. This is the property the scheme exists to provide; without the check, a declaration is decoration.

Precedent portability

Given the clause delta, four dispositions follow mechanically, requiring no judgement:

dispositionconditioneffect
portableclause identical in both layerstransfers whole, citable
persuasiveprose changed, rule unchangedoutcomes comparable, reasoning written against wording the fork no longer uses
voidthe executable rule changedreached under a different rule; not evidence about this one
orphanedclause deletednothing to cite it under

Procedure overrides all four. Where a fork alters panel composition, an assent threshold, a fallback seat count, an appeal structure or a sanction ladder, every inherited decision was reached under a different procedure. Such decisions remain accurate records of what was found; they are not evidence about how this fork's mechanism behaves, which is the only thing precedent is consulted for.

A fork therefore carries the record whole and its force only in part. This is not a limitation of the scheme, it is what the scheme is for.

Siblings are co-equal

A parent may have any number of children. None is the heir, no tag marks a preferred one, and the order in which a client receives them carries no meaning.

Every disposition a client reports for a set of siblings MUST be invariant under permutation of that set. This is testable, and implementations SHOULD test it: an implementation that sorts on input order has silently privileged a branch.

What this does not do

Stated plainly, because a specification that hides its limits wastes the reader's time.

  • It does not discover siblings. Finding every child of a parent means asking

relays which events name a coordinate as forked-from, which returns what those relays chose to serve. A client shown three of four forks reports correctly on the three and cannot know of the fourth. The permutation requirement is a guarantee about even-handedness, not about completeness.

  • It does not determine which constitution is in force. Under lineage that is

a question about which document a member ratified and which relay enforces it, and both lie outside the graph.

  • It specifies no adjudication. There is a larger design behind this

concerning how verdicts are reached; it is deliberately not proposed here, because it depends on problems nobody has solved on this substrate.

  • **Why not kind:34551 (Community Rules)?** Its registry entry declares a

content type of free, which cannot express the dual layer this scheme depends on. That is an inference from a schema rather than a reading of a specification: no defining document for 34551 could be found, and a correction from anyone who knows would be welcome.

  • It does not establish standing. Descent is self-asserted. Anyone may

publish a 9908 naming any parent, including in bad faith to attach themselves to a community they have nothing to do with. The check verifies that a declared delta matches the documents; it says nothing about whether the declarer had any right to fork. That follows from a fork needing nobody's permission and is a boundary rather than an oversight, but it is stated here so that it is not mistaken for one.

  • A declaration may not reach the parent. The 9908 above carries an h

tag naming the parent group. Where that group sets restricted, only members may write to it, so the fork most worth declaring, one made by people who have been removed, is the one least able to publish there. A declaration SHOULD therefore be published to the child group, MAY additionally be published to the parent where write access survives, and clients SHOULD discover forks through forked-from on the child rather than by reading the parent's timeline.

  • Relays that whitelist kinds will drop both events. Nothing here asks a

relay to enforce anything, but a relay accepting only known kinds will discard 39100 and 9908 silently. That is a deployment fact rather than a conflict with NIP-29.

Reference implementation

tools/genealogy.py in the Project Granny Bot corpus implements all of the above and runs against documents on disk with no relay, agent or network. It ships two worked forks of one parent: one declaring falsely on purpose, whose three false declarations are all reported, and one declaring truthfully, so that the sibling case shows one caught and one clean with neither ranked. 35 selftest probes, including the permutation invariant.

Corpus: https://solidarityworksinternational.org/projectgrannybot