Skip to content

Chat-first agent creation via portable buzz CLI drafts#1878

Open
morgmart wants to merge 17 commits into
mainfrom
welcome-agent-creation
Open

Chat-first agent creation via portable buzz CLI drafts#1878
morgmart wants to merge 17 commits into
mainfrom
welcome-agent-creation

Conversation

@morgmart

Copy link
Copy Markdown

What this does

Makes creating your first agent a guided, chat-first experience — and moves conversational agent drafting onto the portable buzz CLI so it works across agent runtimes.

Welcome channel: chat-first agent creation

  • Create an agent is now the first intro card in Welcome (before Create a channel).
  • Clicking it opens a choice dialog: Create with Fizz (recommended, bordered) or Create manually.
  • "Create with Fizz" sends a simple kickoff message and reveals it using the timeline's own scroll-to-bottom-on-send behavior (no smooth-scrolling through history).
  • "Create manually" opens the standard create-agent form pre-targeted to the channel — without navigating away from the channel.

Conversational agent drafts via buzz CLI (portable across runtimes)

  • New commands: buzz agents draft-create and buzz agents draft-update.
  • These publish the same encrypted, owner-scoped observer request Desktop already understands — the agent can only draft; the owner reviews and saves in the standard form.
  • Replaces the create_agent/update_agent MCP tools that only worked for runtimes receiving buzz-dev-mcp (Buzz Agent, Codex). The CLI path works for Claude Code and Goose too via their native shell tools.
  • Shared base prompt + managed buzz-cli skill teach every runtime: ask only for name and what it should do — no runtime/provider/model/access questions. Desktop resolves machine defaults; new agents default to Only me.
  • BUZZ_AUTH_TAG now passes through Buzz Agent's MCP shell so drafts work there.

Any owned agent can draft (not just Fizz)

  • The observer request kind is now generic (agent_management_request).
  • Desktop accepts drafts from any managed agent this Desktop owns, validates the agent and owner share the originating channel, and opens the owner-editable form. The owner save remains the only write gate.

Channel attachment partial success

  • Creating an agent from a channel is now two outcomes: create/start, then attach.
  • If attaching fails, the agent is kept and the created dialog says so, with the normal add-agent error, plus Try again (attach only — never recreates) and Done.

Form polish

  • Advanced section starts collapsed on create (chat-drafted creates no longer prefill respondTo, which was forcing it open).
  • Chat-drafted creates prefill only name + instructions.

Verification

  • just ci-equivalent gates green on pre-commit/pre-push (rust, desktop, tauri, mobile tests).
  • New unit tests: CLI draft contract (owner-encrypted kind 24200, Desktop payload shape), parser allowlist, base-prompt guidance.
  • New Playwright specs: welcome chat-first + manual flows, card order, cancel/done staying in channel, attach-failure retry (asserts add_channel_members retries without a second create_managed_agent), agent picker states.

@morgmart morgmart requested a review from a team as a code owner July 14, 2026 22:40
@morgmart morgmart force-pushed the welcome-agent-creation branch from dd5e4d0 to 4bcbf1c Compare July 14, 2026 22:55

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

Requesting changes before this can meet the 9/10+ bar.

  1. The new CLI does not pass the repository's required Rust lint gate. Both Rust Lint and Windows Rust fail on RespondToArg::to_wire(self) (crates/buzz-cli/src/lib.rs:235) with clippy::wrong_self_convention under -D warnings. This is introduced by this PR and must be fixed rather than merged red (for example, make the enum Copy or rename/change the receiver as appropriate).

  2. Ephemeral draft requests can be silently lost during Desktop startup/query refresh. handleRelayObserverEvent drops a frame unless its agent is already in knownAgentPubkeys, and the management listener independently drops it unless managedAgentsQuery.data is already populated. Kind-24200 requests are ephemeral and there is no queue/replay path, so a valid buzz agents draft-create can print “Draft sent” while Desktop discards it if it arrives before the managed-agent query/effects settle. The listener is also torn down/re-added whenever that query data changes. Please make acceptance depend on an initialized, stable ownership source or buffer candidate requests until ownership is known, and add a test for a request arriving before managed-agent data resolves.

Security direction is otherwise good: verified NIP-OA binding, owner encryption, signed-agent/tag matching, parser allowlists, shared-channel authorization at save, and owner-confirmed write gates. I also verified the focused Rust contract tests (3/3) and the full Desktop helper suite (2834/2834). The branch is one current-main commit behind (#1826), so rebase and rerun CI before approval.

@wpfleger96 wpfleger96 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Code Review — PR #1878

Scope: 39 files, +2102/−759 across Rust (buzz-cli, buzz-acp, buzz-agent, buzz-dev-mcp, nest) and Desktop TS (agent management, channels, welcome flow, E2E).

Three parallel review passes (Rust, Desktop TS, Security) plus manual source-level verification of all key files.

CI

Previous run @ 4bcbf1cb had Clippy wrong_self_convention on RespondToArg::to_wirefixed in dcca7cb7 (added Copy derive, correct fix). E2E failures (global-agent-config-screenshots:119, home-collapsed-top-chrome:9) are pre-existing flakes on unmodified files. New CI run pending at dcca7cb7.


IMPORTANT — F1. Channel co-membership check deferred to submit-time

desktop/src/features/agents/useAgentManagement.ts:~86–95

The subscribeAgentManagementRequests callback checks isOwnedAgent and deduplicates, but does NOT call assertAgentCanActFromOrigin(channelId) before setRequest(next). That check fires only inside submitCreate/submitUpdate (~118–134). An owned agent in channel X can publish a draft with channelId = channel Y (neither agent nor owner is a member), the form opens pre-filled, and only fails on Submit.

No write occurs (the gate works), but the agent can render arbitrary text in the owner's UI before consent.

Fix: Move assertAgentCanActFromOrigin into the subscriber before setRequest(next) — silently drop or toast the out-of-scope draft.

IMPORTANT — F2. Update draft targets persona by display name — scope extends beyond self-update

desktop/src/features/agents/useAgentManagement.ts:~108–116

matchingPersonas resolves by case-insensitive displayName across ALL owned editable personas. assertAgentCanActFromOrigin validates the drafting agent's channel membership, not the target persona's agent. Agent in channel X can draft an update for any persona by display name, even if that persona's agent is only in channel Y.

Fix: Validate the target persona's managed agent pubkey matches sourceAgentPubkey.current (self-update only), or check the target agent is a member of the request's channel.

IMPORTANT — F4. Single-slot pending draft queue with no expiry

desktop/src/features/agents/useAgentManagement.ts:~93

if (pendingRequestId.current === null) gates all new requests. If the dialog is never closed, no management requests are processed for the session. A rogue owned agent can park a blocking draft. Consider a timeout or newest-supersedes-oldest policy.


MINOR

  • M1. No secondary size bound on Desktop receipt (CLI enforces 120/20k chars, Desktop parser doesn't re-validate lengths).
  • M2. BUZZ_AUTH_TAG now passes to all MCP subprocesses via PASSTHROUGH_ENV — document the trust model decision for third-party MCP servers.
  • M3. Several explanatory comments in ChannelScreen.tsx removed as incidental cleanup unrelated to this PR.
  • M4. rustls::crypto::ring::default_provider().install_default() in buzz-dev-mcp — a one-line comment on why (CLI's HTTPS client needs crypto provider via MCP path) would help.
  • M5. E2E readCommandLog global state relies on bridge mock logging contract — silent false-pass if contract changes.

Positives (not padding — genuinely strong)

  • Parser allowlist (hasOnlyKeys in agentManagement.ts) correctly blocks injection of extra fields (runtime, provider, model, respondTo, apiKey) in create drafts.
  • AddChannelBotDialog simplification (−759 lines) consolidates all creation through the canonical form — this is the right direction.
  • CLI draft publishing (agent_management.rs) has solid test coverage: contract, validation, rejection. Encrypted owner-scoped events, UUID validation, proper error handling.
  • Channel attachment partial success (useCreatedAgentChannelAttachment) is well-designed: retry only attempts attach, never recreates.
  • Clippy fix in dcca7cb7 is correct (Copy on two-variant enum).

Blocking: F1, F2. F4 is borderline (stuck-UI, not auth).

@morgmart

morgmart commented Jul 14, 2026

Copy link
Copy Markdown
Author

🤖 Follow-up to @wesbillman’s review submitted July 14 at 23:08 UTC, which contained two requested changes:

  1. RespondToArg now derives Copy, satisfying clippy::wrong_self_convention on Linux and Windows (dcca7cb7).
  2. Ephemeral agent-management requests are now buffered through both startup ownership gates (b227343d):
    • raw signed/encrypted observer frames are held in a bounded queue until the trusted managed-agent set initializes, then pass through the same sender/tag/ownership checks;
    • parsed management requests are held in a bounded queue until managedAgentsQuery resolves, then accepted only if the sender is owned;
    • the listener is stable instead of being torn down whenever query data changes.

Added focused tests proving a request is buffered before ownership resolves, then accepted for an owned agent or rejected for an unknown agent. Local typecheck, Biome, file-size checks, parser/buffer tests, clippy, and pre-push Rust/Desktop/Tauri/mobile gates pass.

This comment predates and does not summarize @wpfleger96’s later review; those findings are being handled in their individual inline threads.

@wpfleger96 wpfleger96 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thorough review of the chat-first agent creation flow. The architecture is well-structured — the CLI draft layer, allowlist parser, and AddChannelBotDialog simplification are all solid. Two IMPORTANT findings on the channel/agent validation path, plus notes below.

Comment thread desktop/src/features/agents/useAgentManagement.ts
Comment thread desktop/src/features/agents/useAgentManagement.ts
Comment thread desktop/src/features/agents/useAgentManagement.ts
Comment thread desktop/src/features/agents/agentManagement.ts
Comment thread crates/buzz-agent/src/mcp.rs
Comment thread crates/buzz-dev-mcp/src/lib.rs
Comment thread desktop/src/features/channels/ui/ChannelScreen.tsx
Comment thread desktop/tests/e2e/welcome-agent-modal-screenshots.spec.ts
@morgmart morgmart force-pushed the welcome-agent-creation branch from ad70e1b to f6d6cf1 Compare July 15, 2026 02:10
@morgmart

Copy link
Copy Markdown
Author

🤖 @wpfleger96 Follow-up to your code review: we worked through every finding individually; the detailed decisions and changes are in the now-resolved inline threads.

  • F1 — origin validation: Fixed. Desktop now verifies ownership and shared-channel membership before showing a draft, and again at Save.
  • F2 — cross-agent updates: Kept intentionally. Owned agents may propose updates to personal agents, but only the owner can apply them through the editable review modal.
  • F4 — concurrent drafts: Kept one active draft for v1 to protect in-progress owner edits; documented the collision tradeoff and future inbox/lifecycle direction.
  • M1 — size bounds: Deferred. Current limits are CLI guardrails, not product-wide form/backend rules; parser-only rejection would be inconsistent and silent.
  • M2 — auth-tag passthrough: Documented the non-secret attestation and MCP trust model.
  • M3 — removed context: Restored the thread-navigation architecture comment.
  • M4 — Rustls setup: Added the provider-install rationale.
  • M5 — E2E command log: Hardened the helper to fail loudly if logging is unavailable.

CI is fully green and there are no unresolved review threads.

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