From 17f302f4526a14998bb60eb3f199e55c87632815 Mon Sep 17 00:00:00 2001 From: Fizz Date: Thu, 3 Sep 2026 18:41:50 -0700 Subject: [PATCH] docs: focus room model on the future workspace Signed-off-by: Fizz --- AGENTS.md | 26 +---- VISION.md | 2 +- VISION_PROJECTS.md | 10 +- VISION_ROOMS.md | 230 +++++++++++++++------------------------------ 4 files changed, 87 insertions(+), 181 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index f016add22f..34e91b06d0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -26,28 +26,12 @@ 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: +channel navigation, read [VISION_ROOMS.md](VISION_ROOMS.md). -- 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. +A room has one conversation and can have several object views. Each object has +one canonical room; a task and its branch can share the **same room**. Do not +create a second conversation merely to add a view. Apply this model consistently +across desktop, web, mobile, CLI, and agents. --- diff --git a/VISION.md b/VISION.md index 860f38dfb0..c5686f9d42 100644 --- a/VISION.md +++ b/VISION.md @@ -152,7 +152,7 @@ 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. -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. +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. Time-bound projects can span durable repositories, each with its own ongoing room. See [VISION_ROOMS.md](VISION_ROOMS.md) for the shared model, nested relationships, and backend specification. 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. diff --git a/VISION_PROJECTS.md b/VISION_PROJECTS.md index 3f4453a912..35fadec0e0 100644 --- a/VISION_PROJECTS.md +++ b/VISION_PROJECTS.md @@ -12,9 +12,9 @@ This document is the software-forge slice of the broader Buzz platform. [VISION. 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. +type. Several facets may share one conversation. Projects organize time-bound +outcomes across repositories; repository rooms support ongoing code and +maintenance discussion. 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. @@ -194,7 +194,7 @@ Every step traced. Every trace a signed event. Change the project CI once and ev 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. +Threaded comments use NIP-22 kind:1111. Labels, assignees, and milestones are nostr tags. Design discussions and RFCs use the forum's long-form async surface. NIP-34 clients can discover and interact with issues. Buzz's forum gives them a home with threading, search, and agent triage. @@ -241,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 (target)** | 1111 (NIP-22) | — | Portable threading; transition from current kind:1 comments remains to be designed | +| **Comments** | 1111 (NIP-22) | — | Threaded replies everywhere | | **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 index b061755460..ff267b3013 100644 --- a/VISION_ROOMS.md +++ b/VISION_ROOMS.md @@ -1,183 +1,105 @@ # 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 +each have 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. +One object has one conversation home. 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. 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. +Object state stays in its own representation: a task has status and assignees, +a repository has refs, and a document has content. The room brings these views +and their conversation together. -### Identity Is Not a Label +## Projects and Repositories -Resolve objects and rooms by stable identity, scoped to the active community: +Projects organize a time-bound outcome. Repositories are durable homes for code +and ongoing conversation. A project can span several repositories, and a +repository can support many projects over time or concurrently. Their rooms have +different purposes and do not normally share a one-to-one relationship. -| 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: +For example, a **Simplify sign-in** project spans the identity service and mobile +app repositories: ```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] +Project room: Simplify sign-in +├── Task room: Improve account recovery +│ ├── Room S: Fix recovery tokens [subtask + identity-service branch] +│ └── Room M: Add recovery screen [subtask + mobile-app branch] +└── Design room: Recovery experience [document] + +Repository room: identity-service [ongoing code and maintenance discussion] +└── Branch view: fix-recovery-tokens → room S + +Repository room: mobile-app [ongoing code and maintenance discussion] +└── Branch view: recovery-screen → room M ``` -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. +The subtask and branch in S open the same room; likewise for M. The repository +branch listings link to those rooms rather than creating new conversations. +Completing the sign-in project does not end either repository's ongoing work. -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. +## Nested Rooms and Relationships -### Three Separate Decisions +Rooms nest to organize work: a project contains task rooms, a task contains +subtask rooms, and a document can have its own room or be a view of an existing +room. A channel canvas is the document view within a room. -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 room has at most one containment parent. The navigation tree is not the entire +relationship model: a task's room can sit under its project while its branch +still belongs to a repository elsewhere. Project-to-repository links and +branch-to-repository links remain available independently of that tree. Multiple +routes to a room all lead to the same conversation. -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. +## Access -**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. +A room and its object views should feel like one workspace. Someone admitted to +that workspace should be able to read its conversation and the objects presented +as part of it, rather than encountering an arbitrary inaccessible subset. The +same principle applies when presenting nested rooms as a shared project workspace. +Reading the work and permission to push, merge, or administer it are distinct +capabilities. -## What Exists Today +The permissions design must make that experience consistent across linked rooms +and objects. For repositories, it must choose whether access is governed through +the canonical room relationship or through repository permissions coordinated +with the room. The model does not prescribe a separate, unrelated channel link +just for Git authorization. The choice of permission authority and inheritance +rules remains an explicit design decision; the required user experience is +coherent access, not disconnected permission islands. -This is the implementation baseline inspected at `2ac0aa1dd`, not a claim that -all of the target model has shipped: +## Backend Specification -| 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) | +Persist room relationships on the channel: -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. +- `parent_channel_id`: nullable channel UUID, in the same community, indexed for + child lookup. +- `object_bindings`: a list of typed object references stored as JSONB. A room + can bind several objects, including a task and its branch. -## Smallest Proposed Backend Extension +Bindings reference the object they represent: an issue ID for a task, an +addressable project or repository coordinate, or a repository coordinate plus +full Git ref for a branch. Object records retain their own state; the bindings +connect them to their conversation home. -Keep the channel UUID, conversation, membership, and object event models. Extend -persisted channel metadata with: +Expose these fields through signed channel create (`9007`), edit (`9002`), and +metadata discovery (`39000`) events. No feature-specific HTTP endpoint is needed. +Edits can set or clear the parent and replace the binding list. Omitted fields +remain unchanged; parent clearing and an empty binding list are explicit actions. +Persist a metadata edit atomically and return the same relationships on discovery. -- 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. +The relay validates management authority, bounded binding shapes, and an existing +same-community parent. It rejects self-parenting and cycles, including concurrent +moves that would create a cycle. -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. +All clients use the same relationships to resolve an object's canonical room. +Creating another view reuses that room. Repeated creation requests must converge +on the same room rather than create parallel conversations. Conflicting bindings +must be reconciled consistently across clients, not resolved by local discovery +order. The metadata storage does not require a global unique-binding constraint.