From 7c0c43ce3d0a07d68a12a545357909ba658973d1 Mon Sep 17 00:00:00 2001 From: Fizz Date: Thu, 3 Sep 2026 18:26:38 -0700 Subject: [PATCH] docs: define the shared room and object model Signed-off-by: Fizz --- AGENTS.md | 26 +++++++ VISION.md | 4 +- VISION_PROJECTS.md | 24 ++++-- VISION_ROOMS.md | 183 ++++++++++++++++++++++++++++++++++++++++++++ VISION_SOVEREIGN.md | 10 ++- 5 files changed, 237 insertions(+), 10 deletions(-) create mode 100644 VISION_ROOMS.md diff --git a/AGENTS.md b/AGENTS.md index 9d1a6afd42..f016add22f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,6 +23,32 @@ against that direction. Scale validation to the change's risk and exercise the real workflow for user-visible or integration behavior when practical; green CI and runtime evidence answer different questions. +### Room and Object Model + +For changes involving projects, tasks, repositories, branches, documents, or +channel navigation, read [VISION_ROOMS.md](VISION_ROOMS.md) before designing the +client or protocol. Apply these rules across desktop, web, mobile, CLI, and agents: + +- A room is a stable channel UUID with one conversation and zero or more object + facets, not an exclusive task/branch/repo type. One object resolves to one + canonical room; several objects may share it. A task and branch can be the + **same room**. Do not create a second chat merely to add a view. +- Resolve by community-scoped object identity, never display names. Preserve + task nesting and branch-to-repository links even when navigation shows a tree. +- Containment, context inheritance, and access control are separate. Nesting or + linking must not grant membership, privatize global records, or change Git + ACLs. Repo `buzz-channel` is security-sensitive; project binding is not repo + authority. +- Do not invent per-client relationship encodings or conflict winners. Shared + metadata must round-trip through relay persistence/discovery and supported + writers; handle unsupported fields, conflicts, retries, and partial creation. +- Preserve one conversation and its history across views. Migrating issue/PR + comments needs an explicit compatibility plan, not silent duplicate streams. + A branch merge must not archive other active facets sharing its room. + +The vision's metadata extension is proposed, not a shipped API. These guardrails +constrain new work; they do not authorize an implicit data migration. + --- ## Ecosystem diff --git a/VISION.md b/VISION.md index 900e5a9475..860f38dfb0 100644 --- a/VISION.md +++ b/VISION.md @@ -152,7 +152,9 @@ Beyond chat: channels are workspaces. The relay hosts git repos. Smart HTTP β€” standard `git clone`, `git push`, nothing special. Your npub signs pushes. Same domain, same auth, same identity as everything else on the relay. -Branches are channels. Create a feature branch, Buzz creates a channel β€” CI results, review comments, and the merge decision all live there. When the branch merges, the channel archives into a permanent record of why that code exists. +The target is **one room, many views**. Projects, tasks, repositories, branches, and documents resolve to canonical conversation rooms; a task and its branch can share the same channel UUID. Rooms nest for navigation without changing permissions. See [VISION_ROOMS.md](VISION_ROOMS.md) for the cross-client conceptual contract and the boundary between existing behavior and proposed backend support. + +In that model, creating a feature branch creates or reuses its room β€” CI results, review comments, and the merge decision belong there. A completed branch-only room can archive into a permanent record; merging a branch must not archive other active work sharing the room. See [VISION_PROJECTS.md](VISION_PROJECTS.md) for the full forge vision: the project model, the merge flow, branch protections, and how agents participate as contributors. diff --git a/VISION_PROJECTS.md b/VISION_PROJECTS.md index 8601b87829..3f4453a912 100644 --- a/VISION_PROJECTS.md +++ b/VISION_PROJECTS.md @@ -1,6 +1,6 @@ # 🐝 Buzz Projects β€” A Nostr-Native Forge -> Someone pushes a fix. Buzz creates a channel for the branch. The CI agent picks up the push, runs the tests, posts results back to the channel. A co-maintainer reviews the diff inline, approves it β€” a signed event, cryptographic proof. Merge. The workflow runs the integration. The channel archives into a permanent record of why that code exists. +> Someone pushes a fix. Buzz creates or reuses the branch’s canonical room, which can already be the task’s room. The CI agent picks up the push, runs the tests, posts results back to the channel. A co-maintainer reviews the diff inline, approves it β€” a signed event, cryptographic proof. Merge. The workflow runs the integration. Once all work sharing the room is finished, it can archive into a permanent record of why that code exists. > > Bug report to merged patch. One place. One search index. One identity system. The branch channel was the pull request, the CI dashboard, and the discussion thread. @@ -10,6 +10,12 @@ This document is the software-forge slice of the broader Buzz platform. [VISION. ## The Project Model +The shared room contract is [VISION_ROOMS.md](VISION_ROOMS.md): a project, repo, +task, branch, or document is a facet of a canonical room, not an exclusive channel +type. Several facets may share one conversation. The room model and automatic +lifecycle described here are product direction, not a claim that provisioning, +comment migration, or inheritance already ships. + A project lives on the relay. `myproject.com` in a browser shows the project home. Click a repo and you're at `repoa.myproject.com` β€” README rendered, file tree navigable, code syntax-highlighted, clone URL at the top. The same URL serves HTML to a browser and git protocol to `git clone`. Content negotiation. One URL, two audiences. Git transport is standard Smart HTTP β€” `git clone`, `git push`, nothing special. Your npub signs pushes. Same domain, same auth, same identity as everything else on the relay. The host in the clone/push URL is also the community selector: the same `owner/repo` name may exist in two communities without sharing refs, branch protections, workflow runs, approvals, or repo announcements. @@ -78,7 +84,9 @@ The cost is stated plainly: a third-party NIP-34 client sees the member repos in A feature branch is a conversation. -When you create a branch, Buzz creates a channel. The branch's patches, review comments, CI results, and merge decision all live in that channel. When the branch merges, the channel archives. The conversation becomes the permanent record of why that code exists. +When you create a branch, Buzz should create or reuse its canonical room. If the branch implements a task in an existing room, task details and the branch diff can be views of that same channel UUID. The branch's patches, review comments, CI results, and merge decision belong to that conversation, not a parallel branch chat. Room nesting preserves the task/subtask structure; a separate branch-to-repository reference preserves code ownership. + +When a branch-only room's work finishes, it can archive as the permanent record of why that code exists. A merge must not automatically archive a shared room whose task or other facets are still active. The example below is the branch-only case. ``` #feat-auth-fix @@ -126,7 +134,7 @@ Push CI Review Merge β”‚ β”‚ β”‚ β”‚ Merge to main β”‚ β”‚ β”‚ β”‚ kind:1631 β”‚ β”‚ β”‚ β”‚ - β”‚ β”‚ β”‚ β”‚ Channel archives + β”‚ β”‚ β”‚ β”‚ Branch-only room archives ``` The approval event is signed by the maintainer's npub. The merge status references the approval. The audit log chains them together. Cryptographic proof of who approved what. @@ -184,12 +192,18 @@ Every step traced. Every trace a signed event. Change the project CI once and ev ### Issues β†’ Forum + NIP-34 -Bug reports are NIP-34 kind:1621 events, rendered through Buzz's forum surface. Threaded comments use NIP-22 kind:1111. Labels, assignees, milestones are nostr tags. Design discussions and RFCs use the forum's long-form async surface. +Bug reports and tasks retain their NIP-34 kind:1621 identity. In the target model, task details, forum presentation, and branch work can open the same canonical room; subtasks can have nested rooms. A forum is a view, not a reason to fork the conversation. + +NIP-22 kind:1111 is the intended portable threaded-comment representation in this forge vision; current issue/PR clients use separate kind:1 comments. Unifying these with room chat requires the explicit read/write compatibility transition described in [VISION_ROOMS.md](VISION_ROOMS.md#rollout-boundaries). Labels, assignees, and milestones remain object metadata, not channel identity. NIP-34 clients can discover and interact with issues. Buzz's forum gives them a home with threading, search, and agent triage. ### Docs β†’ Canvases +A channel canvas is the initial document facet of a room. A document may share +its project's or task's room, or have a dedicated nested room; opening the +document should not create a parallel discussion stream. + Living documents, collaboratively editable by humans and agents via MCP tools. Not static HTML deployed to a CDN β€” documents that update when the code changes, because the doc writer agent watches ref updates and proposes edits. ### Releases β†’ Agent + Workflow @@ -227,7 +241,7 @@ Standard kinds as substrate. Custom kinds only where genuinely novel. | Layer | Standard NIP Kinds | Buzz Custom | Rationale | |-------|-------------------|---------------|-----------| | **Git state** | 30617, 30618, 1617, 1618, 1621, 1630-1633 (NIP-34) | β€” | Interop with ngit, gitworkshop.dev | -| **Comments** | 1111 (NIP-22) | β€” | Threaded replies everywhere | +| **Comments (target)** | 1111 (NIP-22) | β€” | Portable threading; transition from current kind:1 comments remains to be designed | | **Channels** | 9000-9022, 39000-39003 (NIP-29) | β€” | Project workspaces | | **HTTP auth** | 27235 (NIP-98) | β€” | Git push authentication | | **Agent identity** | 0 (NIP-01 profile) | β€” | Agents are npubs | diff --git a/VISION_ROOMS.md b/VISION_ROOMS.md new file mode 100644 index 0000000000..b061755460 --- /dev/null +++ b/VISION_ROOMS.md @@ -0,0 +1,183 @@ +# Buzz Rooms β€” One Conversation, Many Views + +**Status: product direction; not a shipped protocol.** This document defines the +shared conceptual contract for desktop, web, mobile, CLI, and agent integrations. +The backend shape below is a proposal to review before implementation, not an API +clients may assume exists. [VISION.md](VISION.md) covers the platform; +[VISION_PROJECTS.md](VISION_PROJECTS.md) covers its software-forge workflows. + +## The Model + +A **room is a channel**: one stable channel UUID and one working conversation. +Projects, tasks (including subtasks), repositories, branches, and living documents +each resolve to a canonical room. They are **facets** of that room, not mutually +exclusive room types. An ordinary conversation can have no object facets. + +One object has one canonical conversation home within its community. One room can +be home to several objects. A task and its implementation branch can therefore +be two views of **the same channel UUID**, not separate channels with synchronized +messages. Switching from task details to the diff changes the view, not the +conversation, membership, or history. Adding a facet does not create another chat. + +Object state stays in its own representation: a task still has status and +assignees, a repository still has refs, and a document still has content. The room +connects those representations; it does not turn every object into a chat message +or replace NIP-34 records with channel rows. + +### Identity Is Not a Label + +Resolve objects and rooms by stable identity, scoped to the active community: + +| Object | Identity to resolve, not a display-name heuristic | +|---|---| +| Room | Channel UUID | +| Project | Address `30621::` | +| Repository | Address `30617::` | +| Task / subtask | Issue event ID (`kind:1621` today) | +| Branch | Repository address **and full ref**, e.g. `refs/heads/fix-login` | +| Initial document view | The channel's canvas, identified by its channel UUID | + +A room rename does not change its identity. The same branch name in two repos is +two different objects. Newer repository/project metadata events replace state at +the same address; their event IDs are not new object identities. A branch rename +or deletion/recreation needs an explicit binding/lifecycle policy, not a guess +based on a matching label. Independently addressable documents beyond canvases +need their own agreed identity contract before implementation. + +## Nesting Without Losing Relationships + +Rooms can nest. A single parent gives navigation a tree (or a forest of root +rooms); the full object relationships remain a graph. For example: + +```text +Project room P [project + default repository] +β”œβ”€β”€ Task room T [task: Improve sign-in] +β”‚ └── Subtask room S [task: Fix login + branch: refs/heads/fix-login] +└── Design room D [document: sign-in design canvas] +``` + +The subtask and branch both open room S. S remains nested under T, while its branch +still belongs to the repository in P. A repository view may also link to S; that +is another route to the same room, not a second parent or another conversation. +A dedicated repository room is also valid; sharing the default repository with +the project home is not mandatory for every repository. + +Project membership still comes from the project's repository references +([NIP-MP](docs/nips/NIP-MP.md)); nesting rooms does not redefine it. A repository +can belong to several projects and still have one canonical room. Room nesting +also does not by itself define task dependencies or a claimable-work queue. +When several task facets share a room, room containment alone cannot identify +which task is another task's parent; that needs an explicit object relationship. + +### Three Separate Decisions + +1. **Containment/navigation:** where a room appears and how users find it. +2. **Context:** which parent guidance or related documents an agent should read. +3. **Access:** who may read, write, administer, or push. + +A parent link or object association does not grant access, copy membership, or +inherit permissions. Context inheritance is a separate, explicit, permission- +checked policy; a link is not permission to read everything behind it. Navigation +must not expose inaccessible parent/child metadata. An unreadable or unresolved +room does not justify inventing a replacement room or hiding an otherwise +readable object. + +**Existing repository bindings are security-sensitive:** `buzz-channel` on a +repository announcement participates in hosted Git access control. The same tag +on a project is navigation metadata, not authority over its repositories. New +room associations must neither overwrite the repo's ACL binding as a navigation +convenience nor become a second, competing source of Git permissions. Linking a +community-visible issue or project to a private room does not make it private. + +## What Exists Today + +This is the implementation baseline inspected at `2ac0aa1dd`, not a claim that +all of the target model has shipped: + +| Existing behavior | Source | +|---|---| +| Desktop project creation provisions a home channel and default repo sharing that home | [createProject.ts](desktop/src/features/projects/createProject.ts) | +| Projects and repos are signed addressable events; tasks are issue events, not dedicated task rows | [NIP-MP](docs/nips/NIP-MP.md), [SDK builders](crates/buzz-sdk/src/builders.rs), [events schema](migrations/0001_initial_schema.sql) | +| Channels have persisted rows; discovery metadata is reconstructed from supported fields | [channel store](crates/buzz-db/src/store/channel.rs), [side effects](crates/buzz-relay/src/handlers/side_effects.rs) | +| Hosted Git uses the repo's channel binding for access, and object storage for Git data | [binding.rs](crates/buzz-relay/src/api/git/binding.rs), [store.rs](crates/buzz-relay/src/api/git/store.rs) | +| Task creation does not provision a task room; issue/PR comments are separate `kind:1` records | [issueMutations.ts](desktop/src/features/projects/issueMutations.ts), [project hooks](desktop/src/features/projects/hooks.ts) | +| Project/issue/Git records remain community-scoped even when carrying an `h` provenance tag | [ingest.rs](crates/buzz-relay/src/handlers/ingest.rs), [CLI command guidance](crates/buzz-cli/src/commands/mod.rs) | + +The channel store does not yet provide general room hierarchy or multi-object +bindings. Branch ref state is not a branch-room registry. Threads, huddle parent +links, sidebar sections, and lists of related channels are not substitutes for +shared room containment. The agent harness's [current-room canvas context](crates/buzz-acp/src/queue.rs) +does not implement inherited parent context. + +## Smallest Proposed Backend Extension + +Keep the channel UUID, conversation, membership, and object event models. Extend +persisted channel metadata with: + +- An optional `parent_channel_id` in the same community, indexed for child lookup. +- An `object_bindings` list of typed stable references; JSONB is sufficient for an + initial representation. Several bindings may point into one room. + +Illustrative binding values are a task issue ID, a repository/project address, +or a repository address plus full branch ref. These are **conceptual field +names**, not finalized database columns, tag spellings, or SDK types. + +Use the existing signed channel create (`9007`), edit (`9002`), and discovery +metadata (`39000`) path. No feature-specific HTTP endpoint is needed. Proposed +edit semantics are explicit set/clear of the parent and replacement of the +binding list, with unrelated metadata preserved. The implementation must specify +omission, clearing, concurrent edits, and older-client round trips before rollout. +Arbitrary client-added tags do not persist merely because a create/edit event +accepts them: storage and discovery serialization must both support the fields. + +The relay must enforce channel-management authority, bounded/valid binding +shapes, an existing same-community parent, no self-parenting or cycles (including +concurrent moves), and atomic metadata updates. It must enforce access on +relationship discovery as well as writes. Cross-object authority needs an +explicit resolution rule: managing a room is not authority to hijack somebody +else's object's canonical home. Existing owner-signed project/repo bindings must +be reconciled, not silently overruled by room-side claims. + +A global unique-binding constraint is not required for the first metadata +increment. **Canonicality is still the product contract**, not permission for +each client to choose its own winner. Before enabling canonical-room creation, +define one shared resolution/reconciliation rule for conflicting claims and +idempotent retries. Surface unresolved conflicts instead of choosing whichever +room a client happened to discover first. Clients may create/reuse rooms on +object creation or discovery, but must recover from partial object/room creation +without silently provisioning duplicates. Metadata alone does not solve races. + +## Rollout Boundaries + +- **One conversation needs a transition.** Issue/PR comments currently have a + separate event stream; the forge vision also discusses NIP-22 comments. A + follow-up must define compatible reads, one authoritative write destination, + provenance, deduplication, and access behavior before claiming a unified room + conversation. Do not start dual-writing copies of messages or discard history. +- **Automation is separate.** Client-on-discovery provisioning can come first. + Creating a room for a Git push while every client is offline needs a persistent + hook/worker. Document which guarantee an implementation actually provides. +- **Lifecycle follows all facets.** A branch merge may archive a branch-only + room; it must not automatically archive an active task or project sharing that + room. Unlinking/deleting an object must not erase shared conversation history + or cascade-delete other facets. Shared-room archive policy needs explicit UX. +- **Private objects and inheritance are not included.** Private task records, + inherited access, inherited harness context, workflow inheritance, standalone + document objects, and richer relationship/dependency graphs need separate + designs. Do not infer them from the proposed metadata fields. + +## Implementation Review Checklist + +- Do desktop, web, mobile, CLI, and agents resolve the same object to the same + channel UUID, including retries, conflicts, and community switching? +- Can a task gain a branch view without replacing its identity or conversation? +- Do both task nesting and branch-to-repository relationships survive navigation? +- Are unsupported/unresolved bindings handled without guessed names, duplicate + rooms, unauthorized disclosure, or a second conversation stream? +- Are membership, object ownership, repository ACLs, and context policies unchanged + unless the change explicitly designs and tests a new authorization contract? +- Do persistence, edits, discovery, SDKs, and clients round-trip the same metadata? + +Related requests: [channel hierarchy #3667](https://github.com/block/buzz/issues/3667) +and [issue relationships #3728](https://github.com/block/buzz/issues/3728). This +vision establishes direction; it does not close either implementation request. diff --git a/VISION_SOVEREIGN.md b/VISION_SOVEREIGN.md index 77362b3f7e..c173c1591f 100644 --- a/VISION_SOVEREIGN.md +++ b/VISION_SOVEREIGN.md @@ -78,16 +78,18 @@ a response in seconds. The maintainer sees a pre-processed report, not a raw inb They read the triage summary, confirm it's real, assign it. Thirty seconds of their time instead of five minutes. -Someone picks up the bug. They create a branch. Buzz creates a channel: -`#feat-auth-fix`. They work there. They push commits. The CI agent picks up the -work β€” it's watching for pushes, it's just a member with compute β€” runs the tests, +Someone picks up the bug. They create a branch. Buzz creates or reuses its +canonical room: `#feat-auth-fix`. The task and branch can be views of the same +channel UUID, as defined in [VISION_ROOMS.md](VISION_ROOMS.md). They work there. +They push commits. The CI agent picks up the work β€” it's watching for pushes, it's just a member with compute β€” runs the tests, posts results back to the channel. Green. The patch lands in the channel as a reviewable diff. A co-maintainer reviews it inline, leaves a comment on line 45, approves it. The approval is a signed event β€” cryptographic proof of who said yes and when. Merge. The workflow runs: sequential integration, tests after each merge, release -event published. The channel archives. The conversation is now the permanent record +event published. A finished branch-only room archives; a shared room stays active +while its other work continues. The conversation is now the permanent record of why that code exists. Not a chat thread that scrolled away. Not a PR that might get deleted. The event log, on your relay, in your database. Someone reading that code in two years can pull up the channel and see exactly what was discussed, what