Skip to content

feat(agent-host): run a saved agent without the desktop app - #967

Open
loganj wants to merge 8 commits into
agent-host-statefrom
agent-host-standalone
Open

loganj wants to merge 8 commits into
agent-host-statefrom
agent-host-standalone

Conversation

@loganj

@loganj loganj commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

🤖

Summary

Why

Buzz agents are AI assistants, such as Claude or Codex, that a person sets up in the Buzz desktop app. They answer when someone mentions them in a channel, and they can also watch for events and run on a timer. Today an agent runs only while its owner's desktop app is open, because the code that runs agents lives inside the app.

The goal of this stack is a small command-line program that runs an agent with the app closed. It must use the same code and the same saved state as the app, so the agent behaves the same wherever it runs. The app keeps working exactly as it does today.

Stack

Review in order. Each PR keeps the app working.

  1. refactor(agents): separate the agent runner and its reads from the desktop app #961: move the code that decides when an agent runs into its own module, and let the Claude and Codex agent code read conversations without depending on the app.
  2. feat(agents): keep agent state in files that a program outside the app can read #974: keep agent state in files that a program outside the app can read.
  3. feat(agent-host): run a saved agent without the desktop app #967 (this PR): add buzz-agent-host, the program that runs an agent with the app closed.

How to try it

pnpm agent-host
node dist-agent-host/buzz-agent-host.mjs run <pubkey> [--config file.json]
  • The agent must already be saved by the app on this computer. The program reads its name, type and relay from the app's identities.json.
  • The agent's secret key comes from BUZZ_AGENT_KEY, or else from the app's Keychain item. macOS may ask once to allow this.
  • BUZZ_AGENTS_DIR uses a different agents folder, for example for testing.

Details

  • Connection: the program opens its own connection to the relay (the Buzz server) and signs in as the agent, not as the owner. It finds the agent's channels and reads conversations as the agent (src/agent-host/feed.ts, reads.ts).
  • Publishing: it signs only the event types the app allows for agents: messages, reactions, deletions and the other agent event types in app_agent.rs.
  • Locks: it takes hosts/<pubkey>.packaged and hosts/<pubkey>.lock in the same order as the app (Hosting::claim in app_agents.rs). Node has no flock call, but macOS open(2) takes the same flock(2) lock when given O_EXLOCK or O_SHLOCK, and Node passes those flags through. So the program holds each lock itself, with no helper process. Tests check it against a separate flock(2) holder, and it was also checked against Rust's File::try_lock in both directions. The operating system releases a lock when its holder exits, even after a crash. If the check fails, the program does not run the agent. Because of this, the program runs agents only on macOS.
  • Programs it starts: only the ones each agent type declares (claude, or codex app-server), with the same PATH the app uses.
  • Saved state: the program reads and writes the app's agents/state/ files (feat(agents): keep agent state in files that a program outside the app can read #974) through the same storage code the app uses (src/agent-host/storage.ts). It reads the agent's record again at each check, so a change the owner saves in the app takes effect without a restart. A session that one side starts, the other continues.
  • Name: buzz-agent-host, because the app already ships a different program called buzz-agent.

Same as the app

  • Team instructions come from the app's saved teams.
  • Mentions from relay workflows (fix(agents): accept verified relay workflow mentions #970) are accepted under the same rules. The program reads the community's workflow key from its NIP-11 information (self), as the app does, and checks the workflow creator's signed profile.
  • Watch classifiers: the app does not run them yet either (classifier() is "unavailable" in both), so classified watches behave the same.

Not in this program

  • The typing indicator and the activity view. Both are parts of the app's screen, and this program has no screen. Agents do not send them to other people.
  • The app reads the state files only when it starts (see feat(agents): keep agent state in files that a program outside the app can read #974). A change the program saves, such as timer progress, shows in the app after it restarts.
  • Deleted agents: before each claim and at each 5-second check, the program reads identities.json again. If the app deleted the agent, an erase removed it, or its type, owner, relay or sign-in changed, the program stops and exits. If sign-out keeps the agents, they keep running, because the app also restarts kept agents.

Known limits (from adversarial review; not fixed here)

  • Takeover moment: each check holds .packaged shared for a moment. If the installed app tries its lock at that moment, it still runs the agent and tries again later, so both can answer one event. A dev build of the app already checks the same way, so this PR keeps that behavior.
  • Handover inside one app session: the app keeps the copy of the state files it read at startup. If it takes back an agent that this program ran while the app was open (in practice, a dev build), its next save of that agent can write over this program's newer state. With the installed app this does not happen: the app holds the agent whenever it runs, so this program runs it only while the app is closed, and the app reads the files when it starts.
  • It runs Buzz's own copy of Claude or Codex (from feat(agents): run Buzz's own copies of Claude and Codex, kept on the latest release #949), which the desktop app downloads and keeps current. It does not download a copy itself. If the app has not downloaded one yet, a turn fails with "Claude is not installed" or "Codex is not installed".
  • Me chats (from Continue Me chats as one top-level conversation for native agents #1000): only the owner's own connection can read where the owner filed a Me chat. This program reads as the agent, so a mention in a Me chat gets a thread reply here, not a top-level reply. The app does the same when someone other than the owner is signed in.
  • Smaller items, for follow-up: writes from this program skip the fsync that the app's native writes do; roster events (kind 39002) are not checked for their signer; host.ts, feed.ts and spawn.ts have no unit tests yet.

@loganj
loganj force-pushed the agent-host-standalone branch from f0e5288 to 63721af Compare October 13, 2026 16:44
@loganj
loganj changed the base branch from agent-host-reads to agent-host-runner October 13, 2026 16:45
@loganj
loganj force-pushed the agent-host-standalone branch from 63721af to 827cf93 Compare October 13, 2026 17:06
@loganj
loganj changed the base branch from agent-host-runner to agent-host-state October 13, 2026 17:08
@loganj
loganj force-pushed the agent-host-standalone branch from 827cf93 to a848c82 Compare October 13, 2026 17:37
@loganj
loganj force-pushed the agent-host-standalone branch 3 times, most recently from 2469ead to ad53f6f Compare October 13, 2026 19:32
@loganj
loganj marked this pull request as ready for review October 13, 2026 19:48
@loganj
loganj requested a review from a team as a code owner October 13, 2026 19:48
@loganj
loganj force-pushed the agent-host-standalone branch from ad53f6f to fde4b45 Compare October 13, 2026 20:18
@loganj
loganj force-pushed the agent-host-standalone branch from fde4b45 to d03ce7f Compare October 13, 2026 20:44
@loganj
loganj force-pushed the agent-host-standalone branch from d03ce7f to a9a56dd Compare October 13, 2026 21:14
@loganj
loganj force-pushed the agent-host-standalone branch from a9a56dd to a474233 Compare October 13, 2026 21:17
@loganj
loganj force-pushed the agent-host-standalone branch from a474233 to eab5259 Compare October 13, 2026 21:30
@loganj
loganj force-pushed the agent-host-standalone branch 3 times, most recently from 176fb8d to d730f9c Compare October 13, 2026 23:03

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

No additional changes requested in this follow-up; source assessment: 9/10 for the reviewed integration. Range-diff against the previously reviewed f5935e9bf76c92dacb7aeff1ce668d3dde27b5c9 preserves all three recovery/process repair patches unchanged. The new local-config start and profile-search adapters match the current production callers; the catch-up comment accurately describes the host’s existing in-memory behavior. The standalone host still does not perform offline watch catch-up.

Reviewed head bcfb5bffd5056a0f66ba097b675e7788e8cee833 against base 747d8a3290234a0caa37c3577512ce4097081d61. Rocket checked process/lock/feed lifecycle, Mantis checked correctness/security/concurrency and runner/storage integration, and Groot checked product/CLI/error behavior. I independently reconciled the lanes and completed source self-review. This is a follow-up of the prior repairs and their rebase integration, not a new exhaustive review of unchanged code. Public description (no attached images), changed publication surface and five commit messages inspected; no additional publication finding.

Source-only: no PR code, tests, typechecks, builds, apps or live handover executed. One CI snapshot showed 30 successful checks and 2 skipped; that does not establish macOS locking/process behavior, live relay recovery, measured performance or human acceptance. COMMENT only; this is not merge approval.

@loganj
loganj force-pushed the agent-host-standalone branch from bcfb5bf to 0153e4b Compare October 16, 2026 17:31

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

No additional changes requested in this follow-up; source assessment: 9/10 for the reviewed rebase integration. All five PR patches are range-diff identical to the previously reviewed bcfb5bffd5056a0f66ba097b675e7788e8cee833. The eight inherited state/migration changes preserve the standalone host’s current callers: it uses the same per-agent record writer and does not invoke the new migration writers or persist catch-up checkpoints. The prior feed-recovery and process-cleanup repairs remain unchanged.

Head 0153e4bfef9f2e236f12adede6918abd8c0e0f85; base 496533da4c2e43ffe4769bbb2e45b1f637be09b5. This is a follow-up of the previous repairs and their integration with the updated base, not an exhaustive new audit of unchanged feature code. Public description (no image attachments), changed publication surface and all five commit messages inspected; no additional publication finding.

Rocket completed systems/process/storage lifecycle review; Mantis completed correctness/security/concurrency review; Groot completed product/CLI/error-path review. I independently reconciled their evidence and completed source self-review.

Source-only: no PR code, tests, typechecks, builds, apps or live handover executed; current CI was not assessed. macOS locking/process behavior, live relay recovery, measured performance and human acceptance remain unverified. COMMENT only; this is not merge approval.

@loganj
loganj force-pushed the agent-host-standalone branch from 0153e4b to 7136590 Compare October 16, 2026 19:19

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

No additional changes requested in this follow-up; source assessment: 9/10 for the reviewed integration. Range-diff against the previously reviewed 0153e4bfef9f2e236f12adede6918abd8c0e0f85 preserves four of five feature patches unchanged. The remaining patch adds the required RunnerHost.named no-op and matching test fixture. That matches the standalone host’s existing agent-only connection and meChat: false behavior: desktop naming requires the owner’s session and Me placement. Claude’s title-reading path is gated by that Me-chat result, so this host does not start extra title-reading processes. Prior feed recovery and process-cleanup repairs remain unchanged; the Codex/Claude defaults extraction preserves the updated base’s callers.

Head 713659098f23c690dbbaeaae2a1b10e312309b9d; base 100d6534a5c32350f343bca674e0c0f1b7a96d63. This is a follow-up of the previous repairs and their rebase integration, not an exhaustive new audit of unchanged feature code. Public description (no attached images), changed publication surface and all five commit messages inspected; no additional publication finding.

Rocket completed systems/performance/lifecycle coverage, Mantis completed correctness/security/concurrency coverage, and Groot completed product/accessibility/source-visible flow coverage. I independently reconciled their evidence and completed source self-review.

Source-only: no PR code, tests, typechecks, builds, apps or live handover executed; current CI was not assessed. macOS locking/process behavior, live relay recovery, interactive focus/error-retry behavior, measured performance and human acceptance remain unverified. COMMENT only; this is not merge approval.

@loganj
loganj force-pushed the agent-host-standalone branch from 7136590 to 2262e74 Compare October 16, 2026 20:04

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

No introduced finding in this PR’s host-adapter follow-up. One P2 remains in the inherited desktop persistence repair from base #974, detailed below. Source assessment: 9/10 for the host-adapter delta; 8/10 for the reviewed stack integration until the inherited timer-budget defect is fixed.

[P2 — inherited from #974] Preserve pending per-timer edits when merging progress. In service.ts:1004–1009, { ...pending, timers } preserves pending attention/config but replaces all pending timer states with progress calculated from the still-shown record. While spent timer B is being rearmed through the attention writer and its file save is pending, another timer A can tick. B’s new attention survives, but its new armedAt and retained occurrence count are replaced by B’s old state. After persistence, timerState sees the arm-time mismatch and recalculates used from the new arm time, typically zero. B can then exceed its preserved max_occurrences budget. rearmed explicitly preserves that budget unless a restart was requested.

Merge unrelated progress while retaining per-slug timer changes already present in the pending record, or serialize the mutations. Add a gated service/runner case where A ticks while B’s rearm save is held; assert both A’s progress and B’s preserved budget survive. This is source-derived, not an executed reproduction. It is a base #974 follow-up, outside #967’s diff, and does not affect the standalone host’s synchronous adapter. It is recorded here once so the stack’s author receives the finding; no separate comment was posted to #974.

Head 2262e74a580cedee8a2d9336dbab2045bfb432af; base d914c830ebfaa007b042a52449c89e0871014d55. Four feature patches are range-diff identical to previously reviewed head 713659098f23c690dbbaeaae2a1b10e312309b9d; the remaining patch adapts progress to the new signature. That adapter merges into its current record, checks ownership and throws synchronously on storage refusal before timer admission. Prior feed-recovery and process-cleanup repairs remain unchanged. This is a follow-up of the previous repairs and their integration, not a new exhaustive audit of unchanged feature code.

Rocket completed systems/performance/lifecycle coverage, Mantis completed correctness/security/concurrency coverage, and Groot completed product/accessibility/source-visible flow coverage. I independently reconciled the evidence and completed source self-review. Public description (no attached images), changed publication surface and all five commit messages inspected; no additional publication finding.

Source-only: no PR code, tests, typechecks, builds, apps or live handover executed; current CI was not assessed. Native persistence/concurrent handover, host-level timer behavior, macOS locks/process cleanup, live relay recovery, focus/error-retry interactions, performance and human acceptance remain unverified. COMMENT only; this is not merge approval.

@loganj
loganj force-pushed the agent-host-standalone branch from 2262e74 to da64417 Compare October 16, 2026 20:44

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

No introduced finding in #967’s host-adapter update. One P2 remains in the inherited #974 persistence repair. Source assessment: 9/10 for the host delta; 8/10 for the reviewed stack integration until the occurrence-budget race is repaired.

[P2 — inherited from #974] Count a timer occurrence admitted while its own rearm is pending. withProgress at service.ts:740–744 preserves the pending rearm’s entire state when it differs from the shown state, including its old used count. A normal settings save leaves the old schedule visible until persistence settles. If that timer becomes due during the save, dueTimer can admit the occurrence and advance its shown count, while the pending record excludes that increment. Settlement then installs the pending record’s lower count.

For example, with max_occurrences = 1, used = 0 and an old deadline of 1060: begin a rearm just before that deadline and hold its file save; let the old occurrence run; then finish persistence. The rearmed deadline survives but used returns to zero, allowing a second occurrence. The currentness check does not prevent a turn that starts while the old attention object is still shown. Rearm explicitly retains the consumed budget in store.ts:398–408.

Preserve the pending rearmed deadline while carrying forward occurrences consumed during the save, or serialize admission with the conflicting timer edit; keep restart and removal semantics distinct. Add a gated same-timer case beside the new different-timer regression: allow the old occurrence to execute before releasing persistence, then verify the new deadline and incremented count survive and the occurrence limit still holds. This is source-derived, not an executed reproduction.

This finding belongs to base #974: service.ts is identical at this PR’s head and base. It is recorded here once as stack follow-up, outside #967’s changed lines; no separate comment was posted to #974. The previously reported different-timer overwrite is repaired. The host’s synchronous adapter correctly merges only changed timer slugs into its current record.

Reviewed head da64417a38220f348bde6d4bbc7197b33dd19307, base e71ab26c907a93eae0e7da1e2d1ceb843a0baef5. Compared with previously reviewed head 2262e74a580cedee8a2d9336dbab2045bfb432af: four host patches are range-diff identical; the remaining patch adapts the progress merge. Reviewed the four-file endpoint delta and relevant callers, including the inherited persistence repair. This is a focused follow-up, not an exhaustive new audit of unchanged host code.

Rocket completed systems/performance/lifecycle coverage, Mantis completed correctness/security/concurrency coverage, and Groot completed product/accessibility/source-visible flow coverage. I independently reconciled their evidence and completed source self-review. Public PR description (no attached images), changed publication surface and all five commit messages were inspected; no additional publication finding.

Source-only: no PR code, tests, typechecks, builds or apps executed; current CI was not assessed. Live persistence/concurrent handover, native locks/process cleanup, relay recovery, focus/error-retry interactions, measured performance and human acceptance remain unverified. COMMENT only; humans decide which findings must be fixed. This is not merge approval.

@loganj
loganj force-pushed the agent-host-standalone branch from da64417 to 8b8be58 Compare October 16, 2026 21:15

@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 automated source review via Wes’s account.

No new actionable findings in this follow-up. The prior same-timer occurrence-budget defect is repaired at source: the shared runner now waits while the agent record is being saved, before calculating timer progress or consuming an occurrence. Save settlement releases that gate; the standalone host correctly supplies saving: () => false because its write/fsync/rename path finishes synchronously. The added controlled-promise regression covers a rearm spanning the former due time and the remaining occurrence budget.

Scope: head 8b8be58b32fcf26cf71d522c2183839f8f38fa91, base 8aa080b086c1ecbf5ff1365f08c32c09c7dadea9. Follow-up comparison against da64417a38220f348bde6d4bbc7197b33dd19307: five changed files, including the inherited runner/service repair. Four host patches are unchanged by range-diff; the remaining host patch adds the new adapter contract and fixture. Reviewed against the shared feature-owner and host-boundary rules; source assessment for this follow-up: 9/10.

Independent coverage completed: Rocket (systems/performance/lifecycle), Mantis (correctness/security/concurrency), and Groot (product/error/retry flows), integrated by Star Lord. Pending saves intentionally postpone timer admission until settlement and the next existing five-second tick; mention/watch admission continues.

Validation: source inspection only, including save success/refusal/failure and retry paths, public PR description (no image attachments), changed publication surface and commit messages. Tests, builds, app execution, current CI, live host handover, persistence/concurrency behavior and rendered focus/accessibility were not validated. Existing documented host limitations remain. This COMMENT is not approval or merge authorization.

@loganj
loganj force-pushed the agent-host-standalone branch from 8b8be58 to 9239a44 Compare October 16, 2026 22:10

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

No new actionable findings in this host-adapter follow-up. Source assessment for the changed integration: 9/10.

Reviewed head 9239a44fa40004b3a8fb1ff0a5ffa723e5f9320c against base c1479a63f9575b9964fd2c9cf0698015347fed56. Compared with previously reviewed head 8b8be58b32fcf26cf71d522c2183839f8f38fa91: four host patches are unchanged by range-diff. This pass traced AgentStore wiring, serialized attention edits, timer progress and wake ordering, failed-save behavior, provider defaults and their supported callers. Rocket, Mantis and Groot supplied independent systems/lifecycle, correctness/security/concurrency and product/error-retry coverage; I integrated their source evidence.

The inherited Codex live-acceptance adapter mismatch remains at this base and is already reported on #974. It is a validation-tool issue, not a demonstrated production-host failure; no duplicate inline finding here.

Public PR description, five commit messages and changed publication surfaces inspected; the description has no image attachments. Source-only: no tests, builds, app launches or current CI assessment. Live persistence, concurrent writes, desktop/standalone handover, performance and rendered focus/error-retry behavior remain unverified. This COMMENT is not approval or merge authorization.

@loganj
loganj force-pushed the agent-host-standalone branch from 9239a44 to d09a5c6 Compare October 16, 2026 22:30

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

No new actionable findings in this follow-up. Source-review score: 9/10 for the changed scope.

All five agent-host patches are unchanged by range-diff from the previously team-reviewed head 9239a44. The complete endpoint delta is src/bundled/codex/live.mjs (17 additions, 4 deletions), inherited from #974: the acceptance fixture now implements AgentStore's synchronous reads and promise-returning writes, and its thread-name assertion includes the current conversation tag. This addresses the inherited fixture mismatch noted in the previous review; no new host integration behavior was introduced. Reviewed under the small-follow-up solo exception, retaining the earlier Rocket, Mantis and Groot coverage for unchanged feature patches.

Reviewed head: d09a5c6
Base: 9eb0789

Public PR description (no attached images), commit messages and changed publication surfaces checked. Source-only: no PR code, tests, builds, live acceptance command or app executed; current CI not assessed. Native handover, persistence/recovery, live provider behavior and performance remain unverified. No UI focus transitions changed; live error/retry behavior and human acceptance remain unverified. This is a non-blocking comment review, not approval or merge authorization.

loganj and others added 5 commits October 18, 2026 00:14
Add buzz-agent-host, a Node script that runs one agent this machine's
app saved, with the same AgentRunners and Claude/Codex run code the app
uses. It reads the agent's identity from identities.json and its key from
BUZZ_AGENT_KEY or the app's Keychain bundle, listens on the agent's own
relay connection, reads the community as the agent, and follows the app's
hosts/ flock protocol so only one copy runs the agent.

It uses the app's agent storage (agents/state/): the agent runs with the
settings, team prompts and Claude or Codex sessions the app saved, reads
its record again every tick so edits made in the app apply, and writes
only its own agent's record.

Build with `pnpm agent-host`; run with
`node dist-agent-host/buzz-agent-host.mjs run <pubkey>`.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Logan Johnson <loganj@squareup.com>
A DM's first messages wait for its metadata, so an untagged message
from the owner wakes the agent as in the app. Subscriptions the relay
closes after the login are asked for again, with a growing wait, unless
it refused them. Channels are heard in batches of 128, the most the
relay accepts in one request.

When a process exits, stopped or not, its process group is killed too,
as host_process.rs does, so a tool it left running cannot outlive the
agent's claim.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Logan Johnson <loganj@squareup.com>
- While one subscription is asked for again, the open ones still hear
  messages. The feed now holds them until it is listening again, and
  then gives them to the host. Before, the host dropped them.
- Each subscription that closes keeps where it stopped hearing. Its new
  request asks from there, until the relay has sent what it missed.
  Before, traffic on another subscription moved that point on, so a
  long outage skipped messages.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Logan Johnson <loganj@squareup.com>
The feed gave what it heard while not listening as live events. The
runner marks a live event seen before it queues it, so a burst past the
agent's queue (32) or rate budget was dropped for good.

Those events, and what a re-requested subscription sends before its
EOSE, now come as a replay. The runner keeps a replay in its backlog
and admits it as the agent has room.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Logan Johnson <loganj@squareup.com>
Catch-up progress now has one key per agent, so the old reason, a
shared value the app rewrote whole, no longer applies.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Logan Johnson <loganj@squareup.com>
@loganj
loganj force-pushed the agent-host-standalone branch from d09a5c6 to 661ac1f Compare October 18, 2026 04:15

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

Two P2 findings: Solo handover changes conversation/session routing, and revoking the last authorized channel in a subscription batch disables healthy work elsewhere. Details and repairs are inline. Source assessment: 8/10 until these paths are repaired. The revocation defect is an earlier review miss, now established against the concrete relay producer; it was not introduced by this rebase.

Reviewed head 661ac1f54f592ab91b395de054d5c7ecd2a3f2e3 against base d3786b6da4758704b695d43d1e829a0efe650b3a. This is a follow-up of prior repairs and their integration with the updated base. Range-diff preserves four feature patches unchanged; the remaining patch renames the Solo adapter without updating its behavior. Prior feed-recovery and process-cleanup repairs remain present. Rocket, Mantis and Groot supplied independent systems/lifecycle, correctness/security/concurrency and product/source-visible-flow coverage; I integrated their evidence.

Public description (no attached images), changed publication surface and five commit messages inspected; no additional disclosure finding. Optional: refresh the description’s old Me-chat terminology and already-repaired limitations.

Source-only: no PR code, tests, typechecks, builds or apps executed. One hosted-check snapshot was incomplete, with an earlier cancelled run’s failed aggregate; it does not establish green CI. macOS lock/process behavior, live relay recovery, desktop handover, persistence concurrency, rendered focus/accessibility, performance and human acceptance remain unverified. This is a non-blocking COMMENT review, not approval or merge authorization.

Comment thread src/agent-host/reads.ts Outdated
Comment thread src/agent-host/feed.ts
loganj and others added 2 commits October 18, 2026 00:45
The buzz.solo label on channel metadata is the one Solo fact, which every
member and agent reads. The host now reads it fresh for each turn, so an
agent taken over from the desktop answers an existing Solo chat as one
top-level conversation, and threads again once the chat becomes a channel.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Logan Johnson <loganj@squareup.com>
…batch

The relay refuses a channel batch only once the agent can read none of
its channels. The feed stopped being live until the next connection, so
mentions and timers in every other channel stopped. A refused batch no
longer counts toward being live, and is asked for again when a roster
shows the agent back in one of its channels.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Logan Johnson <loganj@squareup.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.

One P2 membership-recovery defect remains, consolidated inline. Source assessment: 8/10 until newly joined and rejoined channels reliably resume delivery. The Solo-label repair is present: the turn and typing paths use the shared label interpretation, conversion is read afresh, and failed reads reject. The revocation repair keeps unrelated work live, but its membership recovery is incomplete.

Reviewed head d2db041290aa285b86eecd5b2e51fe651cacb377 against base d3786b6da4758704b695d43d1e829a0efe650b3a, focusing on the five-file repair delta from previously reviewed 661ac1f54f592ab91b395de054d5c7ecd2a3f2e3 and its supported callers. Rocket completed systems/lifecycle coverage, Mantis correctness/security/concurrency coverage, and Groot product/Solo/error-path coverage. I independently reconciled the lanes and source evidence. Public description and all seven commit messages inspected; no image attachments or additional publication finding. Refreshing the description’s stale limitations is optional.

Source-only: no PR code, tests, builds or apps executed. One hosted CI snapshot showed Vitest flake-check failure, other jobs still running and Windows validation skipped; causal attribution was not assessed. Live relay recovery, native handover, rendered focus/accessibility, measured performance and human acceptance remain unverified. This non-blocking COMMENT review is not merge approval.

Comment thread src/agent-host/feed.ts
const key = `channels:${index}`;
if (
subscribed &&
denied.has(key) &&

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.

🤖 [P2] Refresh batch subscriptions when channel membership returns or expands. Recovery here only handles an already-known channel whose whole batch was denied. Two authorized membership paths remain unheard:

  • If the agent loses the sole channel in its final partial batch and then joins a new channel, that new ID is appended to the denied batch. The else branch still skips both requests at lines 378–380. The new liveness filter reports Listening despite no event/metadata subscription for the new channel.
  • If A and B share an open batch, revoking A removes its relay routing scope while B keeps the subscription open. Rejoining A reaches this condition with denied.has(key) === false, so A is never added back. The supported relay removes individual scopes in subscription.rs:322–335 and emits CLOSED only when the batch becomes empty in side_effects.rs:131–135.

Explicit mentions can still arrive via the separate #p subscription, but untagged DM turns and channel watch events do not reach the runner until another batch refresh/reconnect. Reconcile/reissue the affected channel and metadata batch when readable membership changes, covering both newly discovered channels and rejoining a still-open batch. Extend the regression to assert resumed delivery for both cases; the added test only covers a known channel returning after whole-batch closure. This is source-derived, not an executed reproduction or a claim about the deployed relay version.

After stopAll kills a process group, an orphan that has exited can stay a
zombie until its new parent reaps it, and signal 0 still finds it. The
test now reads the process state, so it no longer fails on CI runners
whose reaper is slow.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Logan Johnson <loganj@squareup.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.

No new actionable findings in this test-only follow-up; 9/10 for the delta. spawn.test.ts now checks process state so a terminated, unreaped zombie does not count as running. The existing positive liveness assertion guards the suite against an unavailable ps, and the shutdown assertions still distinguish a running descendant from a terminated one.

Production source is unchanged from d2db041290aa285b86eecd5b2e51fe651cacb377. The previously reported membership-recovery P2 remains unresolved; this follow-up does not clear it or duplicate its finding. Overall assessment remains 8/10 until that repair is made.

Reviewed head 3880d2c66db412610b3b9c101b574049d22e8883 against base d3786b6da4758704b695d43d1e829a0efe650b3a, focusing on the one-file delta and its process-host callers. Rocket covered systems/process lifecycle, Mantis correctness/concurrency and false-pass risk, and Groot source-visible behavior and validation claims. I reconciled their source evidence and completed self-review. Public PR description (no attached images) and all eight commit messages inspected; no new publication finding.

Source-only: no PR code, tests, builds or apps executed. One hosted CI snapshot showed the Vitest flake check successful while the broader run remained in progress; Windows validation was skipped. Actual process/reaper timing, macOS handover, runtime recovery, performance and human acceptance remain unverified. This COMMENT review is not merge approval.

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.

3 participants