Files
rfc-app/DOCS.md
T
Ben Stull de28272914 Release 0.14.0: public /docs user guide (DOCS.md served at /docs)
Ships DOCS.md and the /docs route — a plain-prose translation of
SPEC.md for users, distinct from the binding spec. Originating need
was the admin-vs-owner role distinction on /admin/users (§6.1);
response is a single guide that covers the framework's user-facing
surfaces end-to-end (roles, proposing, branches, PRs, graduation,
notifications). Mirrors /philosophy: markdown file at repo root +
sibling backend loader + MarkdownPreview render. No schema migration.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 03:08:28 -07:00

24 KiB

Using the RFC app

This is the user-facing guide to the Wiggleverse RFC framework — how to read what's here, propose a new RFC, contribute to one that already exists, and understand who is allowed to do what.

This guide describes the framework. Individual deployments brand and configure themselves independently — the name in the header and the corpus the RFCs are about belong to the deployment, not to this document.

For the why of the framework, read the philosophy. For the binding technical contract, see SPEC.md in the repository.


Reading without signing in

You can read the catalog and every public RFC without an account. Anonymous visitors can:

  • Browse the catalog of super-drafts and active RFCs.
  • Open any RFC and read its canonical body.
  • Read any public branch — its diff and its chat thread.
  • Read any pull request — its diff, its conversation, its review comments.
  • Read the discussion that has accumulated on an RFC's main view.

Reading is open by design. The framework's claim is that the argument behind a definition is the evidence that the definition was earned, and an argument that disappears behind a sign-in wall stops carrying that evidence.

What you cannot do without an account: chat, propose a new RFC, create a branch, open a PR, drop a flag, or post on a discussion thread. Every write affordance is replaced with a sign-in prompt.


Signing in

While the framework is in private beta, only invited email addresses can complete sign-in. If your email is on the allowlist, the "Sign in" button in the header completes the flow and lands you on the catalog with full read and write access. If your email is not on the allowlist, you'll be sent to a short "pending" page explaining the gate.

Once you have an account, you're a contributor by default — the role that grants every write affordance the app exposes, scoped by the per-RFC and per-branch rules described below.


Proposing a new RFC

A new RFC begins as a proposal. The "+ Propose new RFC" button at the bottom of the catalog opens a small modal that collects four things:

  • Title. The word, concept, or topic this RFC would define.
  • Slug. A kebab-cased identifier derived from the title. It is the entry's stable handle from this moment until it graduates; collisions with existing entries or open proposals are caught inline.
  • Pitch. One or two paragraphs answering why this RFC is needed. This becomes the body of the entry.
  • Tags. Optional. The AI suggests tags from the pitch; you can accept, dismiss, or type your own.

Submitting the modal does one concrete thing: it opens a pull request against the framework's meta repository, adding one new file under rfcs/. There is no other Git artifact and no other side-effect. You are returned to the pending-idea view for the new proposal.

A pending idea is publicly readable but not yet a super-draft. The catalog surfaces it in a "Pending ideas" disclosure at the bottom of the list. A conversation can accumulate on the pending-idea view before it is admitted — contributors can argue, in public, about whether the entry belongs in the catalog at all.

Three outcomes are possible:

  • Merge. An admin or owner merges the proposal PR. The entry becomes a super-draft and graduates from the "Pending ideas" section into the main catalog. Any conversation that accumulated on the pending-idea view migrates with it.
  • Decline. An admin or owner declines, attaching a written comment. You see the comment on your next visit, along with a one-click affordance to revise and re-propose.
  • Withdraw. You can withdraw your own proposal at any time. The entry will not appear in any default view; the conversation that accumulated stays attached to the closed PR as historical record.

You are automatically the first owner of any RFC you propose. The claim flow described under Roles & permissions is for other contributors to add themselves as owners later, not for the proposer.


What a super-draft is

A super-draft is an entry that has been admitted to the catalog but does not yet have its own dedicated repository. Most of the argument that shapes a definition happens here. The framework assumes — and the philosophy explicitly invites — that many super-drafts will not survive the argument, and that is fine. The entries that do survive earn their place in the catalog by being defensible in public.

Opening a super-draft from the catalog gives you the same surface an active RFC uses:

  • The canonical body in the centre, read-only by default.
  • A chat thread on the right where the public conversation lives.
  • A breadcrumb dropdown listing any in-flight edit branches and any open body-edit PRs against this entry.
  • A "Start Contributing" affordance that cuts a fresh edit branch and lands you in contribute mode.

Edits to a super-draft body propagate through pull requests against the meta repository — there is no dedicated RFC repository yet.


What an active RFC is

An active RFC is an entry that has been graduated. It has its own dedicated repository, an integer RFC-NNNN identifier, and a canonical body file (RFC.md) inside that repository. The catalog distinguishes super-drafts and active RFCs at a glance.

Opening an active RFC gives you:

  • main — the canonical body, always read-only. Changes to main arrive exclusively through pull requests.
  • A breadcrumb listing every open branch and pull request on this RFC.
  • A per-branch chat thread on the right. Each branch has its own conversation, including main itself.
  • A "Start Contributing" affordance: on main it cuts a new branch and lands you on it in contribute mode; on any other branch you already have push access to, it flips that branch into contribute mode.

Discussion vs contribution

The framework draws an explicit distinction between two surfaces that other tools tend to conflate:

  • Discussion is what the RFC is for. The chat thread on an RFC's main view is the place for "what about this part?" or "have we considered…?" questions that don't yet warrant proposing a specific edit. Posting on a discussion thread does not create any Git artifact; the conversation lives in the app database.
  • Contribution is how an RFC changes. Editing the canonical body requires opening a branch and, eventually, a pull request. The pull request is the place a specific proposed change is reviewed and merged.

Reading both surfaces is open to anonymous visitors. Posting on either requires a contributor account.


Working on a branch

Contribute mode flips one branch into edit-enabled. The centre column splits: a markdown source pane on the left, a live-rendered preview on the right. Fenced mermaid blocks render as diagrams in the preview.

Two kinds of edits accumulate on a branch:

  • AI-proposed changes. You ask the AI a question or request a revision in the branch's chat. When the AI proposes a concrete edit, that edit appears as a change card in a panel below the chat — not yet applied to the document. You can accept, decline, or edit before accepting. Accepting produces one commit on the branch with the original text, the proposed text, and the AI's reason recorded in the commit body.
  • Manual edits. Typing directly into the source pane buffers locally and flushes as a single commit on an idle window, a branch switch, or an explicit "Save now" button. Manual edits also appear as change cards in the same panel — same evidence shape, different author.

Every accepted change is one commit. The framework does not support squash-merges or fixup-style cleanups: the per-change commit granularity is the framework's evidence unit, and collapsing it would erase what was earned.

Discuss mode vs contribute mode

A branch defaults to discuss mode — read-only, with chat enabled. AI proposals still appear in chat, but they are buffered rather than applied; a single CTA invites you to flip the branch into contribute mode if you want to act on them. The toggle is an intent affordance, not a permission one. If you don't have push access to the branch, the toggle is disabled with a sign-in or request-access path.

main is special: contribute mode is never available there. The "Start Contributing" button on main always cuts a new branch.

Flags

Anywhere you can read, you can drop a flag. A flag is the lightweight "I'm pointing at this, it's a problem" gesture — a single short declarative statement anchored to a passage. Creating a flag requires a contributor account but does not require push access to the branch: any signed-in contributor who can read a passage can point at it and say it's wrong.

Flags don't block PR merges by design — making them a merge gate would re-create the failure mode where contributors hastily "resolve" threads to unblock a button. Flags are prominent on PR headers but non-blocking.

Branch visibility

A new branch is publicly readable by default. The branch creator can flip a branch to private, in which case only the creator, any explicit grantees, and the RFC's per-RFC owners and arbiters can read it. Owners and arbiters can flip it back.

Opening a PR makes the branch fully public. If your branch is currently private, the "Open PR" affordance asks you to confirm this before submitting. There is no concept of a private PR — the framework's evidence claim depends on the argument being readable.

Who can push to a branch

Every branch has one of three contribute modes:

  • just-me (default) — only the branch creator can push.
  • specific — only the branch creator and explicitly granted contributors can push.
  • any-contributor — any signed-in contributor can push.

The branch creator and the RFC's per-RFC owners and arbiters can change this setting at any time.

Branch hygiene

A branch with no associated PR auto-closes after 30 days of inactivity. A closed branch is deleted from the Git host 60 days later. Closed branches remain in the catalog under a "show closed" filter — closing is a state, not a censorship event. The chat attached to a closed or deleted branch is preserved as historical record.

Owners and arbiters can pin a branch to disable the auto-close timer if the work is paused but legitimately ongoing.


Opening and reviewing a pull request

A pull request is the deliberate "ready for review" gesture for work that has accumulated on a branch. The "Open PR" affordance is available on any branch with at least one commit ahead of main.

The PR creation modal collects two AI-drafted fields, both editable before submit:

  • Title. A one-line description of the change, in spec voice.
  • Description. Two to four sentences pulling from the branch chat, written for an arbiter.

There is no reviewer picker. The RFC's arbiters are the implicit reviewer set.

The PR review page

The review page shows the diff, the branch's compressed chat (messages that produced accepted changes are expanded, the rest is behind a "Show full conversation" toggle), and the review-comment surface inline below the chat.

Review comments are not a separate concept from chat — they live in the same thread, anchored to a range in the diff. The framework's claim is that the disagreement an arbiter raises about a proposed change is the same kind of thing as the disagreement that produced the proposed change in the first place, and the two should share a surface.

Each PR records a per-user seen-cursor. New diff hunks and new conversation messages since your last visit render with a subtle accent. The cursor advances on view; you do not have to mark anything as read.

Merging a PR

Per-RFC owners and arbiters can merge; app-wide admins and owners also retain this capability. The merge produces a no-fast-forward commit on main, preserving every per-acceptance commit as an individually reachable node in main's history.

Merge is hard-blocked only by Git-level conflicts with main. Open review threads, pending change-cards, unresolved chat threads, and open flags do not block merge by design.

Conflicts with main

A conflict surfaces on the PR page as a read-only banner. A "Start resolution branch" affordance cuts a fresh branch off main's current tip, replays the work into it (asking the AI to resolve unambiguous conflicts, surfacing the rest for you), and opens a new PR. The original PR auto-closes when the resolution PR merges.

Fixup commits on the existing branch are not supported. Per-change commit granularity is the framework's evidence unit; admitting "fix merge conflict with main" commits would dilute it.


Graduation: super-draft → active RFC

Graduation is the moment a super-draft becomes a canonical entry in the catalog. It is initiated by an app-wide admin, an app-wide owner, or one of the RFC's per-RFC owners or arbiters from the super-draft's page.

Two preconditions block the action:

  • The super-draft must have at least one owner. The proposer is automatically the first owner; if they have stepped away, any contributor can use the "Claim ownership" affordance to add themselves.
  • No open body-edit PRs against the super-draft's entry. An open body-edit PR would attempt to re-introduce a body to a frontmatter-only entry after graduation runs. Merge or withdraw them first.

When the dialog confirms, the framework runs a transactional sequence: create a fresh Git repository for the RFC, seed it with the super-draft's body as RFC.md, update the meta-repo entry to state: active with the integer ID and the new repository's URL, auto-merge that update. If any step fails partway, the sequence rolls back — the half-created repository is deleted and the unmerged update is abandoned. The dialog shows each step in flight and tells you exactly what happened.

The chat thread on the super-draft moves to the new repository's main chat at graduation. Edit-branch chats from the super-draft phase stay attached to their original branches on the meta repo and surface from the new RFC view under a "Pre-graduation history" section.

Graduation is not reversible. The path forward from an active RFC is withdrawal, not back to super-draft.


Withdrawing and reopening

An active RFC or a super-draft can be withdrawn by the proposer (for a super-draft they proposed) or by an admin or owner. A withdrawn entry stays in the catalog as a historical record but is hidden from default views. The entry is filterable back in.

An admin or owner can reopen a withdrawn entry back into the super-draft state. The history is preserved across the transition.


AI in the chat

The chat on every RFC, super-draft, branch, and PR has an AI participant by default. The framework treats the AI as one voice among many in a public argument — not an oracle, and not a co-author whose name lands on commits.

You invoke the AI by writing into the chat composer and submitting. Each message can pick a model from the picker (the option list is configurable per RFC). The AI responds in the chat; when its response includes a concrete change to the document, that change appears as a card you can accept, decline, or edit.

When you accept an AI's proposed change, the commit's On-behalf-of: trailer names you, not the AI. The AI's authorship survives only as evidence — the original proposal in the commit body and the message that produced it in the chat record. The framework is explicit about this: AI participation produces evidence; it does not produce authorship.

Two configuration knobs scope AI participation per RFC:

  • Which models are available. The meta-repo entry's frontmatter carries an optional models: list. Absent means the RFC inherits whatever models the deployment is provisioned to run. An empty list (models: []) opts the RFC out of AI entirely — every AI surface is absent rather than disabled-but-present.
  • Whose credentials pay. By default the deployment operator's API credentials cover AI calls on every RFC. A funder: frontmatter field can name a single contributor whose registered credentials pay for AI calls on this RFC instead. The named contributor must explicitly consent from their settings page; either side can revoke at any time.

Per-RFC AI configuration is edited through the meta-repo PR flow that governs the rest of the entry's frontmatter — by the RFC's per-RFC owners and arbiters, or by app-wide admins or owners.


Notifications

The framework's public-async work model produces signals that shouldn't all reach you the same way. Five surfaces compose:

  • In-app inbox. The durable triage surface. One mental space across every RFC you have any relationship to, with per-RFC and per-category filters. Reachable from the inbox icon in the header.
  • Badges. Ambient pull-ins. A single integer beside the inbox icon (count of unread notifications). A small binary dot on individual catalog rows for watched RFCs with unseen activity. No per-row counts and no per-section counts.
  • Toasts. Transient mid-session signals. Used only for your own actions completing, and for events arriving on the view you're currently looking at.
  • Email. The single channel that escapes the app. Opt-in per category, conservative defaults. One-click unsubscribe per category.
  • Digest. Aggregation for activity on watched RFCs you haven't triaged through any other channel.

Watch states

Every RFC has one of three implicit relationship states for you:

  • Watching. You receive structural signals for the RFC.
  • Following. You receive only churn-grade signals (new commits, new chat messages on threads you didn't participate in). This is a lighter relationship than watching.
  • Muted. You receive no signals for the RFC. The mute is per-RFC and self-imposed; it does not affect what others see or what reaches you on other RFCs.

Watch states transition automatically based on your participation, with explicit overrides available from each RFC's header and from the notification settings page.

Email categories

Four categories with distinct defaults:

  • Personal-direct events — default on. Signals where you are the named subject. The contract is that when your name is on the action, the framework reaches out of band.
  • Watched-RFC structural events — default off. PR opened on a watched RFC, PR merged, graduation, withdrawal. Inbox and badges carry these by default; the email toggle is opt-in.
  • Watched-RFC churn — permanently off, by design. Per-commit and per-message email is intentionally not offered. The digest aggregates this activity weekly.
  • Admin-actionable events — default on for admins and owners, unused for contributors.

Quiet hours

You can set a daily window during which email notifications are held. Messages held during the window are released at window end — bundled into a single "Activity while you were away" email if a threshold accumulated, otherwise sent individually.


Roles & permissions

Authorization in this framework is owned by the app itself, not by the Git host. The Git host sees only a single bot account — every commit, every PR, every merge passes through it on a user's behalf — and the app decides which users are authorized to ask the bot to do which things.

The four app-wide roles

Each role is a strict superset of the one below it.

  1. Anonymous. Anyone who has not signed in. Can read public RFCs, public branches, and public PRs; cannot chat, propose, create branches, or open PRs.

  2. Contributor. The default role for any authenticated account. Adds everything anonymous can do, plus: propose new RFCs, create branches on any RFC repository, open PRs from branches they have push access to, post on chat anywhere they can read, claim ownership of unclaimed super-drafts.

  3. Admin. Adds the ability to act on any RFC, anywhere in the framework. Concretely: merge any PR on any RFC, graduate any super-draft, set branch visibility on anyone's behalf, withdraw or reopen any entry, write-mute or restore any contributor, grant or revoke the admin role.

  4. Owner. Adds two capabilities admin does not have: grant or revoke the owner role itself, and disable an account entirely. The framework names a single "owner zero" at bootstrap.

The practical difference between admin and owner is narrow but load-bearing: admin is the operational tier — it does the day-to- day moderation and stewardship work; owner is the tier that controls the admin tier. Disabling an account and creating other owners are owner-only because they affect the framework's chain of authority itself.

The app refuses to let the last owner demote themselves silently — losing the last owner would leave nobody able to grant the role back. Role changes are recorded in an append-only permission_events log; an admin's own admin/users page shows the log of who promoted, demoted, or muted whom.

Per-RFC delegated authority

The four roles above are framework-wide. Within an individual RFC, the meta-repo entry's frontmatter names two additional groups:

  • owners: — contributors elevated for this RFC. They can grant push access on any branch in the RFC, merge any PR on the RFC, change branch visibility, and withdraw the RFC.
  • arbiters: — contributors with merge authority for this RFC. Functionally similar to per-RFC owners for merge decisions; the distinction matters in some configuration paths.

Per-RFC owners and arbiters are not app-wide admins. Their elevated powers are scoped strictly to the RFC named in the frontmatter. This is what lets the framework distribute work without putting one person on the hook for every action.

The proposer of an RFC is automatically the first per-RFC owner. Additional per-RFC owners are added through a "Claim ownership" PR against the meta repository; app-wide admins or owners merge it.

Per-branch contribute grants

Within an RFC, the branch creator and the RFC's per-RFC owners and arbiters can grant push access to specific contributors on a specific branch — specific contribute mode, described under "Working on a branch."

The write-mute

An app-wide admin or owner can mute a contributor. A muted account retains read access and keeps its existing branches, but cannot create new branches, open new PRs, propose new RFCs, or post chat. This is a moderation tool, distinct from removing the account; restoring is the reverse gesture.

The write-mute applies only to contributors. Promoting a user to admin or owner is the way to remove a user's write-restriction in the structural sense; the write-mute is for retaining an account while removing its ability to act.

Every mute and every restore is recorded in permission_events.

Three different "mutes"

The word "mute" appears in three structurally distinct places. They share a word and nothing else.

  • Write-mute. Admin-imposed. Removes a contributor's ability to post or push. Described above.
  • Per-RFC notification mute. Self-imposed. Sets your watch state on a specific RFC to muted — you stop receiving signals for that RFC, in inbox, badges, and email. Does not affect what others see.
  • Per-user notification mute. Self-imposed. Suppresses notifications produced by a specific other user, anywhere in the framework. Notification-volume only — it does not affect what you can read.

A write-muted contributor continues to receive notifications normally, so they can triage what they can't act on, and so a restore lands cleanly.

Audit trail

Every gesture that changes app state — role changes, mutes, graduations, withdrawals, grant changes — is recorded in append-only logs the app maintains. Git commit history is for code archaeology; the app's audit log is the accountability record. An admin's page surfaces both permission_events (the role/mute log) and actions (the state-transition log) for review.


Where to learn more

  • The framework's why lives in the philosophy document.
  • The binding technical contract — section numbers (§n.n) referenced throughout this guide — is in SPEC.md in the framework's source repository.
  • Deployment operators have their own recipe in docs/DEPLOYMENTS.md.