docs: focus room model on the future workspace

Signed-off-by: Fizz <b46ef72d2feab665ebb73edf75cce1628e3e6368697f7081c51cf547d4b77a44@buzz.block.builderlab.xyz>
This commit is contained in:
Fizz
2026-09-03 18:41:50 -07:00
parent 7c0c43ce3d
commit 17f302f452
4 changed files with 87 additions and 181 deletions

View File

@@ -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.
---

View File

@@ -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.

View File

@@ -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 |

View File

@@ -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:<owner-pubkey-hex>:<project-id>` |
| Repository | Address `30617:<owner-pubkey-hex>:<repo-id>` |
| 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.