Skip to content

feat(agents): let hosted agents join teams, warning about instructions - #1870

Open
matt2e wants to merge 11 commits into
mainfrom
team-remote-agent-warning
Open

matt2e wants to merge 11 commits into
mainfrom
team-remote-agent-warning

Conversation

@matt2e

@matt2e matt2e commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Hosted (remote) agents can now be added to a team. While any are checked, the Instructions description changes to "Agents on your devices follow these after their own instructions." A warning with an icon names the hosted members: "Agents run by their provider (astra and kimi) will not get these team instructions." "Run by their provider" follows the app's existing wording for hosted agents, e.g. "Its provider keeps its key and runs it" in the create dialog. Without hosted members, the description stays "Every member follows these after its own instructions." Their provider runs them, so the desktop can't add the team section to their prompts.

Team editor with two provider-run agents checked, light theme

Team editor with one provider-run agent checked, dark theme

Narrow width, wrapped warning

Changes

  • Member picker (AgentsPage.tsx): lists the community's hosted agents only for a team that Save puts in the selected community: a synced team homed there, or a new team where the relay syncs teams. Agents on another device and ones with unfinished setup are never listed. Every other team gets only the agents here: a team stored on this device, a synced team seen outside its home, or a new team on a relay without config sync. Save would refuse hosted agents for any of those. Before this PR, every team listed only agents on this device.
    • Save gets only the members the editor accounts for: ones among its current choices, ones the team already has, and agents on this device in other communities. A hosted agent picked before another community was selected is left off, rather than submitted hidden and refused. It shows checked again if its community is selected again.
    • A new team's editor that is already open offers hosted agents as soon as the relay's team-sync check finishes, without needing to be reopened.
  • Team list (AgentsPage.tsx): a synced team always shows in its home community, even when none of its members is listed there. That happens, for example, when its last member was deleted but leaving the team's channel failed. Elsewhere it shows only where a member is listed, so a team whose members are all hosted (or all on another device) no longer shows up as an empty team in other communities. Like before, a synced team with no members shows everywhere.
  • Warning (TeamEditor): added to the Instructions field's description, with WarningCircleIcon (Tabler alert-circle; the repo allows only Tabler icons). It names the provider-run members with Intl.ListFormat, is part of the textarea's accessible description, and uses the text-warning role.
  • Service (service.ts): a new helper, teamAgents(origin), returns the agents a team in a community can have: the ones here plus the hosted ones whose setup finished. Agents on another device are left out, as they were on main; ones already on a team stay through the opened roster. Two places use it:
    • The synced Save check. Before, it rejected any member without a key on this device, failing with Add <agent> to <host> first.
    • The roster in each local member's prompt. Local teammates now see hosted teammates and can mention them. Until the community's agent records are read (after a restart or reconnect, or while reads fail), a synced team homed there lists each member not on this device by npub alone, because nothing yet tells hosted agents from ones on other devices. Once the records are read, hosted members get their names back and the others drop out, as before.
  • Agents.teamHere({ id, draft }) (service.ts): says whether Save puts a team, or a new team's draft, in the selected community. It shares a new private teamHome() with saveTeam, so the picker and the list follow the same home that Save picks.
  • AgentsSnapshot.syncsTeams (service.ts, optional): whether the selected community's config channels are up. It changes when they come up or go down, so subscribers rerender and ask teamHere again.

Not covered

  • Teams on relays without config sync can't have hosted members. Those teams are stored on this device, and the picker no longer offers hosted agents for them. Hosted agents live on Builderlab communities, which sync teams.

Testing

  • As of 70316c2: vitest run src/features/agents src/bundled/agents: 1131 passed (AgentsPage.test.tsx rerun after each wording change: 78 passed). tsc --noEmit and biome are clean.
  • The three review-fix commits (df826fd, eef19be, c5f984c) were pushed without running tests, tsc or biome, and with hooks skipped. CI is the first run for them.
  • New page test from the first review fixes: "shows a synced team only where its members are, after switching communities" (the team's open editor closes too). New service test: "refuses a new member on another device, and leaves it out of rosters".
  • The second round of review fixes (b093278, b064f9c) was also pushed without running tests, tsc or biome, and with hooks skipped. Neither commit has been verified locally; CI is the first run for them. They add these tests:
    • Page, "offers hosted agents only to a team Save puts in this community". It replaces "offers hosted agents only to new and synced teams". Sky is listed only for the team teamHere places here. It is not listed for a local team, a synced team homed elsewhere, or a new team where teamHere is false.
    • Page, "keeps a synced team in its home while none of its members is listed". The team still shows, opens, and can be deleted.
    • Service, "keeps a new team, hosted agents and all, off a relay without config channels". teamHere is false, and Save refuses the hosted member with "A member is not an agent on this device".
    • Service, "puts a synced team in the selected community only while it is home". teamHere is true in the home community and false for a local team and once another community is selected. "puts set-up hosted agents on a team…" now also checks that teamHere is true for a new team on a syncing relay.
  • The third round of review fixes (6a89505, 6dc4b6b, a77658c) was also pushed without running tests, tsc or biome, and with hooks skipped. None of these commits has been verified locally; CI is the first run for them. They add these tests:
    • Page, "leaves a hosted agent picked in another community off a new team, keeping the rest". Ada and Sky are picked in a new team, then another community is selected. Sky is hidden, and Create submits only Ada, who is counted as "+1 in your other communities". A synced team's hosted member that isn't listed in the new community is still submitted on Save.
    • Page, "offers an open new team hosted agents once its community is known to sync teams". The open draft shows Sky after syncsTeams changes, and keeps its name and picks.
    • Service, "tells subscribers when a new team made here starts to sync". The config check is held after a hosted agent is listed. Releasing it notifies subscribers, sets syncsTeams, and makes teamHere({ draft }) true.
    • Service, "names a hosted teammate by npub while the community's agent list is unread". A synced team has a local member and a hosted one. The community is reconnected and its agent-record read is held, then rejected. Both while held and after the rejection, the local member's roster lists the hosted teammate by npub.
  • New service test: saves a synced team with a hosted member, refuses a hosted agent whose setup didn't finish, and checks the roster names the hosted teammate. It fails on main with Add npub…wcq to relay.example.test first.
  • New page test: hosted agents are offered and unfinished or other-device ones aren't. The description and warning switch as one or two hosted members are checked, and go back once they're unchecked.
  • Screenshots come from the agent-library browser fixture in headless Chromium, with george local and astra and kimi hosted, at 900px and 380px.
  • Not yet done: a run in the desktop app against a real Builderlab hosted agent.

🤖 Generated with Claude Code

matt2e and others added 3 commits October 29, 2026 11:54
Hosted agents can be picked as team members. While one is on the team,
the Instructions field warns that remote agents may not get them. Local
members' rosters now name the community's listed teammates too, so they
can reach hosted ones.

Co-authored-by: Jitter <2b2e6415e748c35180847a37aadae06a11e30dddc76b784e7fd9354c4eb42e7a@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
Co-authored-by: Jitter <2b2e6415e748c35180847a37aadae06a11e30dddc76b784e7fd9354c4eb42e7a@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
With a provider-run member, the description names the agents on the
owner's devices as the ones that follow the instructions, and the
warning names the provider-run ones that won't get them.

Co-authored-by: Jitter <2b2e6415e748c35180847a37aadae06a11e30dddc76b784e7fd9354c4eb42e7a@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
@matt2e
matt2e marked this pull request as ready for review October 29, 2026 01:37
@matt2e
matt2e requested a review from a team as a code owner October 29, 2026 01:37

@kalvinnchau kalvinnchau left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Found a cross-community team display defect and an unprotected eligibility change.

Comment thread src/bundled/agents/AgentsPage.tsx
Comment thread src/features/agents/service.ts Outdated
Comment thread src/bundled/agents/AgentsPage.tsx
@matt2e
matt2e marked this pull request as draft October 29, 2026 05:38
matt2e and others added 3 commits October 29, 2026 16:53
A synced team's roster is its home config channel's members, so every
member is in its home. The Teams list now shows such a team in another
community only while it has no members, rather than whenever none of
its members runs on this device. A team of hosted agents, or of agents
on another device, no longer shows up empty in other communities.

Co-authored-by: Jitter <2b2e6415e748c35180847a37aadae06a11e30dddc76b784e7fd9354c4eb42e7a@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
Only a synced team can have hosted members: Save keeps a team stored on
this device local, and that branch refuses any member that isn't an
agent here. Editing such a team now offers only the agents here, as it
did before hosted agents could join teams. New and synced teams still
offer hosted agents.

Co-authored-by: Jitter <2b2e6415e748c35180847a37aadae06a11e30dddc76b784e7fd9354c4eb42e7a@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
A team's agents in a community were every listed agent whose setup
finished, which took in agents on the owner's other devices as well as
hosted ones. Save then accepted a new member running on another device,
and rosters named those agents, though the member picker never offered
them. Now only hosted listings join the agents here: Save again refuses
a new member on another device with "Add <agent> to <community> first",
and rosters leave such agents out. Members a team already has still
stay, as its opened roster proves them.

Co-authored-by: Jitter <2b2e6415e748c35180847a37aadae06a11e30dddc76b784e7fd9354c4eb42e7a@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
@matt2e
matt2e marked this pull request as ready for review October 29, 2026 06:02

@kalvinnchau kalvinnchau left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Two remaining problems: synced teams can become inaccessible when all members are unlisted, and the picker still offers hosted selections that cannot be saved.

Comment thread src/bundled/agents/AgentsPage.tsx
Comment thread src/bundled/agents/AgentsPage.tsx Outdated

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Star Lord’s automated source review via Wes’s account, with independent Rocket, Mantis and Groot coverage. Two changes suggested inline: preserve hosted teammates during listing hydration (P2), and avoid offering hosted members that the team cannot accept from another community (P3).

Reviewed head c5f984ce411a39b27ea1d94fa454e071b240ab56, base ae5359daa9ac92b43da2d88ea38e1f7daa2544e8. Source and three attached screenshots inspected; no tests, app execution, live focus checks or CI verification. The latest commits and native hosted-agent flow remain unvalidated by this review.

Comment thread src/features/agents/service.ts
Comment thread src/bundled/agents/AgentsPage.tsx Outdated
matt2e and others added 2 commits October 29, 2026 19:05
The member picker offered hosted agents to a new team in a community
whose relay doesn't sync teams, and to a synced team seen outside its
home. Save kept the new team on this device and refused them with "A
member is not an agent on this device", and checked the synced team
against its home, refusing them with "Add <agent> to <home> first".

The service now says whether Save puts a team, or a new team's draft,
in the selected community, from the same home Save picks. The editor
offers hosted agents only then, which also covers a team stored on
this device and replaces the editor's own check for one.

Co-authored-by: Jitter <2b2e6415e748c35180847a37aadae06a11e30dddc76b784e7fd9354c4eb42e7a@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
A synced team showed only where one of its members was listed. One
whose members were all unlisted, as when its last member was deleted
but leaving the team's channel failed, vanished from every community,
its home included, so it couldn't be opened, edited or deleted though
its config channel remained.

The Teams list now always shows a synced team in its home, asking the
service where Save puts it. Elsewhere it still shows only with a member
listed there, or while it has no members.

Co-authored-by: Jitter <2b2e6415e748c35180847a37aadae06a11e30dddc76b784e7fd9354c4eb42e7a@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Star Lord’s automated source review via Wes’s account, with independent Rocket, Mantis and Groot coverage.

The existing P2 hosted-roster hydration finding remains unresolved. The home-community visibility and hosted-picker destination fixes address the prior findings; one new low-priority picker-refresh issue is inline.

Reviewed head b064f9c944873998b38cad23ba94cd9538a18b17, base ae5359daa9ac92b43da2d88ea38e1f7daa2544e8, including the follow-up from c5f984ce. Source-only: no tests or app execution; live focus/recovery remains unverified. The available check snapshot showed successful Semgrep, zizmor and DCO checks, without functional test results.

Comment thread src/bundled/agents/AgentsPage.tsx

@kalvinnchau kalvinnchau left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 One additional picker-state issue remains.

Comment thread src/bundled/agents/AgentsPage.tsx
matt2e and others added 3 commits October 29, 2026 20:50
A new team's editor stays open when the selected community changes, and
its choices become that community's agents. A hosted agent picked before
the switch was hidden, so it couldn't be unchecked, and left out of the
warning and the away count, but Create still submitted it and Save
refused it with "Add <agent> to <community> first".

Save now gets only the members the editor accounts for: ones among its
choices, ones the team already has, and agents on this device in other
communities. A hosted agent picked elsewhere is left off, and shows
checked again if its community is selected again.

Co-authored-by: Jitter <2b2e6415e748c35180847a37aadae06a11e30dddc76b784e7fd9354c4eb42e7a@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
When a community's config channels came up after its agents were
listed, nothing in the snapshot changed, so subscribers weren't told. A
new team's editor already open kept hiding the hosted agents, which
Save would now accept, until something else made the page render.

The snapshot now has `syncsTeams`, whether the selected community's
config channels are up. What `teamHere` says of a new team changes with
it, so the open editor asks again and offers them.

Co-authored-by: Jitter <2b2e6415e748c35180847a37aadae06a11e30dddc76b784e7fd9354c4eb42e7a@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
A community's agent records are read in the background after each
restart or reconnect, and a failed read leaves them unread until a
later one succeeds. Until then a turn could start from the persisted
team, and its roster dropped every hosted teammate, name and npub, as
nothing yet said they were hosted.

While the community's records are unread, a synced team homed there now
names each member not on this device by npub alone, since a hosted one
can't yet be told from one on another device. Once they are read, hosted
members get their names again and the others leave, as before.

Co-authored-by: Jitter <2b2e6415e748c35180847a37aadae06a11e30dddc76b784e7fd9354c4eb42e7a@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants