You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Buzz teams live in channels. A channel holds the whole life of a project — the
strategy discussion, the design argument, the agent that drafts the
implementation, the review that reshapes it. Channels can be private, and teams
rely on that: what is said in the channel stays with the channel's members.
The code does not. Today, the moment anyone on the team — human or agent —
pushes that work to a Buzz-hosted repository, it becomes readable by every
authenticated user on the relay. The privacy model holds for the conversation
and silently breaks at its most valuable artifact.
As a team collaborating in a private channel, I want the repositories our
work produces to be exactly as private as the channel itself, so that inviting
someone into the team is the only access decision I ever have to make.
Concrete situations this serves:
A small team on a shared relay builds something unannounced. They cannot
self-host a relay just to keep one repository quiet, and they should not have
to: the channel already defines who is on the team.
An agent-heavy workflow where managed agents turn private channel
discussions into commits. Without private repositories, an agent pushing code
is an unintentional publishing act — the conversation was private, the diff is
not.
A relay operator hosting several groups (a community server, a
consultancy, a company with multiple teams). Each group's channel isolates
their discussion; their repositories need the same tenant boundary or the
groups can read each other's source.
Offboarding. When someone leaves the team, removing them from the channel
should be the whole procedure. Membership-based access means their repository
access ends on their next request — no separate ACL to remember, no stale
deploy keys.
Not confirming a project exists. An outsider probing clone URLs learns
nothing: a repository they cannot access answers exactly like a repository
that was never created.
The design consequence: channel membership is the access list. Buzz already
has a first-class notion of "the team" — the channel — with invitation,
removal, and roles. Private repositories reuse it rather than introducing a
second permissions registry that can drift out of sync with the team it is
supposed to describe.
Problem
Buzz-hosted Git repositories are currently readable by any authenticated relay
member. A repository can carry a buzz-channel binding for push authorization,
but that binding does not restrict discovery, browsing, clone, or fetch.
This prevents teams from safely hosting repositories that should only be
available to a specific channel. Protecting pushes alone is not sufficient: a
non-member who knows the clone URL can still read the repository.
Requested behavior
Add explicit private visibility to NIP-34 repository announcements:
A repository owner can mark a repository private and bind it to one Buzz
channel.
The repository owner, the verified owner of a managed-agent repository, and
current members of the bound channel can discover and use the private
repository.
Other authenticated users cannot discover it through repository announcements
or state events, search, listing, counts, live subscriptions, or the HTTP
bridge.
Apply the same access check to every Smart HTTP Git surface: info/refs, git-upload-pack, and git-receive-pack.
Return the same generic 404 repository not found response for a denied
private repository and a repository that does not exist.
Resolve repository visibility and channel membership at request time so
membership removal takes effect on the next request.
Keep channel roles and branch protection responsible for write authorization
after the repository-level access gate succeeds.
Expose private visibility and channel selection in Desktop and the buzz repos
CLI.
Preserve existing behavior for repositories that do not explicitly opt into
private visibility, including repositories that already use buzz-channel
only as a push binding.
Acceptance criteria
A repository can opt into private visibility with one channel UUID.
Creating or updating a private repository rejects missing, malformed,
duplicate, or unsupported visibility/channel metadata.
A private repository announcement is rejected if its owner is not a
current member of the selected channel.
The repository owner, a verified managed-agent owner, and current channel
members can discover, browse, clone, fetch, and—subject to existing write
policy—push to the private repository.
A non-member cannot discover the private kind 30617 announcement or
associated kind 30618 repository state through WebSocket queries, HTTP
queries, search, counts, pagination, or live subscriptions.
A non-member receives a generic 404 repository not found from info/refs, git-upload-pack, and git-receive-pack, even when using
the exact repository URL.
Removing a channel member revokes discovery and Git access on that
member's next request.
Repository counts remain exact after access filtering; overly broad
discovery counts are rejected rather than truncated.
Public and legacy repositories retain their existing read behavior unless
explicitly marked private.
Changing a repository back to public preserves any existing buzz-channel
push binding.
Desktop supports selecting private visibility and a channel during
creation, and owners can change visibility from project details.
The CLI supports private creation and visibility edits with clear
validation and relay rejection errors.
Automated tests cover visibility parsing, live membership revocation,
discovery and counts, live fan-out, pagination, legacy compatibility, and
all Smart HTTP endpoints.
Why: the user story
Buzz teams live in channels. A channel holds the whole life of a project — the
strategy discussion, the design argument, the agent that drafts the
implementation, the review that reshapes it. Channels can be private, and teams
rely on that: what is said in the channel stays with the channel's members.
The code does not. Today, the moment anyone on the team — human or agent —
pushes that work to a Buzz-hosted repository, it becomes readable by every
authenticated user on the relay. The privacy model holds for the conversation
and silently breaks at its most valuable artifact.
As a team collaborating in a private channel, I want the repositories our
work produces to be exactly as private as the channel itself, so that inviting
someone into the team is the only access decision I ever have to make.
Concrete situations this serves:
self-host a relay just to keep one repository quiet, and they should not have
to: the channel already defines who is on the team.
discussions into commits. Without private repositories, an agent pushing code
is an unintentional publishing act — the conversation was private, the diff is
not.
consultancy, a company with multiple teams). Each group's channel isolates
their discussion; their repositories need the same tenant boundary or the
groups can read each other's source.
should be the whole procedure. Membership-based access means their repository
access ends on their next request — no separate ACL to remember, no stale
deploy keys.
nothing: a repository they cannot access answers exactly like a repository
that was never created.
The design consequence: channel membership is the access list. Buzz already
has a first-class notion of "the team" — the channel — with invitation,
removal, and roles. Private repositories reuse it rather than introducing a
second permissions registry that can drift out of sync with the team it is
supposed to describe.
Problem
Buzz-hosted Git repositories are currently readable by any authenticated relay
member. A repository can carry a
buzz-channelbinding for push authorization,but that binding does not restrict discovery, browsing, clone, or fetch.
This prevents teams from safely hosting repositories that should only be
available to a specific channel. Protecting pushes alone is not sufficient: a
non-member who knows the clone URL can still read the repository.
Requested behavior
Add explicit private visibility to NIP-34 repository announcements:
channel.
current members of the bound channel can discover and use the private
repository.
or state events, search, listing, counts, live subscriptions, or the HTTP
bridge.
info/refs,git-upload-pack, andgit-receive-pack.404 repository not foundresponse for a deniedprivate repository and a repository that does not exist.
membership removal takes effect on the next request.
after the repository-level access gate succeeds.
buzz reposCLI.
private visibility, including repositories that already use
buzz-channelonly as a push binding.
Acceptance criteria
duplicate, or unsupported visibility/channel metadata.
current member of the selected channel.
members can discover, browse, clone, fetch, and—subject to existing write
policy—push to the private repository.
30617announcement orassociated kind
30618repository state through WebSocket queries, HTTPqueries, search, counts, pagination, or live subscriptions.
404 repository not foundfrominfo/refs,git-upload-pack, andgit-receive-pack, even when usingthe exact repository URL.
member's next request.
discovery counts are rejected rather than truncated.
explicitly marked private.
buzz-channelpush binding.
creation, and owners can change visibility from project details.
validation and relay rejection errors.
discovery and counts, live fan-out, pagination, legacy compatibility, and
all Smart HTTP endpoints.