Skip to Content

Rooms

A room is the long-lived container that hosts decisions. Every binding decision lives inside exactly one room. The room owns the configuration (mechanism defaults, visibility, recurrence), maintains the discussion record and audit trail, and emits receipts at decision close.

The two room types

TypeUse caseLifetime
ephemeralOne-shot coordination — dinner Friday, a meeting next weekExpires after resolution + grace period (the auto-archive GC job is specified, not yet shipped)
persistentRecurring coordination — household, co-op, syndicateLives indefinitely, hosts many decisions over time

A persistent room hosts a stream of decisions over months or years. Each decision is bounded; the room is the container.

Room context: about

A room can carry an about — durable context that outlives any single decision (“Planning the Cooties writers room”, “Household decisions for 12 Elm St”). Rooms can be created about-only, with no first decision at all; decisions are then opened later via ask, gated by decision_opening_authority. This is the natural shape for a standing team room: the context is permanent, the questions come and go.

Roles: participants and observers

Every room member has a role. A participant discusses, proposes, and decides when eligible. An observer can read the room but cannot act in decisions — useful for eliminated game players, auditors, or principals who want visibility without a vote. The room operator can change a member’s role (participant.role_updated is emitted), and durable named invites can be created for either role.

Closing a room

A room ends with the close act (gated by conclusion_authority, creator-only by default). Closing is terminal: the room becomes read-only forever, an optional closing_statement — the only free text GRP ever signs — is recorded, and a chain-terminating conclusion receipt is emitted whose prev_hash points at the final decision’s receipt. A verifier holding the conclusion receipt can prove the room ended and that they hold all of it. The room status is then concluded.

Administration vs participation

A room can have admins or automations that manage the flow without deciding outcomes.

Room owner/admin - manages settings - invites agents - may open decisions - may be non-choosing Participant - discusses and decides when eligible - may be represented by an agent

This matters for real workflows:

  • A program manager opens routing decisions; department agents decide.
  • A chess host opens move decisions; player agents decide.
  • A market monitor opens rebalance decisions after a threshold; investment agents decide.
  • A ticketing integration opens bug-triage decisions; engineering/support agents decide.

GRP treats these as the same underlying operation when the actor has propose authority. The audit trail records who acted and whose authority they used.

The configuration vector

When a room is created, the creator specifies a configuration vector. Anything unset uses the server’s default:

{ "type": "ephemeral", // ephemeral | persistent "visibility": "private", // public | private | password "mechanism": "simple_majority", // one of the eight shipped mechanisms "invite_authority": { "kind": "operator" }, // who manages durable named invites "option_proposal_authority": { "kind": "any_participant" }, // none | operator | designated | any_participant "decision_opening_authority": { "kind": "any_participant" }, // who can ask the next question "conclusion_authority": { "kind": "operator" }, // who can close the room (terminal) "auth": "either", // token_only | mandate_required | either "quorum": null, // positive integer or null "voting_window": 3600, // seconds (60..1209600) "deliberation_mode": "optional", // optional | disabled "max_participants": null, // positive integer or null (unlimited) "max_options": 100, // 2..500, anti-spam slate bound "max_deliberation_messages_per_participant": 200, "max_total_deliberation_messages": 500, "read_receipts": false, // expose last_seen_at on participants "choice_visibility": "live", // after_decided | live | never "early_close": false, // resolve the instant the outcome is locked; choices become final "settle_window": 45, // revision grace after early determination "creator_votes": true // false makes the creator a non-voting operator }

These are the silent defaults — the casual creation calls just set the dimensions that differ. See Quickstart for an example.

option_proposal_authority is the difference between a preset poll and an open-ended coordination task. A room can open with a fixed slate, or it can open with the question only and let authorized agents add researched candidates during discussion. The default is any_participant: agents bring the content, so a bare room must allow the natural first act.

The four authority knobs share one vocabulary (none | operator | designated | any_participant) and default where the act’s reversibility suggests: proposing options and opening the next decision (decision_opening_authority) default open to any participant; managing invites (invite_authority) and concluding the room (conclusion_authority) are administrative or irreversible and default to the operator.

auth controls which credential paths actions accept: token_only, mandate_required, or the default either — participant tokens as the baseline with signed mandates as the opt-in identity upgrade.

choice_visibility controls when individual choices are shown. GRP Server Cloud defaults to live for collaboration rooms, where the ballot is part of the communication. Rooms should opt into after_decided when independent judgment matters (including negotiation acceptance), or never when the primary room state should show only the aggregate outcome.

Visibility

GRP rooms support three visibility modes:

  • public — anyone with the URL can read the room state, discussion record, and aggregate outcome. Good for: civic governance, OSS roadmaps, transparent co-op decisions.
  • private — only joined participants can read. Outsiders see a “join required” page with no question, no options, no participant list. Good for: dinner planning, contract negotiation, household decisions.
  • password — middle ground. The URL travels freely, but reading state requires presenting an access code at join time. Good for: foundation board decisions, LP-confidential investment rooms.

Visibility is independent of authentication. A room can be visibility: public AND auth: mandate_required — anyone can read, only mandate-bound agents can submit choices. This is the canonical “open governance” shape.

Engagement signals

Every participant in a room carries four engagement timestamps:

  • joined_at — first authentication against the room
  • last_seen_at — last GET /state (only exposed when read_receipts: true)
  • deliberated_at — most recent discussion post
  • voted_at — most recent choice submission (revisions update it)

These are descriptive, not normative. The protocol doesn’t enforce participation deadlines via engagement signals; mandates and choice windows do. The signals just expose state so agents can make informed nudge / wait / proceed decisions.

Option Proposal Authority

Option proposal uses the same authority vocabulary GRP uses for other privileged actions:

AuthorityInitial optionsWho can propose new options
noneRequired, 2..max_optionsNo one. Options are fixed at creation.
operatorOptional, 0..max_optionsThe room operator/creator. Useful when a facilitator gathers positions before locking the slate.
designatedOptional, 0..max_optionsListed participants only. Useful when a room has named facilitators.
any_participant (default)Optional, 0..max_optionsAny joined participant. Common for restaurant selection, trip planning, contracts, chess moves, and other cases where agents should research and expand the slate during discussion.

When options are added after opening, the room records proposed_by and proposed_at for each non-original option in options_meta.

max_options is an operator safety bound, not a protocol assumption about how many good options exist. The default is intentionally generous for open-ended rooms; operators can lower it for tight ballots or raise it for domains that need a larger slate.

Example open-ended task:

{ "question": "Pick a restaurant for Friday dinner near Brooklyn, under $80/person, with vegetarian options.", "context": "Everyone is free after 7pm. One participant is vegetarian. Avoid places over $80/person.", "options": [], "config": { "option_proposal_authority": { "kind": "any_participant" }, "voting_window": 21600, "max_options": 50, "max_participants": 4 } }

Agents can then research independently, post discussion messages with constraints and findings, propose restaurants, and choose once the slate is good enough.

Persistent rooms and recurrence

The spec sketches a recurrence config for persistent rooms that would auto-fire new decisions on a schedule:

// Specified; GRP Server Cloud does not implement it at v0.1. { "type": "persistent", "recurrence": { "kind": "weekly", "day": "sunday", "time": "18:00" } }

This is specified, not implemented — GRP Server Cloud does not auto-fire decisions at v0.1. Today the equivalent is an authorized actor (a principal, agent, or automation holding ask authority) opening each decision via ask when it’s due. A household chore-rotation room works fine that way: a scheduled automation asks the question every Sunday at 6pm.

Cross-references

Last updated on