diff --git a/crates/buzz-acp/src/base_prompt.md b/crates/buzz-acp/src/base_prompt.md index 3dd4945ae..e644a4a54 100644 --- a/crates/buzz-acp/src/base_prompt.md +++ b/crates/buzz-acp/src/base_prompt.md @@ -72,9 +72,13 @@ When in doubt, prefer the reply destination explicitly supplied in `[Context]`. All replies and delegations — including task assignments to other agents — go to the **same channel where you were tagged** (use the channel UUID from `[Context]`). Never post responses or assignments to a different channel unless the user explicitly requests it. +### Channel Creation + +When creating a channel, use `buzz channels create --type stream` unless the owner explicitly requests a forum. Forum channels are a preview feature and may be hidden for owners who have not enabled them; when the request is ambiguous, ask before using `--type forum`. + ### Forum Channels -Forum channels are not stream channels, and the reply kind must match the thread root. Before replying, inspect the root kind in `[Context]`; if `[Context]` gives only a root event ID, fetch that root with `buzz messages thread --channel --event ` before choosing a kind. Use the stream default kind `9` for replies beneath a kind-`9` root, even if the channel also hosts forum posts. For a new forum thread, send kind `45001`: `buzz messages send --channel --kind 45001 --content "..."`. Only beneath a kind-`45001` forum root, send replies as kind `45003` with the supplied `--reply-to `. Never send kind `45003` beneath a kind-`9` root. +Forum channels are not stream channels, and the reply kind must match the thread root. Before replying, inspect the supplied `Thread root kind` in `[Context]`; only if the kind is unavailable, fetch the root with `buzz messages thread --channel --event ` before choosing a kind. Use the stream default kind `9` for replies beneath kind-`9`, legacy kind-`40002`, reminder kind-`40007`, kind-`40008` diff, and workflow approval kind-`46010` stream roots, even if the channel also hosts forum posts. For a new forum thread, send kind `45001`: `buzz messages send --channel --kind 45001 --content "..."`. Only beneath a kind-`45001` forum root, send replies as kind `45003` with the supplied `--reply-to `. Never send kind `45003` beneath stream roots. ### General diff --git a/crates/buzz-acp/src/lib.rs b/crates/buzz-acp/src/lib.rs index abac9bba2..28f8eb96d 100644 --- a/crates/buzz-acp/src/lib.rs +++ b/crates/buzz-acp/src/lib.rs @@ -21,8 +21,9 @@ use std::time::Duration; use acp::{AcpClient, EnvVar, McpServer}; use anyhow::Result; use buzz_core::kind::{ - KIND_MEMBER_ADDED_NOTIFICATION, KIND_MEMBER_REMOVED_NOTIFICATION, KIND_STREAM_MESSAGE, - KIND_STREAM_REMINDER, KIND_WORKFLOW_APPROVAL_REQUESTED, + KIND_FORUM_COMMENT, KIND_FORUM_POST, KIND_MEMBER_ADDED_NOTIFICATION, + KIND_MEMBER_REMOVED_NOTIFICATION, KIND_STREAM_MESSAGE, KIND_STREAM_REMINDER, + KIND_WORKFLOW_APPROVAL_REQUESTED, }; use buzz_core::observer::{ decrypt_observer_payload, encrypt_observer_payload, OBSERVER_FRAME_TELEMETRY, @@ -2077,6 +2078,8 @@ async fn tokio_main() -> Result<()> { kinds: config.kinds_override.clone().unwrap_or_else(|| { vec![ KIND_STREAM_MESSAGE, + KIND_FORUM_POST, + KIND_FORUM_COMMENT, KIND_WORKFLOW_APPROVAL_REQUESTED, KIND_STREAM_REMINDER, ] @@ -3822,15 +3825,29 @@ fn spawn_failure_notice( content: String, ) { if let Some(rest) = rest_client { - let thread_tags = batch + let (thread_tags, triggering_kind, triggering_event_id) = batch .events .last() - .map(|be| queue::parse_thread_tags(&be.event)) + .map(|be| { + ( + queue::parse_thread_tags(&be.event), + be.event.kind.as_u16() as u32, + Some(be.event.id), + ) + }) .unwrap_or_default(); let rest = rest.clone(); let channel_id = batch.channel_id; tokio::spawn(async move { - pool::post_failure_notice(&rest, channel_id, &thread_tags, &content).await; + pool::post_failure_notice( + &rest, + channel_id, + &thread_tags, + triggering_kind, + triggering_event_id, + &content, + ) + .await; }); } } @@ -4464,6 +4481,15 @@ mod agent_draft_prompt_tests { assert!(prompt.contains("never changes membership automatically")); } + #[test] + fn shared_base_prompt_defaults_channel_creation_to_stream() { + let prompt = include_str!("base_prompt.md"); + assert!(prompt.contains("buzz channels create --type stream")); + assert!(prompt.contains("unless the owner explicitly requests a forum")); + assert!(prompt.contains("may be hidden for owners who have not enabled them")); + assert!(prompt.contains("ask before using `--type forum`")); + } + #[test] fn shared_base_prompt_distinguishes_forum_kinds_from_stream_messages() { let prompt = include_str!("base_prompt.md"); @@ -4471,9 +4497,13 @@ mod agent_draft_prompt_tests { assert!(prompt.contains("kind `45001`")); assert!(prompt.contains("kind `45003`")); assert!(prompt.contains("stream default kind `9`")); - assert!(prompt.contains("if `[Context]` gives only a root event ID")); + assert!(prompt.contains( + "legacy kind-`40002`, reminder kind-`40007`, kind-`40008` diff, and workflow approval kind-`46010` stream roots" + )); + assert!(prompt.contains("inspect the supplied `Thread root kind` in `[Context]`")); + assert!(prompt.contains("only if the kind is unavailable")); assert!(prompt.contains("buzz messages thread --channel --event ")); - assert!(prompt.contains("Never send kind `45003` beneath a kind-`9` root")); + assert!(prompt.contains("Never send kind `45003` beneath stream roots")); } } diff --git a/crates/buzz-cli/src/lib.rs b/crates/buzz-cli/src/lib.rs index 2c137faab..3cb10f8bd 100644 --- a/crates/buzz-cli/src/lib.rs +++ b/crates/buzz-cli/src/lib.rs @@ -567,7 +567,7 @@ pub enum ChannelsCmd { }, /// Create a new channel #[command( - after_help = "Examples:\n buzz channels create --name general --type stream --visibility open\n buzz channels create --name design --type forum --visibility open --description \"Design discussions\"\n buzz channels create --name standup --type stream --visibility open --ttl 3600 # ephemeral, archived after 1h idle\n buzz channels create --name project-x --template \"Buzz Team\" # type/visibility/canvas/roster from the template; explicit flags override" + after_help = "Examples:\n buzz channels create --name general --type stream --visibility open\n buzz channels create --name standup --type stream --visibility open --ttl 3600 # ephemeral, archived after 1h idle\n buzz channels create --name project-x --template \"Buzz Team\" # type/visibility/canvas/roster from the template; explicit flags override\n\nUse stream unless the owner explicitly requests a forum. Forum channels are a preview feature and may be hidden for owners who have not enabled them." )] Create { /// Channel name diff --git a/desktop/src-tauri/src/managed_agents/nest.rs b/desktop/src-tauri/src/managed_agents/nest.rs index d1d85f281..5283b1a54 100644 --- a/desktop/src-tauri/src/managed_agents/nest.rs +++ b/desktop/src-tauri/src/managed_agents/nest.rs @@ -50,7 +50,7 @@ const NEST_AGENTS_VERSION: u32 = 4; /// Template content version for SKILL.md. /// Bump this when changing `nest_skill.md` to trigger refresh on existing installs. -const NEST_SKILL_VERSION: u32 = 6; +const NEST_SKILL_VERSION: u32 = 7; const BEGIN_MARKER: &str = ""; diff --git a/desktop/src-tauri/src/managed_agents/nest/tests.rs b/desktop/src-tauri/src/managed_agents/nest/tests.rs index 299b1af27..50722345f 100644 --- a/desktop/src-tauri/src/managed_agents/nest/tests.rs +++ b/desktop/src-tauri/src/managed_agents/nest/tests.rs @@ -41,12 +41,23 @@ fn nest_skill_contains_safe_mention_workflow() { assert!(BUZZ_CLI_SKILL_MD.contains("never changes membership automatically")); } +#[test] +fn nest_skill_defaults_channel_creation_to_stream() { + assert!(BUZZ_CLI_SKILL_MD.contains("buzz channels create --type stream")); + assert!(BUZZ_CLI_SKILL_MD.contains("unless the owner explicitly requests a forum")); + assert!(BUZZ_CLI_SKILL_MD.contains("may be hidden for owners who have not enabled them")); + assert!(BUZZ_CLI_SKILL_MD.contains("ask before using `--type forum`")); +} + #[test] fn nest_skill_contains_forum_workflow() { assert!(BUZZ_CLI_SKILL_MD.contains("forum root as kind `45001`")); assert!(BUZZ_CLI_SKILL_MD.contains("forum reply as kind `45003`")); assert!(BUZZ_CLI_SKILL_MD.contains("reply kind must match the thread root")); - assert!(BUZZ_CLI_SKILL_MD.contains("Never use kind `45003` beneath a kind-`9` root")); + assert!(BUZZ_CLI_SKILL_MD.contains( + "legacy kind-`40002`, reminder kind-`40007`, kind-`40008` diff, and workflow approval kind-`46010` stream roots" + )); + assert!(BUZZ_CLI_SKILL_MD.contains("Never use kind `45003` beneath stream roots")); } #[test] diff --git a/desktop/src-tauri/src/managed_agents/nest_skill.md b/desktop/src-tauri/src/managed_agents/nest_skill.md index 264b16743..c6f31b5ca 100644 --- a/desktop/src-tauri/src/managed_agents/nest_skill.md +++ b/desktop/src-tauri/src/managed_agents/nest_skill.md @@ -94,7 +94,9 @@ buzz messages send --channel \ --content "@Alice check this" --mention ``` -**Forum messages:** Forum roots and comments are distinct from stream messages, and the reply kind must match the thread root. Check the root kind before replying: omit `--kind` (or use kind `9`) beneath a kind-`9` stream root, even in a forum-capable channel. Send a forum root as kind `45001`; only beneath a kind-`45001` forum root, send a forum reply as kind `45003` with `--reply-to `. Never use kind `45003` beneath a kind-`9` root. +**Channel creation:** Use `buzz channels create --type stream` unless the owner explicitly requests a forum. Forum channels are a preview feature and may be hidden for owners who have not enabled them; ask before using `--type forum` when the request is ambiguous. + +**Forum messages:** Forum roots and comments are distinct from stream messages, and the reply kind must match the thread root. Check the root kind before replying: omit `--kind` (or use kind `9`) beneath kind-`9`, legacy kind-`40002`, reminder kind-`40007`, kind-`40008` diff, and workflow approval kind-`46010` stream roots, even in a forum-capable channel. Send a forum root as kind `45001`; only beneath a kind-`45001` forum root, send a forum reply as kind `45003` with `--reply-to `. Never use kind `45003` beneath stream roots. ```bash buzz messages send --channel --kind 45001 --content "New discussion"