Skip to content

Add customizable welcome message builder - #6947

Draft
klopez4212 wants to merge 10 commits into
mainfrom
kennylopez-welcome-message-builder
Draft

Add customizable welcome message builder#6947
klopez4212 wants to merge 10 commits into
mainfrom
kennylopez-welcome-message-builder

Conversation

@klopez4212

Copy link
Copy Markdown
Contributor

Summary

  • add an admin welcome-message builder with manual editing, preview, formatting, and inline member, link, image, and channel elements
  • add provider-agnostic writing help through the existing configured agent runtime
  • support drag-and-drop image placement and render uploaded images in preview

Testing

  • full pre-push suite (desktop checks, typecheck, tests, Rust tests, clippy, Tauri tests, and file-size checks)
  • focused welcome-message Playwright flow
  • focused ACP and welcome-message backend tests

Signed-off-by: kenny lopez <klopez4212@gmail.com>
@klopez4212
klopez4212 requested a review from a team as a code owner August 27, 2026 17:06
Signed-off-by: kenny lopez <klopez4212@gmail.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ec7d9cd4cd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +74 to +77
function saveMessage() {
setSavedMessage(message);
setBuilderOpen(false);
toast.success("Welcome message saved");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Persist the welcome message instead of only updating local state

saveMessage only copies the draft into component state and displays a success toast; no Tauri command, relay event, or storage write occurs, and no join workflow reads this state. Consequently, leaving the settings view or restarting the app loses the “saved” message, and new members never receive or see it. Persist and hydrate this as community-scoped data, preferably through the repository’s Nostr event path.

AGENTS.md reference: AGENTS.md:L158-L172

Useful? React with 👍 / 👎.

Comment on lines +82 to +83
if let Some(home) = default_agent_workdir() {
command.current_dir(home);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Isolate the writing-only ACP session from coding tools

When the configured runtime is a tool-capable coding agent such as Goose, Codex, or Claude, this helper runs it from ~/.buzz (or the user’s home directory), while AcpClient::handle_permission_request automatically selects every allow_once permission. The supposedly text-only writing request can therefore execute shell or file-edit tools against a directory containing Buzz configuration and credentials. Run this helper in an isolated temporary directory and reject tool permissions or explicitly apply a read-only/plan mode.

Useful? React with 👍 / 👎.

Signed-off-by: kenny lopez <klopez4212@gmail.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fe090044d8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct WelcomeMessageDraft {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Document the exported welcome draft

WelcomeMessageDraft is a newly exported Rust type but has no rustdoc, violating the repository requirement that new public APIs have doc comments. Add a concise description of the serialized draft contract before exporting it.

AGENTS.md reference: AGENTS.md:L147-L150

Useful? React with 👍 / 👎.

Comment on lines +101 to +103
for (key, value) in &descriptor.env {
command.env(key, value);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve the selected model for writing help

When the preferred runtime is Claude or Codex and the configured global model differs from the CLI default, forwarding only descriptor.env loses that selection: those runtimes have no model_env_var, while the normal managed-agent spawn separately applies ANTHROPIC_MODEL or BUZZ_ACP_MODEL, and run_one_shot_prompt does not select a model after creating the session. Writing help therefore silently runs the runtime's default model, potentially changing behavior and cost; propagate and apply the resolved model through the one-shot path.

Useful? React with 👍 / 👎.

match update_type {
"agent_message_chunk" => {
if let Some(text) = update["content"]["text"].as_str() {
self.agent_message.push_str(text);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Bound assistant-output capture to the helper

For every ordinary relay-driven agent turn, this now appends all agent_message_chunk text even though only the one-shot helper consumes the buffer. The existing LinesCodec limit only bounds each individual line, so a verbose or rogue adapter can stream bounded chunks throughout the two-hour turn and make every agent client retain an arbitrarily large string, defeating the read-path OOM protection. Enable capture only for helper clients or impose an aggregate response cap.

Useful? React with 👍 / 👎.

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

:bot: Jude’s code review agent — REQUEST CHANGES

Reviewed: 0ccf934b88f610f5f235862ecd51e2dcbae2cb74..fe090044d84f853315fdba229a4578608ba69ef9 (live head rechecked immediately before submission)

Risk: high — this adds a community-admin setting whose claimed persistence and member-join delivery cross renderer, native, relay, authorization, and lifecycle boundaries.

Blocking — Save neither persists nor delivers the welcome message

desktop/src/features/community-members/ui/WelcomeChannelSettings.tsx:38-40 holds the only saved value in component-local React state. saveMessage() at :74-78 only copies the draft into that state, closes the dialog, and displays “Welcome message saved.” The new native command generates a draft, but the changed production paths contain no durable save/load contract or join-path consumer.

Consequently, a remount/restart discards the setting, another admin/device cannot observe it, and a joining member never receives or renders it. The focused Playwright flow only closes and reopens the dialog within the same mounted component, so it protects the illusion rather than the stated contract: “Set the message new members see when they join.”

Author action: either:

  1. implement community-scoped, authorized durable save/load and authoritative join-path consumption; report success only after durable completion; expose loading/save/delivery failures; and add regressions proving persistence across remount/reload plus delivery/rendering for a joining member, including tenant/auth and retry/duplicate boundaries; or
  2. if this is intentionally builder-only, remove the Save/live-delivery claims and success toast, then retitle/rescope the feature truthfully.

Verification owner: author for the blocking implementation and contract-shaped regressions; reviewer for revalidation of the admin/new-member journey and visible success/error states.

Exact-head validation

  • PASS — cargo test -p buzz-acp: 823 unit + 9 lifecycle integration tests, 0 failures.
  • PASS — pnpm --dir desktop test: 5,706 tests, 0 failures.
  • PASS — just desktop-tauri-test: full Tauri workspace suite; one test ignored by declaration.
  • PASS — desktop tsc --noEmit.
  • PASS — invites-settings-screenshots.spec.ts: 6/6; inspected builder, formatting/preview, context-menu, assisted-writing, and image-preview output with no separate visual blocker.
  • PASS — exact-head GitHub functional matrix: Desktop/Core/smoke/integration/relay, Rust, Security, cross-compile, DCO, macOS build, and release candidate. The lone red Mark Previous Review Stale job is review-workflow bookkeeping, not a PR-caused product gate.
  • PASS — clean detached worktree and git diff --check at the reviewed SHA.

Confidence gaps — not additional blockers

  • No packaged native journey was independently exercised. Reviewer/tooling owns that verification; it is not additional author rework.
  • The focused Rust attempts in one validation lane timed out while downloading/compiling; the completed affected-package suites and exact-head CI passed.
  • Pasted rich content is serialized as HTML and reconstructed with template.innerHTML. No unsafe retained element/attribute was reproduced through the actual contenteditable path, so this remains residual security risk rather than a finding; a targeted sanitization test would improve confidence.
  • Provider-specific ACP one-shot output/chunk behavior was not exercised against every supported adapter.

The editor is polished. Unfortunately, it is attached to no system of record and no join lifecycle. The primary success state is therefore materially false.

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

Carl, an automated reviewer, commenting via Wes’s GitHub account.

REQUEST CHANGES on fe090044d84f853315fdba229a4578608ba69ef9 against 0ccf934b88f610f5f235862ecd51e2dcbae2cb74. I reviewed GitHub metadata, diff, and exact-head source only; I did not execute PR code.

P1 — Save neither persists nor delivers the advertised welcome message

WelcomeChannelSettings.tsx:38-40 keeps the only saved value in component-local React state, and saveMessage() at :74-78 only copies the draft into that state, closes the dialog, and reports “Welcome message saved.” Across the changed production paths, generate_welcome_message only returns an assisted draft; there is no community-scoped durable write/read or join-time consumer.

The setting therefore disappears on remount/restart, cannot propagate to another admin/device, and cannot produce the message promised by “Set the message new members see when they join.” The Playwright flow protects the local-state illusion by checking the dialog closes without reloading or joining a member.

Please either implement an authorized community-scoped save/load and authoritative join-delivery/rendering path, with causal coverage for remount/reload, community isolation, and an actual member join, or rescope the UI so it no longer claims this is saved or delivered.

P1 security — The writing-only helper can authorize coding tools in Buzz’s sensitive working directory

welcome_message.rs:80-103 launches the globally configured ACP coding runtime from default_agent_workdir() (the user home/~/.buzz) and forwards its resolved environment and provider credentials. The shared ACP client handles every session/request_permission by selecting allow_once (acp.rs:1936-1980), and run_one_shot_prompt creates a normal session with no tool-denial/read-only policy (lib.rs:5092-5108). Thus a feature presented as text generation can execute shell or file tools against Buzz configuration and credentials if the model requests them.

Run this narrow writing task in an isolated, empty working directory with an explicit no-tools policy (not merely a prompt instruction), and add a regression proving a requested tool permission is rejected. Do not expose the user’s full coding-agent environment unless the writer strictly needs each value.

P2 — Assistant-output capture is unbounded for every normal ACP turn

acp.rs:1766-1769 now appends every agent_message_chunk to a String on the shared client, although only the one-shot helper consumes it. The 10 MB codec limit applies per line, not to the aggregate; an ordinary long-running or rogue adapter can keep sending valid bounded chunks until the turn’s hard deadline and grow process memory without a cap. Enable capture only for one-shot clients or enforce a small aggregate limit with a defined overflow error and test.

CI is broadly green; that does not exercise the absent persistence/delivery contract or make the tool boundary safe.

Signed-off-by: kenny lopez <klopez4212@gmail.com>
…ssage-builder

Signed-off-by: kenny lopez <klopez4212@gmail.com>
Signed-off-by: kenny lopez <klopez4212@gmail.com>
@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown

🔐 Codex Security Review

Status: review required for the current range.

The current range is a3730784fc851bb1125b40cca9b0a30788a293c1...3d7627ef708ec9a9e0ff9704e12c730fdcb5d342.
A new review must complete for this exact range. When manual authorization
is required, a Block organization member must comment exactly
@buzz-security-review 3d7627ef708ec9a9e0ff9704e12c730fdcb5d342 to authorize a new review.
Any previous review applies only to its recorded range.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e8ae0f486a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +106 to +108
for (key, value) in &descriptor.env {
command.env(key, value);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reapply the writer prompt after the layered environment

When the selected harness definition or global agent environment sets the supported BUZZ_ACP_SYSTEM_PROMPT knob, this later environment loop overwrites WELCOME_WRITER_SYSTEM_PROMPT on the child command. Writing help then receives the ordinary agent prompt instead of the fixed plain-JSON/no-tools prompt, which can make otherwise valid configurations return tool activity or unparsable output. Apply the writer-specific value after descriptor.env, or exclude this key from the inherited environment for this helper.

Useful? React with 👍 / 👎.

Comment on lines +5113 to +5114
let system_prompt_transport = if is_goose || (protocol_version < 2 && !is_claude_agent) {
None

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Send the one-shot system prompt through Goose's extension

When Goose is the configured runtime, this branch deliberately omits the system prompt from session/new, but the one-shot path never follows up with session_set_goose_system_prompt as the normal session setup in pool.rs does. Consequently Goose never receives WELCOME_WRITER_SYSTEM_PROMPT, so the writing helper loses its intended plain-text/no-tools instruction and may produce output that fails draft parsing. Invoke Goose's custom system-prompt request after creating the session, with the same fallback behavior as the pooled path.

Useful? React with 👍 / 👎.

Signed-off-by: kenny lopez <klopez4212@gmail.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b65fdc9245

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

|| !valid_type
|| insert.title.trim().is_empty()
|| insert.title.len() > 120
|| insert.url.len() > 2_048

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Resolve generated channel inserts to real channel IDs

When writing help is asked to mention a channel such as #introductions, the model receives neither the community’s channel catalog nor the UUID-based buzz://channel/<uuid> contract, and this validation accepts any destination up to 2,048 characters. The E2E mock consequently returns buzz://channel/introductions, which parseChannelLink rejects as invalid-channel-uuid; this draft can still be saved without warning, leaving the welcome message with a nonfunctional channel chip. Pass resolvable channel data into the generation flow or require the admin to select a real channel before accepting the draft.

Useful? React with 👍 / 👎.

Signed-off-by: kenny lopez <klopez4212@gmail.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 846eed7271

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +39 to +40
(channel) =>
channel.channelType !== "dm" && channel.archivedAt === null,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Exclude inaccessible private channels from the welcome picker

When an admin belongs to a private channel, this filter includes it in the picker even though the welcome message is intended for every newly joined community member. Relay membership does not grant private-channel membership, and isChannelReferenceOpenable rejects private references for non-members, so selecting one produces a channel chip that most new members cannot open; restrict choices to open channels or couple the welcome flow to explicit channel admission.

AGENTS.md reference: AGENTS.md:L11-L18

Useful? React with 👍 / 👎.

@klopez4212
klopez4212 marked this pull request as draft August 28, 2026 10:45
delkc added 2 commits August 28, 2026 17:03
Signed-off-by: Clay Delk <clay.delk@gmail.com>
…ssage-builder

* origin/main:
  refactor(db): extract domain stores from database runtime (#6987)
  feat(desktop): add team sharing to community catalog (#3995)
  Refresh mobile utility surfaces and theme picker (#6944)
  fix(desktop): complete project empty and context states (#6980)
  Fix mobile jump-to-latest flicker (#6807)
  refactor(relay): NIP-98 admin auth with Operator/Moderator roles and NIP-11 discovery (#3777)
  refactor(db): split channel membership store (#6782)
  feat(auth): add NIP-FI canonical assertion verifier and contracts (#6776)

Signed-off-by: Clay Delk <clay.delk@gmail.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