From 8ae9ee19c625272033dc9c3ce9a7896f4f2e6045 Mon Sep 17 00:00:00 2001
From: Will Pfleger <wpfleger@block.xyz>
Date: Thu, 14 May 2026 14:53:03 -0400
Subject: [PATCH 01/18] feat: two-layer prompt architecture for managed agents
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Agents running in Sprout have no platform awareness — they don't know
about channels, MCP tools, @mention syntax, or the other agents in the
workspace. This adds a base layer prompt (compiled into sprout-acp via
include_str!) that gives every agent reliable Sprout context on every
turn, regardless of persona or runtime.

Base layer: platform identity, MCP tool reference, communication
patterns, workspace layout, startup recovery. Persona layer: unchanged
role-specific content (Solo/Kit/Scout behavioral protocols, worktree
discipline, quality bar).

Also adds default model (claude-sonnet-4-20250514) to all three
built-in personas so users don't need to pick at agent creation,
and fixes a merge_personas() bug where .is_some() checks would cause
infinite reset loops once built-ins carry non-None model values.
---
 crates/sprout-acp/src/base_prompt.md          |  35 +++++
 crates/sprout-acp/src/lib.rs                  |   5 +
 crates/sprout-acp/src/pool.rs                 |   2 +
 crates/sprout-acp/src/queue.rs                |  55 +++++++-
 crates/sprout-persona/PERSONA_PACK_SPEC.md    | 133 ++++++++++++++----
 .../src-tauri/src/managed_agents/personas.rs  |  12 +-
 6 files changed, 205 insertions(+), 37 deletions(-)
 create mode 100644 crates/sprout-acp/src/base_prompt.md

diff --git a/crates/sprout-acp/src/base_prompt.md b/crates/sprout-acp/src/base_prompt.md
new file mode 100644
index 0000000000..852d375535
--- /dev/null
+++ b/crates/sprout-acp/src/base_prompt.md
@@ -0,0 +1,35 @@
+You are operating inside the Sprout platform — a Nostr-based messaging platform for human-agent collaboration. The sprout-acp harness bridges channel events to your session.
+
+## MCP Tools
+
+- `get_messages(channel_id, limit=50)` — fetch recent history (max 200 per call)
+- `get_messages(channel_id, since=<unix_ts>)` — fetch messages since timestamp; returns oldest-first when `since` is set without `before`
+- `get_thread(channel_id, event_id)` — fetch a full thread by root event ID
+- `get_feed()` — personalized feed of mentions and needs-action items across all channels
+- `send_message(channel_id, content)` — post a new message to a channel
+- `send_message(channel_id, content, parent_event_id)` — reply within an existing thread
+- `search(q="your query")` — cross-channel full-text search
+
+## Communication Patterns
+
+- Address agents and humans with `@name` in message content.
+- Use `parent_event_id` when responding to a thread; post a new message for new topics.
+- There are no push notifications — poll for new messages using `since=<last_seen_ts>`.
+
+## Startup Recovery
+
+On startup or after a gap: call `get_feed()` first to surface pending mentions and action items, then call `get_messages` on your assigned channels to catch up, then check the workspace `AGENTS.md` for team context.
+
+## Workspace Layout
+
+Persistent workspace at `$AGENT_CWD/` with the following directories:
+
+- `RESEARCH/` — findings and reference material
+- `PLANS/` — project and task plans
+- `GUIDES/` — how-to documentation
+- `WORK_LOGS/` — timestamped activity logs
+- `OUTBOX/` — drafts pending review or send
+- `REPOS/` — checked-out source repositories
+- `.scratch/` — ephemeral working files
+
+Knowledge files use `ALL_CAPS_WITH_UNDERSCORES.md` naming and YAML frontmatter. `AGENTS.md` in the working directory lists active agents and their assigned roles.
diff --git a/crates/sprout-acp/src/lib.rs b/crates/sprout-acp/src/lib.rs
index 9de5586bd6..73734b7b29 100644
--- a/crates/sprout-acp/src/lib.rs
+++ b/crates/sprout-acp/src/lib.rs
@@ -1076,6 +1076,11 @@ async fn tokio_main() -> Result<()> {
         max_turn_duration: Duration::from_secs(config.max_turn_duration_secs),
         dedup_mode: config.dedup_mode,
         system_prompt: config.system_prompt.clone(),
+        base_prompt: if std::env::var("SPROUT_ACP_BASE_PROMPT_DISABLED").is_ok() {
+            None
+        } else {
+            Some(include_str!("base_prompt.md").to_string())
+        },
         heartbeat_prompt: config.heartbeat_prompt.clone(),
         cwd: std::env::current_dir()
             .unwrap_or_else(|_| std::path::PathBuf::from("/"))
diff --git a/crates/sprout-acp/src/pool.rs b/crates/sprout-acp/src/pool.rs
index a4c8ba1f49..d0be9e25ab 100644
--- a/crates/sprout-acp/src/pool.rs
+++ b/crates/sprout-acp/src/pool.rs
@@ -192,6 +192,7 @@ pub struct PromptContext {
     pub dedup_mode: DedupMode,
     pub system_prompt: Option<String>,
     pub heartbeat_prompt: Option<String>,
+    pub base_prompt: Option<String>,
     pub cwd: String,
     /// REST client for pre-prompt context fetches (thread/DM history).
     pub rest_client: RestClient,
@@ -931,6 +932,7 @@ pub async fn run_prompt_task(
         let agent_core_section = agent.state.core_sections.get(&b.channel_id).cloned();
         crate::queue::format_prompt(
             b,
+            ctx.base_prompt.as_deref(),
             ctx.system_prompt.as_deref(),
             agent_core_section.as_deref(),
             channel_info.as_ref(),
diff --git a/crates/sprout-acp/src/queue.rs b/crates/sprout-acp/src/queue.rs
index 6847f6bb98..d97ef42b23 100644
--- a/crates/sprout-acp/src/queue.rs
+++ b/crates/sprout-acp/src/queue.rs
@@ -928,12 +928,14 @@ fn format_conversation_context(
 /// Format a [`FlushBatch`] into a prompt string for the agent.
 ///
 /// Produces a stable prompt with these sections (in order):
-/// 1. `[System]` — system prompt (if configured)
-/// 2. `[Context]` — scope, channel name, structural hints
+/// 0. `[Base]\n{base_prompt}` — platform orientation (if configured)
+/// 1. `[System]\n{system_prompt}` — if system prompt is set
+/// 2. `[Context]` — scope, channel name, and contextual hints for the agent
 /// 3. `[Thread Context]` or `[Conversation Context]` — if fetched
 /// 4. `[Event]` / `[Sprout events]` — the triggering event(s)
 pub fn format_prompt(
     batch: &FlushBatch,
+    base_prompt: Option<&str>,
     system_prompt: Option<&str>,
     agent_core: Option<&str>,
     channel_info: Option<&PromptChannelInfo>,
@@ -956,7 +958,12 @@ pub fn format_prompt(
         .map(|ci| ci.channel_type == "dm")
         .unwrap_or(false);
 
-    let mut sections: Vec<String> = Vec::with_capacity(4);
+    let mut sections: Vec<String> = Vec::with_capacity(5);
+
+    // 0. Base prompt (platform-level, always first).
+    if let Some(bp) = base_prompt {
+        sections.push(format!("[Base]\n{bp}"));
+    }
 
     // 1. System prompt.
     if let Some(sp) = system_prompt {
@@ -1392,6 +1399,7 @@ mod tests {
 
         let prompt = format_prompt(
             &batch,
+            None,
             Some("You are a triage bot."),
             None,
             None,
@@ -1417,7 +1425,7 @@ mod tests {
             cancelled_events: vec![],
         };
         let core = "[Agent Memory — core]\nbe helpful";
-        let prompt = format_prompt(&batch, Some("sys"), Some(core), None, None, None);
+        let prompt = format_prompt(&batch, None, Some("sys"), Some(core), None, None, None);
         assert!(
             prompt.contains("[System]\nsys\n\n[Agent Memory — core]\nbe helpful"),
             "expected core block after [System]; got: {prompt}"
@@ -1438,10 +1446,47 @@ mod tests {
             cancelled_events: vec![],
         };
         let core = "[Agent Memory — core]\nbe helpful";
-        let prompt = format_prompt(&batch, None, Some(core), None, None, None);
+        let prompt = format_prompt(&batch, None, None, Some(core), None, None, None);
         assert!(prompt.starts_with("[Agent Memory — core]\nbe helpful\n\n[Context]"));
     }
 
+    // ── Test 11c: base prompt prepended before system prompt ─────────────────
+
+    #[test]
+    fn test_format_prompt_with_base_prompt() {
+        let ch = Uuid::new_v4();
+        let event = make_event("hello");
+
+        let batch = FlushBatch {
+            channel_id: ch,
+            events: vec![BatchEvent {
+                event,
+                prompt_tag: "test".into(),
+                received_at: Instant::now(),
+            }],
+            cancelled_events: vec![],
+        };
+
+        // Both base_prompt and system_prompt: [Base] comes first, then [System].
+        let prompt = format_prompt(
+            &batch,
+            Some("Platform base."),
+            Some("Role prompt."),
+            None,
+            None,
+            None,
+            None,
+        );
+        assert!(prompt.starts_with("[Base]\nPlatform base.\n\n[System]\nRole prompt."));
+
+        // Only base_prompt (no system_prompt): [Base] comes first, then [Context].
+        let prompt = format_prompt(&batch, Some("Platform base."), None, None, None, None, None);
+        assert!(prompt.starts_with("[Base]\nPlatform base.\n\n[Context]"));
+
+        // No base_prompt: no [Base] section emitted.
+        let prompt = format_prompt(&batch, None, None, None, None, None, None);
+        assert!(!prompt.contains("[Base]"));
+    }
     // ── Test 12: drop mode discards in-flight channel events ─────────────────
 
     #[test]
diff --git a/crates/sprout-persona/PERSONA_PACK_SPEC.md b/crates/sprout-persona/PERSONA_PACK_SPEC.md
index cbbeaecff2..5ffc961abd 100644
--- a/crates/sprout-persona/PERSONA_PACK_SPEC.md
+++ b/crates/sprout-persona/PERSONA_PACK_SPEC.md
@@ -94,7 +94,7 @@ none of them override it.
 - **Extension mechanism**: Sprout-specific fields sit at the top level of `plugin.json` alongside
   OPS fields. No OPS core field is overloaded.
 - **`defaults`**: ignored entirely by OPS consumers. sprout-acp resolves it at deploy time before
-  constructing per-persona configurations (see Section 9 and Section 11).
+  constructing per-persona configurations (see Section 10 and Section 12).
 
 ---
 
@@ -129,7 +129,7 @@ my-pack/
 
 - `agents/` — all persona files. No nesting; flat directory.
 - `skills/` — one subdirectory per skill. Each skill directory contains a `SKILL.md` file.
-  Both `name:` and `description:` frontmatter fields are **required** — see Section 5.
+  Both `name:` and `description:` frontmatter fields are **required** — see Section 6.
 - `.plugin/` — OPS-required location for the manifest.
 - `hooks/` — optional; omit if no hooks are needed.
 - `instructions.md` — optional; omit if no pack-level instructions.
@@ -146,7 +146,7 @@ A persona file is a markdown document with YAML frontmatter. The **YAML frontmat
 identity, skills, MCP servers, and behavioral config. The **markdown body** (everything after the
 closing `---`) is the agent's persona prompt text.
 
-> **Note**: The persona prompt is currently delivered as a `[System]` prefix in the user message text (see Section 11). True system prompt injection (once at session creation rather than every turn) is planned — see Section 15.
+> **Note**: The persona prompt is currently delivered as a `[System]` prefix in the user message text (see Section 12). True system prompt injection (once at session creation rather than every turn) is planned — see Section 16.
 
 ### Full Schema
 
@@ -209,14 +209,14 @@ You are Lep, a security-focused code reviewer on the Meadow team.
 | `author` | string | ❌ | OPS compatibility field. |
 | `skills` | string[] | ❌ | Pack-relative paths to skill directories for this agent only. |
 | `mcp_servers` | object[] | ❌ | Per-persona MCP servers. Merged with pack-level `.mcp.json`. |
-| `subscribe` | string[] | ❌ | Channels to monitor. See Section 9. |
-| `triggers` | object | ❌ | Controls which messages activate a response. See Section 9. |
-| `model` | string | ❌ | Model to use. See Section 9. |
-| `temperature` | float | ❌ | Sampling temperature. See Section 9. |
-| `max_context_tokens` | int | ❌ | Context window limit. See Section 9. |
-| `thread_replies` | bool | ❌ | Reply in-thread when triggering message is in a thread. See Section 9. |
-| `broadcast_replies` | bool | ❌ | Surface thread replies to the main channel. See Section 9. |
-| `hooks` | object | ❌ | Lifecycle hooks. Harness-managed. See Section 8. |
+| `subscribe` | string[] | ❌ | Channels to monitor. See Section 10. |
+| `triggers` | object | ❌ | Controls which messages activate a response. See Section 10. |
+| `model` | string | ❌ | Model to use. See Section 10. |
+| `temperature` | float | ❌ | Sampling temperature. See Section 10. |
+| `max_context_tokens` | int | ❌ | Context window limit. See Section 10. |
+| `thread_replies` | bool | ❌ | Reply in-thread when triggering message is in a thread. See Section 10. |
+| `broadcast_replies` | bool | ❌ | Surface thread replies to the main channel. See Section 10. |
+| `hooks` | object | ❌ | Lifecycle hooks. Harness-managed. See Section 9. |
 
 > **Legacy alias**: The YAML key `respond_to` is accepted as an alias for `triggers` in persona frontmatter. In `plugin.json` defaults, both `triggers` and `respond_to` are accepted. The canonical key is `triggers`.
 
@@ -228,7 +228,86 @@ files (agent runtimes typically do not read them).
 
 ---
 
-## 5. Skills
+## 5. Two-Layer Prompt Architecture
+
+sprout-acp assembles the agent's context from two distinct prompt layers before sending each
+message. Understanding this layering is essential for persona authors — content that belongs in
+one layer should not be duplicated in the other.
+
+### Prompt Section Order
+
+Each message delivered to the agent runtime includes these sections in order:
+
+```
+[Base]
+<platform orientation — injected by sprout-acp>
+
+[System]
+<persona prompt — markdown body of .persona.md>
+
+---
+# Team Instructions
+<contents of instructions.md, if present>
+
+[Context]
+<workspace layout, available skills, MCP tool reference>
+
+[Thread/Conversation Context]
+<recent message history, if applicable>
+
+[Sprout event]
+<the triggering message or event>
+```
+
+### The `[Base]` Layer
+
+The `[Base]` layer is compiled into sprout-acp and is **identical for every agent**. It covers:
+
+| Content | Purpose |
+|---------|---------|
+| Platform identity | Tells the agent it is running inside Sprout and what that means |
+| MCP tool reference | Documents the tools available via the connected MCP servers |
+| Workspace layout | Describes `$AGENT_CWD`, skill discovery paths, and file conventions |
+| Message polling | Explains how to check for new messages proactively |
+
+Pack authors do not write or configure the `[Base]` layer — it is maintained by the Sprout team
+and updated in sprout-acp releases.
+
+**Disabling the base layer**: Set `SPROUT_ACP_BASE_PROMPT_DISABLED=1` in the sprout-acp process
+environment to omit the `[Base]` section entirely. This is intended for testing and advanced
+deployments where operators supply their own platform context.
+
+### The `[System]` Layer
+
+The `[System]` layer is the persona prompt — the markdown body of the `.persona.md` file. It is
+**unique per agent** and defines the agent's role, identity, and behavioral rules. This is where
+pack authors write their persona content.
+
+What belongs in `[System]`:
+
+| Content | Examples |
+|---------|---------|
+| Agent name and role | "You are Lep, a security-focused code reviewer" |
+| Team protocols | Escalation rules, @-mention discipline, handoff conventions |
+| Domain rules | Security checklists, review criteria, coding standards |
+| Behavioral autonomy | When to act independently vs. when to ask |
+
+### Guidance for Pack Authors
+
+**Do not duplicate base layer content in persona prompts.** Users with the base layer enabled
+(the default) would see that content twice per message. Specifically, do not re-explain:
+
+- How to use MCP tools (covered by `[Base]`)
+- How to poll for new messages or use the `since` parameter (covered by `[Base]`)
+- Workspace layout or skill loading mechanics (covered by `[Base]`)
+- That the agent is running inside Sprout (covered by `[Base]`)
+
+Focus persona prompts on what makes this agent unique: its role, personality, domain expertise,
+and team-specific protocols.
+
+---
+
+## 6. Skills
 
 > **Implementation note**: Skill paths are stored as declared in persona frontmatter. Resolution
 > to `SKILL.md` `name:` fields and runtime copying to `$AGENT_CWD/.agents/skills/` is planned
@@ -323,7 +402,7 @@ load(source: "security-review")
 ```
 
 sprout-acp lists available skills in the user message prefix so the agent knows what's available.
-See Section 11 for the full message format.
+See Section 12 for the full message format.
 
 ### Skill File Format
 
@@ -344,7 +423,7 @@ enforce required metadata fields (see PF-5).
 
 ---
 
-## 6. MCP Server Configuration
+## 7. MCP Server Configuration
 
 MCP servers provide external tool access (GitHub, Semgrep, databases, etc.). Configuration is
 defined at two levels: pack-level (shared across all agents) and per-persona (agent-specific).
@@ -408,13 +487,13 @@ sprout-acp passes the merged config via `NewSessionRequest.mcp_servers`. **No `.
 
 ---
 
-## 7. Pack-Level Instructions
+## 8. Pack-Level Instructions
 
 `instructions.md` contains shared rules, coding standards, and team norms that apply to all agents
 in the pack. sprout-acp appends it to the persona prompt in the user message prefix.
 
 sprout-acp appends `instructions.md` to the persona prompt in the user message prefix (see
-Section 11). **No file is written to disk.**
+Section 12). **No file is written to disk.**
 
 **What does NOT work**: `.mdc` rule files (agent runtimes typically don't read them), `rules/` directory (no
 `--rules-dir` flag), relying on the pack's `AGENTS.md` for runtime injection (it's for human
@@ -426,7 +505,7 @@ contributors only).
 
 ---
 
-## 8. Lifecycle Hooks
+## 9. Lifecycle Hooks
 
 > **Implementation note**: Hooks are parsed and validated at pack load time but not yet executed.
 > Hook execution is planned for a future release.
@@ -492,7 +571,7 @@ sprout-acp means no hooks fire.
 
 ---
 
-## 9. Behavioral Configuration
+## 10. Behavioral Configuration
 
 The behavioral config fields in a persona's frontmatter control how the agent participates in
 Sprout conversations. These are all Sprout-specific — the agent runtime has no awareness of them. They sit
@@ -763,7 +842,7 @@ All fields are consumed entirely by sprout-acp. None are passed to the agent run
 
 ---
 
-## 10. Distribution
+## 11. Distribution
 
 ### Phase 1: Zip File
 
@@ -845,7 +924,7 @@ The Sprout desktop app can import persona packs via the Import button:
 
 ---
 
-## 11. Delivery Mechanism Summary
+## 12. Delivery Mechanism Summary
 
 How each pack component reaches the running agent:
 
@@ -862,7 +941,7 @@ How each pack component reaches the running agent:
 
 > **Pack defaults are resolved at deploy time**, not at runtime. When sprout-acp loads a pack and
 > constructs per-persona session configurations, it merges the `defaults` object with each persona's
-> frontmatter behavioral config fields (per the precedence model in Section 9) and stores the
+> frontmatter behavioral config fields (per the precedence model in Section 10) and stores the
 > resulting effective configuration. The `defaults` object itself is not forwarded to the agent runtime or
 > stored in any runtime artifact — only the resolved per-persona values are used.
 
@@ -892,7 +971,7 @@ Load a skill with: load(source: "skill-name")
 
 The `[System]` prefix re-sends the full persona prompt on every turn. True system prompt injection
 — calling `agent.extend_system_prompt()` after `create_agent_for_session()` in `on_new_session()`
-— fires once at session creation. This is planned work; see Section 15.
+— fires once at session creation. This is planned work; see Section 16.
 
 ### What Does NOT Work (Anti-Pattern Reference)
 
@@ -911,12 +990,12 @@ The `[System]` prefix re-sends the full persona prompt on every turn. True syste
 
 ---
 
-## 12. Security Considerations
+## 13. Security Considerations
 
 ### Secret Management
 
 Never embed secrets in pack files. Use `${VAR_NAME}` references in all `env` blocks. Currently,
-`${VAR_NAME}` strings are passed through as literals to the agent runtime (see Section 6). When
+`${VAR_NAME}` strings are passed through as literals to the agent runtime (see Section 7). When
 harness-side interpolation is implemented, sprout-acp will resolve them from the process
 environment at startup and refuse to start if any are unresolved. Inject secrets via your
 deployment mechanism (systemd env files, Vault, Kubernetes secrets, etc.).
@@ -944,7 +1023,7 @@ both with the same caution as any untrusted prompt content.
 
 ---
 
-## 13. Migration Path
+## 14. Migration Path
 
 ### From V6 (sprout-namespaced) Format
 
@@ -1022,7 +1101,7 @@ The V6 namespaced `sprout:` block format is not supported. Only the current flat
 
 ---
 
-## 14. Open Questions / Future Work
+## 15. Open Questions / Future Work
 
 ### Unresolved
 
@@ -1052,7 +1131,7 @@ The V6 namespaced `sprout:` block format is not supported. Only the current flat
 
 ---
 
-## 15. Planned Features
+## 16. Planned Features
 
 Features required by this spec but not yet implemented.
 
diff --git a/desktop/src-tauri/src/managed_agents/personas.rs b/desktop/src-tauri/src/managed_agents/personas.rs
index b3cc61ae6e..55899f7484 100644
--- a/desktop/src-tauri/src/managed_agents/personas.rs
+++ b/desktop/src-tauri/src/managed_agents/personas.rs
@@ -14,6 +14,7 @@ struct BuiltInPersona {
     avatar_url: Option<&'static str>,
     system_prompt: &'static str,
     name_pool: &'static [&'static str],
+    model: Option<&'static str>,
 }
 
 const SOLO_AVATAR: &str = "data:image/png;base64,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";
@@ -110,7 +111,6 @@ Surface to the user only when:
   - After **fixes**: what was addressed before re-review.
 - **Between phase updates**, stay quiet while things go well. The Autonomy section above governs when to surface a question vs. resolve it independently — default to resolving.
 - For longer phases, post a one-line progress update roughly every 15 minutes so the user knows you're alive.
-- In a Sprout channel, check for new messages proactively (use your read tools with the `since` parameter) so you don't miss the user trying to talk to you.
 - **Completion** — Concise final report:
   - What changed and why
   - Files changed
@@ -146,6 +146,7 @@ const BUILT_IN_PERSONAS: &[BuiltInPersona] = &[
             "Atlas", "Ember", "Flint", "Sage", "Drift", "Quill", "Wren", "Cedar", "Pike", "Lark",
             "Birch", "Dune", "Fern", "Moss", "Reed", "Slate", "Ash", "Brook", "Glen", "Stone",
         ],
+        model: Some("claude-sonnet-4-20250514"),
     },
     BuiltInPersona {
         id: "builtin:kit",
@@ -269,7 +270,6 @@ Surface to the user only when:
 - **Between phase updates**, stay quiet while things go well. Default to resolving via the Autonomy ladder.
 - For longer phases, post a one-line progress update roughly every 15 minutes so the user knows you're alive.
 - `@scout` follows the @-Mention Discipline rules at the top of this prompt — only on real assignment messages (new assignment, focused fix after COMPLETE/BLOCKED, or answer to a specific blocker), with the structured fields attached. Never `@mention` Scout twice for the same active phase.
-- In a Sprout channel, check for new messages proactively (use your read tools with the `since` parameter) so you don't miss the user trying to talk to you.
 - **Completion** — Concise final report:
   - What changed and why
   - Files changed
@@ -294,6 +294,7 @@ Aim for 9/10+ on the first pass. There is no separate refactoring pass — if it
 Don't present work that doesn't meet this bar. No emojis.
 
 Your name is Kit. You are friendly and helpful. You are understated, but have a sense of humor."#,
+        model: Some("claude-sonnet-4-20250514"),
     },
     BuiltInPersona {
         id: "builtin:scout",
@@ -452,6 +453,7 @@ You are read-only, but you still resolve questions yourself before pinging Kit:
 If you're invoked outside a Sprout team channel (or by an agent that isn't Kit), apply the same protocols. Default to FULL REVIEW for completed work or PLAN REVIEW + RESEARCH for plans. Report to whoever invoked you.
 
 Your name is Scout. You are friendly and helpful. You are understated, but have a sense of humor."#,
+        model: Some("claude-sonnet-4-20250514"),
     },
 ];
 
@@ -468,7 +470,7 @@ fn built_in_persona_records(now: &str) -> Vec<PersonaRecord> {
             avatar_url: persona.avatar_url.map(|s| s.to_string()),
             system_prompt: persona.system_prompt.to_string(),
             provider: None,
-            model: None,
+            model: persona.model.map(|s| s.to_string()),
             name_pool: persona.name_pool.iter().map(|s| s.to_string()).collect(),
             is_builtin: true,
             is_active: true,
@@ -522,8 +524,8 @@ fn merge_personas(mut stored: Vec<PersonaRecord>, now: &str) -> (Vec<PersonaReco
                 || existing.system_prompt != built_in.system_prompt
                 || existing.name_pool != built_in.name_pool
                 || existing.env_vars != built_in.env_vars
-                || existing.provider.is_some()
-                || existing.model.is_some()
+                || existing.provider != built_in.provider
+                || existing.model != built_in.model
                 || !existing.is_builtin
             {
                 *existing = PersonaRecord {

From fec3b7363d2b634f7d0f869a8d8b212278eb11ca Mon Sep 17 00:00:00 2001
From: Will Pfleger <wpfleger@block.xyz>
Date: Thu, 14 May 2026 16:19:44 -0400
Subject: [PATCH 02/18] fix: address all review feedback on two-layer prompt
 architecture
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Consolidated fixes from 5 independent reviewers (3 Claude specialists,
Codex/GPT-5.5, Gemini) plus PLAN author feedback.

Structural: refactor format_prompt() from 6 positional params to
FormatPromptArgs struct — eliminates positional confusion and makes
future additions zero-cost for existing call sites.

Correctness: replace get_channel_history() references in [Context]
hints with get_messages() (the actual MCP tool name), fix $AGENT_CWD
reference in base_prompt.md (env var doesn't exist), fix [Context]
description in PERSONA_PACK_SPEC to match reality.

Config: migrate SPROUT_ACP_BASE_PROMPT_DISABLED from bare env::var
check to proper Config field (no_base_prompt), add base_prompt_file
for runtime override. Change base_prompt type from Option<String> to
Option<&'static str> to reflect compile-time constant nature.

Personas: add provider: Some("claude") alongside model on all three
built-in personas so the UI/runtime agree on the backend. Add comment
documenting merge_personas() canonical-override semantics.

Coverage: prepend [Base] to heartbeat and initial_message paths that
previously bypassed format_prompt(). Add section-ordering test with
full context. Fix trailing-newline triple-gap via trim_end().
---
 crates/sprout-acp/README.md                   |   2 +-
 crates/sprout-acp/src/base_prompt.md          |   6 +-
 crates/sprout-acp/src/config.rs               |  22 ++
 crates/sprout-acp/src/lib.rs                  |  15 +-
 crates/sprout-acp/src/pool.rs                 |  23 +-
 crates/sprout-acp/src/queue.rs                | 265 +++++++++++++-----
 crates/sprout-persona/PERSONA_PACK_SPEC.md    |   8 +-
 .../src-tauri/src/managed_agents/personas.rs  |   9 +-
 8 files changed, 264 insertions(+), 86 deletions(-)

diff --git a/crates/sprout-acp/README.md b/crates/sprout-acp/README.md
index ecd66bd66e..b72c2f6ade 100644
--- a/crates/sprout-acp/README.md
+++ b/crates/sprout-acp/README.md
@@ -237,7 +237,7 @@ Forum event kinds:
 2. **Channel discovery** — Queries the relay REST API for accessible channels, subscribes to each.
 3. **Event loop** — Listens for @mention events (kind 9 with the agent's pubkey in a `#p` tag). Events queue per channel.
 4. **Prompting** — When events are pending and no prompt is in flight for that channel, drains all queued events for the oldest channel into a single batched prompt via ACP `session/prompt`.
-5. **Agent response** — The agent processes the prompt and uses Sprout MCP tools (`send_message`, `get_channel_history`, etc.) to interact with Sprout.
+5. **Agent response** — The agent processes the prompt and uses Sprout MCP tools (`send_message`, `get_messages`, etc.) to interact with Sprout.
 6. **Recovery** — If the agent crashes, the harness respawns it. If the relay disconnects, the harness reconnects with a `since` filter to avoid missing events.
 
 Each channel has at most one prompt in flight. Multiple channels can be processed concurrently when agents > 1.
diff --git a/crates/sprout-acp/src/base_prompt.md b/crates/sprout-acp/src/base_prompt.md
index 852d375535..b9a0a49085 100644
--- a/crates/sprout-acp/src/base_prompt.md
+++ b/crates/sprout-acp/src/base_prompt.md
@@ -1,6 +1,6 @@
 You are operating inside the Sprout platform — a Nostr-based messaging platform for human-agent collaboration. The sprout-acp harness bridges channel events to your session.
 
-## MCP Tools
+## MCP Tools (via `sprout-mcp`)
 
 - `get_messages(channel_id, limit=50)` — fetch recent history (max 200 per call)
 - `get_messages(channel_id, since=<unix_ts>)` — fetch messages since timestamp; returns oldest-first when `since` is set without `before`
@@ -18,11 +18,11 @@ You are operating inside the Sprout platform — a Nostr-based messaging platfor
 
 ## Startup Recovery
 
-On startup or after a gap: call `get_feed()` first to surface pending mentions and action items, then call `get_messages` on your assigned channels to catch up, then check the workspace `AGENTS.md` for team context.
+On startup or after a gap: call `get_feed()` first to surface pending mentions and action items, then call `get_messages` on your assigned channels to catch up, then check `AGENTS.md` for team context. Use `search()` for cross-channel keyword lookups when you need to find specific prior discussions.
 
 ## Workspace Layout
 
-Persistent workspace at `$AGENT_CWD/` with the following directories:
+Your persistent workspace is in your working directory, with the following subdirectories:
 
 - `RESEARCH/` — findings and reference material
 - `PLANS/` — project and task plans
diff --git a/crates/sprout-acp/src/config.rs b/crates/sprout-acp/src/config.rs
index fe2d2fd809..6bbff8fa9a 100644
--- a/crates/sprout-acp/src/config.rs
+++ b/crates/sprout-acp/src/config.rs
@@ -352,6 +352,20 @@ pub struct CliArgs {
     )]
     pub no_memory: bool,
 
+    /// Disable the [Base] platform-context section prepended to every prompt.
+    /// When set, agents receive only the persona [System] prompt with no Sprout orientation.
+    #[arg(long, env = "SPROUT_ACP_NO_BASE_PROMPT")]
+    pub no_base_prompt: bool,
+
+    /// Path to a custom base prompt file. Overrides the compiled-in default.
+    /// Mutually exclusive with --no-base-prompt.
+    #[arg(
+        long,
+        env = "SPROUT_ACP_BASE_PROMPT_FILE",
+        conflicts_with = "no_base_prompt"
+    )]
+    pub base_prompt_file: Option<PathBuf>,
+
     /// Desired LLM model ID. Applied to every new ACP session after creation.
     /// Use `sprout-acp models` to discover available model IDs.
     #[arg(long, env = "SPROUT_ACP_MODEL")]
@@ -461,6 +475,10 @@ pub struct Config {
     /// Agent owner pubkey (hex). Used for `--respond-to=owner-only` gate.
     /// Replaces the old REST-based owner lookup.
     pub agent_owner: Option<String>,
+    /// Disable the [Base] platform-context section prepended to every prompt.
+    pub no_base_prompt: bool,
+    /// Path to a custom base prompt file that overrides the compiled-in default.
+    pub base_prompt_file: Option<PathBuf>,
 }
 
 /// Validate and deduplicate allowlist entries: each must be exactly 64 hex chars.
@@ -798,6 +816,8 @@ impl Config {
             persona_env_vars,
             relay_observer: args.relay_observer,
             agent_owner: args.agent_owner.map(|s| s.trim().to_ascii_lowercase()),
+            no_base_prompt: args.no_base_prompt,
+            base_prompt_file: args.base_prompt_file,
         };
 
         Ok(config)
@@ -1161,6 +1181,8 @@ mod tests {
             persona_env_vars: vec![],
             relay_observer: false,
             agent_owner: None,
+            no_base_prompt: false,
+            base_prompt_file: None,
         }
     }
 
diff --git a/crates/sprout-acp/src/lib.rs b/crates/sprout-acp/src/lib.rs
index 73734b7b29..a57853837a 100644
--- a/crates/sprout-acp/src/lib.rs
+++ b/crates/sprout-acp/src/lib.rs
@@ -1076,10 +1076,15 @@ async fn tokio_main() -> Result<()> {
         max_turn_duration: Duration::from_secs(config.max_turn_duration_secs),
         dedup_mode: config.dedup_mode,
         system_prompt: config.system_prompt.clone(),
-        base_prompt: if std::env::var("SPROUT_ACP_BASE_PROMPT_DISABLED").is_ok() {
+        base_prompt: if config.no_base_prompt {
             None
+        } else if let Some(ref path) = config.base_prompt_file {
+            let content = std::fs::read_to_string(path).unwrap_or_else(|e| {
+                panic!("failed to read base prompt file {}: {e}", path.display())
+            });
+            Some(Box::leak(content.into_boxed_str()))
         } else {
-            Some(include_str!("base_prompt.md").to_string())
+            Some(include_str!("base_prompt.md"))
         },
         heartbeat_prompt: config.heartbeat_prompt.clone(),
         cwd: std::env::current_dir()
@@ -2319,6 +2324,10 @@ fn dispatch_heartbeat(
         .heartbeat_prompt
         .clone()
         .unwrap_or_else(default_heartbeat_prompt);
+    let prompt_text = match ctx.base_prompt {
+        Some(bp) => format!("[Base]\n{}\n\n{prompt_text}", bp.trim_end()),
+        None => prompt_text,
+    };
     let result_tx = pool.result_tx();
     let ctx_clone = Arc::clone(ctx);
     let agent_index = agent.index;
@@ -2813,6 +2822,8 @@ mod build_mcp_servers_tests {
             persona_env_vars: vec![],
             relay_observer: false,
             agent_owner: None,
+            no_base_prompt: false,
+            base_prompt_file: None,
         }
     }
 
diff --git a/crates/sprout-acp/src/pool.rs b/crates/sprout-acp/src/pool.rs
index d0be9e25ab..7b8ce93ac0 100644
--- a/crates/sprout-acp/src/pool.rs
+++ b/crates/sprout-acp/src/pool.rs
@@ -192,7 +192,7 @@ pub struct PromptContext {
     pub dedup_mode: DedupMode,
     pub system_prompt: Option<String>,
     pub heartbeat_prompt: Option<String>,
-    pub base_prompt: Option<String>,
+    pub base_prompt: Option<&'static str>,
     pub cwd: String,
     /// REST client for pre-prompt context fetches (thread/DM history).
     pub rest_client: RestClient,
@@ -804,11 +804,16 @@ pub async fn run_prompt_task(
                 target: "pool::session",
                 "sending initial_message to session {session_id} for channel {cid}"
             );
+            // Prepend base prompt to initial_message for platform orientation.
+            let init_msg = match ctx.base_prompt {
+                Some(bp) => format!("[Base]\n{}\n\n{initial_msg}", bp.trim_end()),
+                None => initial_msg.to_string(),
+            };
             let init_result = agent
                 .acp
                 .session_prompt_with_idle_timeout(
                     &session_id,
-                    initial_msg,
+                    &init_msg,
                     ctx.idle_timeout,
                     ctx.max_turn_duration,
                 )
@@ -932,12 +937,14 @@ pub async fn run_prompt_task(
         let agent_core_section = agent.state.core_sections.get(&b.channel_id).cloned();
         crate::queue::format_prompt(
             b,
-            ctx.base_prompt.as_deref(),
-            ctx.system_prompt.as_deref(),
-            agent_core_section.as_deref(),
-            channel_info.as_ref(),
-            conversation_context.as_ref(),
-            profile_lookup.as_ref(),
+            &crate::queue::FormatPromptArgs {
+                base_prompt: ctx.base_prompt,
+                system_prompt: ctx.system_prompt.as_deref(),
+                agent_core: agent_core_section.as_deref(),
+                channel_info: channel_info.as_ref(),
+                conversation_context: conversation_context.as_ref(),
+                profile_lookup: profile_lookup.as_ref(),
+            },
         )
     } else {
         // Should not happen — batch is None only for heartbeats which have prompt_text.
diff --git a/crates/sprout-acp/src/queue.rs b/crates/sprout-acp/src/queue.rs
index d97ef42b23..feeffbd03e 100644
--- a/crates/sprout-acp/src/queue.rs
+++ b/crates/sprout-acp/src/queue.rs
@@ -829,15 +829,15 @@ fn format_context_hints(
     if is_dm {
         let is_reply = thread_tags.root_event_id.is_some();
         // DM replies use get_thread() because /messages excludes thread replies.
-        // DM non-replies use get_channel_history() for recent conversation.
+        // DM non-replies use get_messages() for recent conversation.
         let ctx_hint = if has_conversation_context && is_reply {
             "Thread context included below. Use get_thread() for full history if truncated."
         } else if has_conversation_context {
-            "Conversation context included below. Use get_channel_history() for full history if truncated."
+            "Conversation context included below. Use get_messages() for full history if truncated."
         } else if is_reply {
             "Use get_thread() to fetch the reply chain."
         } else {
-            "Use get_channel_history() for conversation context."
+            "Use get_messages() for conversation context."
         };
         let mut s = format!(
             "[Context]\n\
@@ -885,7 +885,7 @@ fn format_context_hints(
             "[Context]\n\
              Scope: channel\n\
              Channel: {channel_display}\n\
-             Hint: Use get_channel_history() for recent messages if needed."
+             Hint: Use get_messages() for recent messages if needed."
         )
     }
 }
@@ -925,6 +925,17 @@ fn format_conversation_context(
     s
 }
 
+/// Arguments for [`format_prompt`] beyond the required [`FlushBatch`].
+#[derive(Default)]
+pub struct FormatPromptArgs<'a> {
+    pub base_prompt: Option<&'a str>,
+    pub system_prompt: Option<&'a str>,
+    pub agent_core: Option<&'a str>,
+    pub channel_info: Option<&'a PromptChannelInfo>,
+    pub conversation_context: Option<&'a ConversationContext>,
+    pub profile_lookup: Option<&'a PromptProfileLookup>,
+}
+
 /// Format a [`FlushBatch`] into a prompt string for the agent.
 ///
 /// Produces a stable prompt with these sections (in order):
@@ -933,15 +944,7 @@ fn format_conversation_context(
 /// 2. `[Context]` — scope, channel name, and contextual hints for the agent
 /// 3. `[Thread Context]` or `[Conversation Context]` — if fetched
 /// 4. `[Event]` / `[Sprout events]` — the triggering event(s)
-pub fn format_prompt(
-    batch: &FlushBatch,
-    base_prompt: Option<&str>,
-    system_prompt: Option<&str>,
-    agent_core: Option<&str>,
-    channel_info: Option<&PromptChannelInfo>,
-    conversation_context: Option<&ConversationContext>,
-    profile_lookup: Option<&PromptProfileLookup>,
-) -> String {
+pub fn format_prompt(batch: &FlushBatch, args: &FormatPromptArgs<'_>) -> String {
     // Scope is always derived from the LAST event in the batch — that's the
     // one the agent is responding to. Thread/DM context is supplementary info
     // included alongside, not a scope override. This prevents mixed batches
@@ -954,24 +957,25 @@ pub fn format_prompt(
         }
     };
     let thread_tags = parse_thread_tags(&last_event.event);
-    let is_dm = channel_info
+    let is_dm = args
+        .channel_info
         .map(|ci| ci.channel_type == "dm")
         .unwrap_or(false);
 
-    let mut sections: Vec<String> = Vec::with_capacity(5);
+    let mut sections: Vec<String> = Vec::with_capacity(7);
 
     // 0. Base prompt (platform-level, always first).
-    if let Some(bp) = base_prompt {
-        sections.push(format!("[Base]\n{bp}"));
+    if let Some(bp) = args.base_prompt {
+        sections.push(format!("[Base]\n{}", bp.trim_end()));
     }
 
     // 1. System prompt.
-    if let Some(sp) = system_prompt {
+    if let Some(sp) = args.system_prompt {
         sections.push(format!("[System]\n{sp}"));
     }
 
     // 1b. NIP-AE agent core memory (rendered by `engram_fetch::build_core_section`).
-    if let Some(core) = agent_core {
+    if let Some(core) = args.agent_core {
         sections.push(core.to_string());
     }
 
@@ -983,16 +987,16 @@ pub fn format_prompt(
     };
     sections.push(format_context_hints(
         batch.channel_id,
-        channel_info,
+        args.channel_info,
         &thread_tags,
         is_dm,
-        conversation_context.is_some(),
+        args.conversation_context.is_some(),
         triggering_event_id.as_deref(),
     ));
 
     // 3. Conversation context (thread or DM).
-    if let Some(ctx) = conversation_context {
-        sections.push(format_conversation_context(ctx, profile_lookup));
+    if let Some(ctx) = args.conversation_context {
+        sections.push(format_conversation_context(ctx, args.profile_lookup));
     }
 
     // 4a. Cancelled events section (cancel + re-prompt).
@@ -1003,7 +1007,7 @@ pub fn format_prompt(
                 "\n\n--- Event {} ({}) ---\n{}",
                 i + 1,
                 be.prompt_tag,
-                format_event_block(batch.channel_id, channel_info, be, profile_lookup)
+                format_event_block(batch.channel_id, args.channel_info, be, args.profile_lookup)
             ));
         }
         sections.push(s);
@@ -1017,13 +1021,13 @@ pub fn format_prompt(
             format!(
                 "[New request — supersedes previous]\n\n--- Event 1 ({}) ---\n{}",
                 be.prompt_tag,
-                format_event_block(batch.channel_id, channel_info, be, profile_lookup)
+                format_event_block(batch.channel_id, args.channel_info, be, args.profile_lookup)
             )
         } else {
             format!(
                 "[Sprout event: {}]\n{}",
                 be.prompt_tag,
-                format_event_block(batch.channel_id, channel_info, be, profile_lookup)
+                format_event_block(batch.channel_id, args.channel_info, be, args.profile_lookup)
             )
         }
     } else {
@@ -1041,7 +1045,7 @@ pub fn format_prompt(
                 "\n\n--- Event {} ({}) ---\n{}",
                 i + 1,
                 be.prompt_tag,
-                format_event_block(batch.channel_id, channel_info, be, profile_lookup)
+                format_event_block(batch.channel_id, args.channel_info, be, args.profile_lookup)
             ));
         }
         s
@@ -1272,7 +1276,7 @@ mod tests {
             cancelled_events: vec![],
         };
 
-        let prompt = format_prompt(&batch, None, None, None, None, None);
+        let prompt = format_prompt(&batch, &FormatPromptArgs::default());
 
         // Should contain [Context] section before the event.
         assert!(prompt.contains("[Context]"));
@@ -1368,7 +1372,7 @@ mod tests {
             cancelled_events: vec![],
         };
 
-        let prompt = format_prompt(&batch, None, None, None, None, None);
+        let prompt = format_prompt(&batch, &FormatPromptArgs::default());
 
         assert!(prompt.contains("[Context]"));
         assert!(prompt.contains("[Sprout events — 3 events]"));
@@ -1399,12 +1403,10 @@ mod tests {
 
         let prompt = format_prompt(
             &batch,
-            None,
-            Some("You are a triage bot."),
-            None,
-            None,
-            None,
-            None,
+            &FormatPromptArgs {
+                system_prompt: Some("You are a triage bot."),
+                ..Default::default()
+            },
         );
         assert!(prompt.starts_with("[System]\nYou are a triage bot.\n\n[Context]"));
     }
@@ -1425,7 +1427,14 @@ mod tests {
             cancelled_events: vec![],
         };
         let core = "[Agent Memory — core]\nbe helpful";
-        let prompt = format_prompt(&batch, None, Some("sys"), Some(core), None, None, None);
+        let prompt = format_prompt(
+            &batch,
+            &FormatPromptArgs {
+                system_prompt: Some("sys"),
+                agent_core: Some(core),
+                ..Default::default()
+            },
+        );
         assert!(
             prompt.contains("[System]\nsys\n\n[Agent Memory — core]\nbe helpful"),
             "expected core block after [System]; got: {prompt}"
@@ -1446,7 +1455,13 @@ mod tests {
             cancelled_events: vec![],
         };
         let core = "[Agent Memory — core]\nbe helpful";
-        let prompt = format_prompt(&batch, None, None, Some(core), None, None, None);
+        let prompt = format_prompt(
+            &batch,
+            &FormatPromptArgs {
+                agent_core: Some(core),
+                ..Default::default()
+            },
+        );
         assert!(prompt.starts_with("[Agent Memory — core]\nbe helpful\n\n[Context]"));
     }
 
@@ -1470,22 +1485,81 @@ mod tests {
         // Both base_prompt and system_prompt: [Base] comes first, then [System].
         let prompt = format_prompt(
             &batch,
-            Some("Platform base."),
-            Some("Role prompt."),
-            None,
-            None,
-            None,
-            None,
+            &FormatPromptArgs {
+                base_prompt: Some("Platform base."),
+                system_prompt: Some("Role prompt."),
+                ..Default::default()
+            },
         );
         assert!(prompt.starts_with("[Base]\nPlatform base.\n\n[System]\nRole prompt."));
 
         // Only base_prompt (no system_prompt): [Base] comes first, then [Context].
-        let prompt = format_prompt(&batch, Some("Platform base."), None, None, None, None, None);
+        let prompt = format_prompt(
+            &batch,
+            &FormatPromptArgs {
+                base_prompt: Some("Platform base."),
+                ..Default::default()
+            },
+        );
         assert!(prompt.starts_with("[Base]\nPlatform base.\n\n[Context]"));
 
         // No base_prompt: no [Base] section emitted.
-        let prompt = format_prompt(&batch, None, None, None, None, None, None);
+        let prompt = format_prompt(&batch, &FormatPromptArgs::default());
         assert!(!prompt.contains("[Base]"));
+        assert!(prompt.starts_with("[Context]"));
+    }
+
+    #[test]
+    fn test_format_prompt_base_prompt_ordering_with_full_context() {
+        let ch = Uuid::new_v4();
+        let event = make_event("hello");
+        let batch = FlushBatch {
+            channel_id: ch,
+            events: vec![BatchEvent {
+                event,
+                prompt_tag: "test".into(),
+                received_at: Instant::now(),
+            }],
+            cancelled_events: vec![],
+        };
+
+        let ctx = ConversationContext::Thread {
+            messages: vec![ContextMessage {
+                pubkey: "npub1test".into(),
+                content: "prior message".into(),
+                timestamp: "2024-01-01T00:00:00Z".into(),
+            }],
+            total: 1,
+            truncated: false,
+        };
+
+        let prompt = format_prompt(
+            &batch,
+            &FormatPromptArgs {
+                base_prompt: Some("Platform base."),
+                system_prompt: Some("Role prompt."),
+                conversation_context: Some(&ctx),
+                ..Default::default()
+            },
+        );
+
+        // Verify section ordering: [Base] < [System] < [Context] < [Thread Context]
+        let base_pos = prompt.find("[Base]").expect("[Base] missing");
+        let system_pos = prompt.find("[System]").expect("[System] missing");
+        let context_pos = prompt.find("[Context]").expect("[Context] missing");
+        let thread_pos = prompt
+            .find("[Thread Context")
+            .expect("[Thread Context] missing");
+
+        assert!(base_pos < system_pos, "[Base] must come before [System]");
+        assert!(
+            system_pos < context_pos,
+            "[System] must come before [Context]"
+        );
+        assert!(
+            context_pos < thread_pos,
+            "[Context] must come before [Thread Context]"
+        );
     }
     // ── Test 12: drop mode discards in-flight channel events ─────────────────
 
@@ -1964,7 +2038,13 @@ mod tests {
             channel_type: "stream".into(),
         };
 
-        let prompt = format_prompt(&batch, None, None, Some(&ci), None, None);
+        let prompt = format_prompt(
+            &batch,
+            &FormatPromptArgs {
+                channel_info: Some(&ci),
+                ..Default::default()
+            },
+        );
         assert!(prompt.contains("engineering (#"));
         assert!(prompt.contains("Scope: channel"));
     }
@@ -1987,7 +2067,13 @@ mod tests {
             channel_type: "dm".into(),
         };
 
-        let prompt = format_prompt(&batch, None, None, Some(&ci), None, None);
+        let prompt = format_prompt(
+            &batch,
+            &FormatPromptArgs {
+                channel_info: Some(&ci),
+                ..Default::default()
+            },
+        );
         assert!(prompt.contains("Scope: dm"));
     }
 
@@ -2013,7 +2099,7 @@ mod tests {
             cancelled_events: vec![],
         };
 
-        let prompt = format_prompt(&batch, None, None, None, None, None);
+        let prompt = format_prompt(&batch, &FormatPromptArgs::default());
         assert!(prompt.contains("Scope: thread"));
         assert!(prompt.contains("Thread root: root123"));
     }
@@ -2056,7 +2142,13 @@ mod tests {
             truncated: true,
         };
 
-        let prompt = format_prompt(&batch, None, None, None, Some(&ctx), None);
+        let prompt = format_prompt(
+            &batch,
+            &FormatPromptArgs {
+                conversation_context: Some(&ctx),
+                ..Default::default()
+            },
+        );
         assert!(prompt.contains("[Thread Context (2 of 5 messages, truncated)]"));
         assert!(prompt.contains("Let's refactor auth"));
         assert!(prompt.contains("Thread context included below"));
@@ -2089,7 +2181,14 @@ mod tests {
             truncated: false,
         };
 
-        let prompt = format_prompt(&batch, None, None, Some(&ci), Some(&ctx), None);
+        let prompt = format_prompt(
+            &batch,
+            &FormatPromptArgs {
+                channel_info: Some(&ci),
+                conversation_context: Some(&ctx),
+                ..Default::default()
+            },
+        );
         assert!(prompt.contains("Scope: dm"));
         assert!(prompt.contains("[Conversation Context (1 of 1 messages)]"));
         assert!(prompt.contains("Can you deploy?"));
@@ -2141,7 +2240,14 @@ mod tests {
             ),
         ]);
 
-        let prompt = format_prompt(&batch, None, None, None, Some(&ctx), Some(&profiles));
+        let prompt = format_prompt(
+            &batch,
+            &FormatPromptArgs {
+                conversation_context: Some(&ctx),
+                profile_lookup: Some(&profiles),
+                ..Default::default()
+            },
+        );
 
         assert!(prompt.contains("From: Wes (npub:"));
         assert!(prompt.contains(
@@ -2236,13 +2342,20 @@ mod tests {
             truncated: false,
         };
 
-        let prompt = format_prompt(&batch, None, None, Some(&ci), Some(&ctx), None);
+        let prompt = format_prompt(
+            &batch,
+            &FormatPromptArgs {
+                channel_info: Some(&ci),
+                conversation_context: Some(&ctx),
+                ..Default::default()
+            },
+        );
         // Scope should be "dm", not "thread".
         assert!(
             prompt.contains("Scope: dm"),
             "DM reply should have Scope: dm, got:\n{prompt}"
         );
-        // Hint should point to get_thread(), not get_channel_history().
+        // Hint should point to get_thread(), not get_messages().
         assert!(
             prompt.contains("get_thread()"),
             "DM reply hint should mention get_thread(), got:\n{prompt}"
@@ -2257,7 +2370,7 @@ mod tests {
     }
 
     #[test]
-    fn test_format_prompt_dm_non_reply_hints_get_channel_history() {
+    fn test_format_prompt_dm_non_reply_hints_get_messages() {
         let ch = Uuid::new_v4();
         let event = make_event("hey there");
         let batch = FlushBatch {
@@ -2275,11 +2388,17 @@ mod tests {
         };
 
         // No context fetched — hints only.
-        let prompt = format_prompt(&batch, None, None, Some(&ci), None, None);
+        let prompt = format_prompt(
+            &batch,
+            &FormatPromptArgs {
+                channel_info: Some(&ci),
+                ..Default::default()
+            },
+        );
         assert!(prompt.contains("Scope: dm"));
         assert!(
-            prompt.contains("get_channel_history()"),
-            "DM non-reply hint should mention get_channel_history()"
+            prompt.contains("get_messages()"),
+            "DM non-reply hint should mention get_messages()"
         );
         assert!(
             !prompt.contains("get_thread()"),
@@ -2302,7 +2421,7 @@ mod tests {
             cancelled_events: vec![],
         };
 
-        let prompt = format_prompt(&batch, None, None, None, None, None);
+        let prompt = format_prompt(&batch, &FormatPromptArgs::default());
         assert!(
             prompt.contains(&format!("Event ID: {event_id}")),
             "prompt should contain the event ID"
@@ -2325,7 +2444,7 @@ mod tests {
             cancelled_events: vec![],
         };
 
-        let prompt = format_prompt(&batch, None, None, None, None, None);
+        let prompt = format_prompt(&batch, &FormatPromptArgs::default());
         assert!(
             prompt.contains(&format!("From: {npub} (hex: {hex})")),
             "prompt should contain both npub and hex"
@@ -2347,7 +2466,7 @@ mod tests {
             cancelled_events: vec![],
         };
 
-        let prompt = format_prompt(&batch, None, None, None, None, None);
+        let prompt = format_prompt(&batch, &FormatPromptArgs::default());
         assert!(
             prompt.contains("Tags:"),
             "tags should always be included, even for stream messages"
@@ -2671,7 +2790,7 @@ mod tests {
             cancelled_events: vec![],
         };
 
-        let prompt = format_prompt(&batch, None, None, None, None, None);
+        let prompt = format_prompt(&batch, &FormatPromptArgs::default());
         assert!(
             prompt.contains(&format!("parent_event_id=\"{event_id}\"")),
             "channel thread reply should include reply instruction with triggering event ID"
@@ -2705,7 +2824,13 @@ mod tests {
             channel_type: "dm".into(),
         };
 
-        let prompt = format_prompt(&batch, None, None, Some(&ci), None, None);
+        let prompt = format_prompt(
+            &batch,
+            &FormatPromptArgs {
+                channel_info: Some(&ci),
+                ..Default::default()
+            },
+        );
         assert!(
             prompt.contains(&format!("parent_event_id=\"{event_id}\"")),
             "DM thread reply should include reply instruction"
@@ -2726,7 +2851,7 @@ mod tests {
             cancelled_events: vec![],
         };
 
-        let prompt = format_prompt(&batch, None, None, None, None, None);
+        let prompt = format_prompt(&batch, &FormatPromptArgs::default());
         assert!(
             !prompt.contains("parent_event_id"),
             "top-level message should NOT include reply instruction"
@@ -2751,7 +2876,13 @@ mod tests {
             channel_type: "dm".into(),
         };
 
-        let prompt = format_prompt(&batch, None, None, Some(&ci), None, None);
+        let prompt = format_prompt(
+            &batch,
+            &FormatPromptArgs {
+                channel_info: Some(&ci),
+                ..Default::default()
+            },
+        );
         assert!(
             !prompt.contains("parent_event_id"),
             "DM non-reply should NOT include reply instruction"
@@ -2781,7 +2912,7 @@ mod tests {
             cancelled_events: vec![],
         };
 
-        let prompt = format_prompt(&batch, None, None, None, None, None);
+        let prompt = format_prompt(&batch, &FormatPromptArgs::default());
         // The instruction should use the triggering event's own ID — not root or parent.
         assert!(
             prompt.contains(&format!("parent_event_id=\"{event_id}\"")),
@@ -2824,7 +2955,7 @@ mod tests {
             cancelled_events: vec![],
         };
 
-        let prompt = format_prompt(&batch, None, None, None, None, None);
+        let prompt = format_prompt(&batch, &FormatPromptArgs::default());
         assert!(
             prompt.contains(&format!("parent_event_id=\"{threaded_id}\"")),
             "batched prompt should use last (threaded) event's ID"
@@ -2857,7 +2988,7 @@ mod tests {
             cancelled_events: vec![],
         };
 
-        let prompt = format_prompt(&batch, None, None, None, None, None);
+        let prompt = format_prompt(&batch, &FormatPromptArgs::default());
         assert!(
             !prompt.contains("parent_event_id"),
             "batched prompt where last event is top-level should NOT include reply instruction"
diff --git a/crates/sprout-persona/PERSONA_PACK_SPEC.md b/crates/sprout-persona/PERSONA_PACK_SPEC.md
index 5ffc961abd..f29fa32209 100644
--- a/crates/sprout-persona/PERSONA_PACK_SPEC.md
+++ b/crates/sprout-persona/PERSONA_PACK_SPEC.md
@@ -250,7 +250,7 @@ Each message delivered to the agent runtime includes these sections in order:
 <contents of instructions.md, if present>
 
 [Context]
-<workspace layout, available skills, MCP tool reference>
+<scope, channel name, and contextual hints>
 
 [Thread/Conversation Context]
 <recent message history, if applicable>
@@ -273,9 +273,9 @@ The `[Base]` layer is compiled into sprout-acp and is **identical for every agen
 Pack authors do not write or configure the `[Base]` layer — it is maintained by the Sprout team
 and updated in sprout-acp releases.
 
-**Disabling the base layer**: Set `SPROUT_ACP_BASE_PROMPT_DISABLED=1` in the sprout-acp process
-environment to omit the `[Base]` section entirely. This is intended for testing and advanced
-deployments where operators supply their own platform context.
+**Disabling or customizing the base layer**: Set `SPROUT_ACP_NO_BASE_PROMPT` to omit the `[Base]`
+section entirely. To replace the compiled-in default with custom content, set
+`SPROUT_ACP_BASE_PROMPT_FILE` to a file path — sprout-acp reads it at startup and uses it instead.
 
 ### The `[System]` Layer
 
diff --git a/desktop/src-tauri/src/managed_agents/personas.rs b/desktop/src-tauri/src/managed_agents/personas.rs
index 55899f7484..e7bb0318eb 100644
--- a/desktop/src-tauri/src/managed_agents/personas.rs
+++ b/desktop/src-tauri/src/managed_agents/personas.rs
@@ -15,6 +15,7 @@ struct BuiltInPersona {
     system_prompt: &'static str,
     name_pool: &'static [&'static str],
     model: Option<&'static str>,
+    provider: Option<&'static str>,
 }
 
 const SOLO_AVATAR: &str = "data:image/png;base64,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";
@@ -147,6 +148,7 @@ const BUILT_IN_PERSONAS: &[BuiltInPersona] = &[
             "Birch", "Dune", "Fern", "Moss", "Reed", "Slate", "Ash", "Brook", "Glen", "Stone",
         ],
         model: Some("claude-sonnet-4-20250514"),
+        provider: Some("claude"),
     },
     BuiltInPersona {
         id: "builtin:kit",
@@ -295,6 +297,7 @@ Don't present work that doesn't meet this bar. No emojis.
 
 Your name is Kit. You are friendly and helpful. You are understated, but have a sense of humor."#,
         model: Some("claude-sonnet-4-20250514"),
+        provider: Some("claude"),
     },
     BuiltInPersona {
         id: "builtin:scout",
@@ -454,6 +457,7 @@ If you're invoked outside a Sprout team channel (or by an agent that isn't Kit),
 
 Your name is Scout. You are friendly and helpful. You are understated, but have a sense of humor."#,
         model: Some("claude-sonnet-4-20250514"),
+        provider: Some("claude"),
     },
 ];
 
@@ -469,7 +473,7 @@ fn built_in_persona_records(now: &str) -> Vec<PersonaRecord> {
             display_name: persona.display_name.to_string(),
             avatar_url: persona.avatar_url.map(|s| s.to_string()),
             system_prompt: persona.system_prompt.to_string(),
-            provider: None,
+            provider: persona.provider.map(|s| s.to_string()),
             model: persona.model.map(|s| s.to_string()),
             name_pool: persona.name_pool.iter().map(|s| s.to_string()).collect(),
             is_builtin: true,
@@ -519,6 +523,9 @@ fn merge_personas(mut stored: Vec<PersonaRecord>, now: &str) -> (Vec<PersonaReco
             let created_at = existing.created_at.clone();
             let updated_at = existing.updated_at.clone();
             let is_active = existing.is_active;
+            // Built-in fields are canonical — user overrides on provider/model are
+            // intentionally not preserved across restarts. Users who want a custom
+            // model or provider should clone the built-in as a custom persona.
             if existing.display_name != built_in.display_name
                 || existing.avatar_url != built_in.avatar_url
                 || existing.system_prompt != built_in.system_prompt

From 72082dc3ad0c435b0a9fb796e9b71351755bf48e Mon Sep 17 00:00:00 2001
From: Will Pfleger <wpfleger@block.xyz>
Date: Thu, 14 May 2026 21:05:10 -0400
Subject: [PATCH 03/18] fix: CLI-first base prompt and remove hardcoded model
 from built-ins
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

base_prompt.md now leads with the sprout CLI (12 subcommand groups from
#585) rather than MCP tools, which are still available but secondary.
Adds the @mention formatting rule (no bold/italic), get_feed type
filtering, and a pointer to nest_agents.md for workspace conventions.

Reverts the hardcoded model/provider on Solo, Kit, and Scout back to
None. The agent binary's own default is the right choice here — pinning
claude-sonnet-4-20250514 is opinionated and will go stale. Users who
want a specific model can set it per-agent via the model picker.
---
 crates/sprout-acp/src/base_prompt.md          | 61 ++++++++++++-------
 .../src-tauri/src/managed_agents/personas.rs  | 12 ++--
 2 files changed, 45 insertions(+), 28 deletions(-)

diff --git a/crates/sprout-acp/src/base_prompt.md b/crates/sprout-acp/src/base_prompt.md
index b9a0a49085..5f82e213e9 100644
--- a/crates/sprout-acp/src/base_prompt.md
+++ b/crates/sprout-acp/src/base_prompt.md
@@ -1,35 +1,52 @@
-You are operating inside the Sprout platform — a Nostr-based messaging platform for human-agent collaboration. The sprout-acp harness bridges channel events to your session.
+You are operating inside the Sprout platform — a Nostr-based messaging platform for human-agent collaboration. The sprout-acp harness routes channel events to your session.
 
-## MCP Tools (via `sprout-mcp`)
+## Sprout CLI
 
-- `get_messages(channel_id, limit=50)` — fetch recent history (max 200 per call)
-- `get_messages(channel_id, since=<unix_ts>)` — fetch messages since timestamp; returns oldest-first when `since` is set without `before`
-- `get_thread(channel_id, event_id)` — fetch a full thread by root event ID
-- `get_feed()` — personalized feed of mentions and needs-action items across all channels
-- `send_message(channel_id, content)` — post a new message to a channel
-- `send_message(channel_id, content, parent_event_id)` — reply within an existing thread
-- `search(q="your query")` — cross-channel full-text search
+The `sprout` CLI is your primary interface. Auth env vars: `SPROUT_RELAY_URL`, `SPROUT_PRIVATE_KEY`, `SPROUT_AUTH_TAG`. Exit codes: 0 ok, 1 user error, 2 network, 3 auth, 4 other. Output is structured JSON — pipe through `jq` as needed.
+
+| Group | Key commands |
+|-------|-------------|
+| `sprout messages` | `send`, `get`, `thread`, `search` |
+| `sprout channels` | `list`, `get`, `create`, `join`, `members` |
+| `sprout canvas` | `get`, `set` |
+| `sprout reactions` | `add`, `remove` |
+| `sprout dms` | `list`, `open` |
+| `sprout users` | `get`, `set-profile`, `presence` |
+| `sprout workflows` | `list`, `trigger`, `runs` |
+| `sprout feed` | `get` |
+| `sprout social` | `publish`, `notes` |
+| `sprout repos` | `create`, `get`, `list` |
+| `sprout upload` | `file` |
+
+Run `sprout --help` or `sprout <group> --help` for full usage.
+
+MCP tools (via `sprout-mcp`) are also available but the CLI is preferred for batch operations and scripting.
 
 ## Communication Patterns
 
-- Address agents and humans with `@name` in message content.
-- Use `parent_event_id` when responding to a thread; post a new message for new topics.
-- There are no push notifications — poll for new messages using `since=<last_seen_ts>`.
+- Address agents and humans with plain `@name` — do NOT bold or italicize mention text (formatting prevents alert delivery).
+- Use `sprout messages thread` or MCP `get_thread()` when responding in-thread; post new messages for new topics.
+- No push notifications — poll with `sprout messages get --since=<unix_ts>` or MCP `get_messages(since=<ts>)`. When `since` is set without `before`, results are oldest-first (chronological).
 
 ## Startup Recovery
 
-On startup or after a gap: call `get_feed()` first to surface pending mentions and action items, then call `get_messages` on your assigned channels to catch up, then check `AGENTS.md` for team context. Use `search()` for cross-channel keyword lookups when you need to find specific prior discussions.
+1. `sprout feed get` (or MCP `get_feed()`) — surface pending mentions and action items. Filter by type: `mentions`, `needs_action`, `activity`, `agent_activity`.
+2. `sprout messages get <channel_id>` on assigned channels — catch up on recent history.
+3. Check `AGENTS.md` in your working directory for team context.
+4. Check `RESEARCH/`, `GUIDES/`, `PLANS/` before searching externally. Use `sprout messages search --query "..."` for cross-channel keyword lookups.
 
 ## Workspace Layout
 
-Your persistent workspace is in your working directory, with the following subdirectories:
+Your persistent workspace is in your working directory:
 
-- `RESEARCH/` — findings and reference material
-- `PLANS/` — project and task plans
-- `GUIDES/` — how-to documentation
-- `WORK_LOGS/` — timestamped activity logs
-- `OUTBOX/` — drafts pending review or send
-- `REPOS/` — checked-out source repositories
-- `.scratch/` — ephemeral working files
+| Dir | Purpose |
+|-----|---------|
+| `RESEARCH/` | Findings and reference material |
+| `PLANS/` | Project and task plans |
+| `GUIDES/` | How-to documentation |
+| `WORK_LOGS/` | Timestamped activity logs |
+| `OUTBOX/` | Drafts pending review or send |
+| `REPOS/` | Checked-out source repositories |
+| `.scratch/` | Ephemeral working files |
 
-Knowledge files use `ALL_CAPS_WITH_UNDERSCORES.md` naming and YAML frontmatter. `AGENTS.md` in the working directory lists active agents and their assigned roles.
+Knowledge files use `ALL_CAPS_WITH_UNDERSCORES.md` naming. `AGENTS.md` lists active agents and roles. See `nest_agents.md` in your working directory for full workspace conventions.
diff --git a/desktop/src-tauri/src/managed_agents/personas.rs b/desktop/src-tauri/src/managed_agents/personas.rs
index e7bb0318eb..2bd74c3bc6 100644
--- a/desktop/src-tauri/src/managed_agents/personas.rs
+++ b/desktop/src-tauri/src/managed_agents/personas.rs
@@ -147,8 +147,8 @@ const BUILT_IN_PERSONAS: &[BuiltInPersona] = &[
             "Atlas", "Ember", "Flint", "Sage", "Drift", "Quill", "Wren", "Cedar", "Pike", "Lark",
             "Birch", "Dune", "Fern", "Moss", "Reed", "Slate", "Ash", "Brook", "Glen", "Stone",
         ],
-        model: Some("claude-sonnet-4-20250514"),
-        provider: Some("claude"),
+        model: None,
+        provider: None,
     },
     BuiltInPersona {
         id: "builtin:kit",
@@ -296,8 +296,8 @@ Aim for 9/10+ on the first pass. There is no separate refactoring pass — if it
 Don't present work that doesn't meet this bar. No emojis.
 
 Your name is Kit. You are friendly and helpful. You are understated, but have a sense of humor."#,
-        model: Some("claude-sonnet-4-20250514"),
-        provider: Some("claude"),
+        model: None,
+        provider: None,
     },
     BuiltInPersona {
         id: "builtin:scout",
@@ -456,8 +456,8 @@ You are read-only, but you still resolve questions yourself before pinging Kit:
 If you're invoked outside a Sprout team channel (or by an agent that isn't Kit), apply the same protocols. Default to FULL REVIEW for completed work or PLAN REVIEW + RESEARCH for plans. Report to whoever invoked you.
 
 Your name is Scout. You are friendly and helpful. You are understated, but have a sense of humor."#,
-        model: Some("claude-sonnet-4-20250514"),
-        provider: Some("claude"),
+        model: None,
+        provider: None,
     },
 ];
 

From 453a9d02b77c19790e7ce7d6ae5ee775058c48d0 Mon Sep 17 00:00:00 2001
From: Will Pfleger <wpfleger@block.xyz>
Date: Thu, 14 May 2026 14:48:33 -0400
Subject: [PATCH 04/18] feat(desktop): dynamic nest AGENTS.md regeneration

AGENTS.md in ~/.sprout is now dynamically regenerated whenever personas,
agents, or workspace config changes. Agents discover their teammates on
every fresh session via a managed section demarcated by HTML comment
markers. User edits outside the markers are preserved across
regenerations.
---
 .../src-tauri/src/commands/agent_models.rs    |  10 +-
 desktop/src-tauri/src/commands/agents.rs      |  23 +-
 desktop/src-tauri/src/commands/personas.rs    |  26 +-
 desktop/src-tauri/src/commands/workspace.rs   |  10 +-
 desktop/src-tauri/src/lib.rs                  |   7 +-
 desktop/src-tauri/src/managed_agents/nest.rs  | 245 ++++++++++++++++++
 .../src/managed_agents/nest_agents.md         |   7 +
 7 files changed, 313 insertions(+), 15 deletions(-)

diff --git a/desktop/src-tauri/src/commands/agent_models.rs b/desktop/src-tauri/src/commands/agent_models.rs
index bcdc0150f9..a016cac377 100644
--- a/desktop/src-tauri/src/commands/agent_models.rs
+++ b/desktop/src-tauri/src/commands/agent_models.rs
@@ -8,9 +8,9 @@ use crate::{
     managed_agents::{
         build_managed_agent_summary, default_agent_workdir, find_managed_agent_mut,
         load_managed_agents, managed_agent_avatar_url, missing_command_message,
-        normalize_agent_args, resolve_command, save_managed_agents, sync_managed_agent_processes,
-        AgentModelInfo, AgentModelsResponse, UpdateManagedAgentRequest, UpdateManagedAgentResponse,
-        DEFAULT_MCP_COMMAND,
+        normalize_agent_args, regenerate_nest_context, resolve_command, save_managed_agents,
+        sync_managed_agent_processes, AgentModelInfo, AgentModelsResponse,
+        UpdateManagedAgentRequest, UpdateManagedAgentResponse, DEFAULT_MCP_COMMAND,
     },
     relay::{relay_ws_url_with_override, sync_managed_agent_profile},
     util::now_iso,
@@ -251,6 +251,10 @@ pub async fn update_managed_agent(
         (summary, sync_params)
     }; // lock dropped here
 
+    if let Err(error) = regenerate_nest_context(&app) {
+        eprintln!("sprout-desktop: nest context regeneration failed: {error}");
+    }
+
     // Phase 2: relay profile sync (async, best-effort, outside lock)
     let profile_sync_error =
         if let Some((agent_keys, relay_url, display_name, avatar_url, auth_tag)) = sync_params {
diff --git a/desktop/src-tauri/src/commands/agents.rs b/desktop/src-tauri/src/commands/agents.rs
index 7e663ed41a..1f984b0ba9 100644
--- a/desktop/src-tauri/src/commands/agents.rs
+++ b/desktop/src-tauri/src/commands/agents.rs
@@ -7,12 +7,13 @@ use crate::{
         build_managed_agent_summary, discover_provider_candidates, ensure_persona_is_active,
         find_managed_agent_mut, invoke_provider, load_managed_agents, load_personas,
         managed_agent_avatar_url, managed_agent_log_path, managed_agents_base_dir,
-        normalize_agent_args, provider_deploy, read_log_tail, resolve_provider_binary,
-        save_managed_agents, start_managed_agent_process, stop_managed_agent_process,
-        sync_managed_agent_processes, validate_provider_config, BackendKind, BackendProviderInfo,
-        CreateManagedAgentRequest, CreateManagedAgentResponse, ManagedAgentLogResponse,
-        ManagedAgentRecord, ManagedAgentSummary, DEFAULT_ACP_COMMAND, DEFAULT_AGENT_COMMAND,
-        DEFAULT_AGENT_PARALLELISM, DEFAULT_AGENT_TURN_TIMEOUT_SECONDS, DEFAULT_MCP_COMMAND,
+        normalize_agent_args, provider_deploy, read_log_tail, regenerate_nest_context,
+        resolve_provider_binary, save_managed_agents, start_managed_agent_process,
+        stop_managed_agent_process, sync_managed_agent_processes, validate_provider_config,
+        BackendKind, BackendProviderInfo, CreateManagedAgentRequest, CreateManagedAgentResponse,
+        ManagedAgentLogResponse, ManagedAgentRecord, ManagedAgentSummary, DEFAULT_ACP_COMMAND,
+        DEFAULT_AGENT_COMMAND, DEFAULT_AGENT_PARALLELISM, DEFAULT_AGENT_TURN_TIMEOUT_SECONDS,
+        DEFAULT_MCP_COMMAND,
     },
     relay::{relay_ws_url_with_override, sync_managed_agent_profile},
     util::now_iso,
@@ -452,6 +453,10 @@ pub async fn create_managed_agent(
         (agent, spawn_error)
     };
 
+    if let Err(error) = regenerate_nest_context(&app) {
+        eprintln!("sprout-desktop: nest context regeneration failed: {error}");
+    }
+
     // ── Phase 4: sync agent profile on relay (async, outside lock) ───────────
     let avatar_url = input
         .avatar_url
@@ -713,7 +718,11 @@ pub fn delete_managed_agent(
     if records.len() == initial_len {
         return Err(format!("agent {pubkey} not found"));
     }
-    save_managed_agents(&app, &records)
+    save_managed_agents(&app, &records)?;
+    if let Err(error) = regenerate_nest_context(&app) {
+        eprintln!("sprout-desktop: nest context regeneration failed: {error}");
+    }
+    Ok(())
 }
 
 #[tauri::command]
diff --git a/desktop/src-tauri/src/commands/personas.rs b/desktop/src-tauri/src/commands/personas.rs
index f5ece7f018..5312429967 100644
--- a/desktop/src-tauri/src/commands/personas.rs
+++ b/desktop/src-tauri/src/commands/personas.rs
@@ -7,7 +7,7 @@ use crate::{
     managed_agents::{
         encode_persona_json, import_persona_pack, list_installed_packs, load_managed_agents,
         load_personas, load_teams, parse_json_persona, parse_md_persona, parse_png_persona,
-        parse_zip_personas, save_managed_agents, save_personas,
+        parse_zip_personas, regenerate_nest_context, save_managed_agents, save_personas,
         uninstall_persona_pack as do_uninstall_persona_pack, validate_persona_activation_change,
         validate_persona_deletion, CreatePersonaRequest, PackSummary, ParsePersonaFilesResult,
         PersonaRecord, UpdatePersonaRequest,
@@ -85,6 +85,9 @@ pub fn create_persona(
     };
     personas.push(persona.clone());
     save_personas(&app, &personas)?;
+    if let Err(error) = regenerate_nest_context(&app) {
+        eprintln!("sprout-desktop: nest context regeneration failed: {error}");
+    }
     Ok(persona)
 }
 
@@ -134,6 +137,9 @@ pub fn update_persona(
     persona.updated_at = now_iso();
 
     save_personas(&app, &personas)?;
+    if let Err(error) = regenerate_nest_context(&app) {
+        eprintln!("sprout-desktop: nest context regeneration failed: {error}");
+    }
     personas
         .into_iter()
         .find(|record| record.id == input.id)
@@ -182,6 +188,9 @@ pub fn delete_persona(
     if changed_agents {
         save_managed_agents(&app, &agents)?;
     }
+    if let Err(error) = regenerate_nest_context(&app) {
+        eprintln!("sprout-desktop: nest context regeneration failed: {error}");
+    }
 
     Ok(())
 }
@@ -230,6 +239,9 @@ pub fn set_persona_active(
 
     let updated = persona.clone();
     save_personas(&app, &personas)?;
+    if let Err(error) = regenerate_nest_context(&app) {
+        eprintln!("sprout-desktop: nest context regeneration failed: {error}");
+    }
     Ok(updated)
 }
 
@@ -383,7 +395,11 @@ pub fn install_persona_pack(
     if !source.is_dir() {
         return Err(format!("pack path is not a directory: {path}"));
     }
-    import_persona_pack(&app, &source)
+    let result = import_persona_pack(&app, &source)?;
+    if let Err(error) = regenerate_nest_context(&app) {
+        eprintln!("sprout-desktop: nest context regeneration failed: {error}");
+    }
+    Ok(result)
 }
 
 #[tauri::command]
@@ -396,7 +412,11 @@ pub fn uninstall_persona_pack(
         .managed_agents_store_lock
         .lock()
         .map_err(|e| e.to_string())?;
-    do_uninstall_persona_pack(&app, &pack_id)
+    do_uninstall_persona_pack(&app, &pack_id)?;
+    if let Err(error) = regenerate_nest_context(&app) {
+        eprintln!("sprout-desktop: nest context regeneration failed: {error}");
+    }
+    Ok(())
 }
 
 #[tauri::command]
diff --git a/desktop/src-tauri/src/commands/workspace.rs b/desktop/src-tauri/src/commands/workspace.rs
index e75d1801d6..615dd2324c 100644
--- a/desktop/src-tauri/src/commands/workspace.rs
+++ b/desktop/src-tauri/src/commands/workspace.rs
@@ -1,8 +1,9 @@
 use nostr::Keys;
 use serde::Serialize;
-use tauri::State;
+use tauri::{AppHandle, State};
 
 use crate::app_state::AppState;
+use crate::managed_agents::regenerate_nest_context;
 use crate::relay;
 
 #[derive(Serialize)]
@@ -30,6 +31,7 @@ pub fn get_active_workspace(state: State<'_, AppState>) -> Result<ActiveWorkspac
 pub fn apply_workspace(
     relay_url: String,
     nsec: Option<String>,
+    app: AppHandle,
     state: State<'_, AppState>,
 ) -> Result<(), String> {
     // ── Validate before mutating ──────────────────────────────────────────
@@ -51,5 +53,11 @@ pub fn apply_workspace(
         *keys_guard = keys;
     }
 
+    if let Err(error) = regenerate_nest_context(&app) {
+        eprintln!(
+            "sprout-desktop: failed to regenerate nest context after workspace switch: {error}"
+        );
+    }
+
     Ok(())
 }
diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs
index 8537035f2d..f5b12775a3 100644
--- a/desktop/src-tauri/src/lib.rs
+++ b/desktop/src-tauri/src/lib.rs
@@ -24,7 +24,7 @@ use huddle::{
     speak_agent_message, start_huddle, start_stt_pipeline,
 };
 use managed_agents::{
-    ensure_nest, kill_stale_tracked_processes, load_managed_agents,
+    ensure_nest, kill_stale_tracked_processes, load_managed_agents, regenerate_nest_context,
     restore_managed_agents_on_launch, save_managed_agents, sync_managed_agent_processes,
     BackendKind, ManagedAgentProcess,
 };
@@ -403,6 +403,11 @@ pub fn run() {
                 }
             }
 
+            if let Err(error) = regenerate_nest_context(&app_handle) {
+                eprintln!("sprout-desktop: failed to regenerate nest context: {error}");
+            }
+
+
             // Pre-download voice models in the background so they're ready
             // when the user starts their first huddle. Idempotent — no-op if
             // already downloaded. ~289 MB total (~100 MB Parakeet STT + ~189 MB Pocket TTS).
diff --git a/desktop/src-tauri/src/managed_agents/nest.rs b/desktop/src-tauri/src/managed_agents/nest.rs
index 25639b8d91..28f2eb045b 100644
--- a/desktop/src-tauri/src/managed_agents/nest.rs
+++ b/desktop/src-tauri/src/managed_agents/nest.rs
@@ -6,8 +6,15 @@
 //!
 //! Idempotent: existing files and directories are never overwritten.
 
+use super::{
+    load_managed_agents, load_personas, BackendKind, ManagedAgentRecord, PersonaRecord, RespondTo,
+};
+use crate::app_state::AppState;
+use crate::relay::relay_ws_url_with_override;
 use std::fs;
+use std::io;
 use std::path::{Path, PathBuf};
+use tauri::{AppHandle, Manager};
 
 /// Subdirectories created inside the nest.
 const NEST_DIRS: &[&str] = &[
@@ -224,6 +231,107 @@ pub fn ensure_cli_symlink(_exe_parent: &Path) -> Result<(), String> {
     Ok(())
 }
 
+const CLI_QUICK_REFERENCE: &str = "\
+## CLI Quick Reference
+`sprout messages send --channel <id> --content <text>` — send a message
+`sprout messages get --channel <id>` — read recent messages
+`sprout channels list` — list available channels
+`sprout workflows trigger --workflow <id>` — trigger a workflow
+Run `sprout --help` for the full command reference.";
+
+pub fn render_dynamic_section(
+    personas: &[PersonaRecord],
+    agents: &[ManagedAgentRecord],
+    relay_url: &str,
+) -> String {
+    let active_agents = if agents.is_empty() {
+        "## Active Agents\n\n*(No agents deployed yet. Add agents in the Sprout desktop app.)*"
+            .to_string()
+    } else {
+        let mut table =
+            "## Active Agents\n\n| Name | Role | How to address |\n|------|------|----------------|"
+                .to_string();
+        for agent in agents {
+            let role = agent
+                .persona_id
+                .as_deref()
+                .and_then(|pid| personas.iter().find(|p| p.id == pid))
+                .map(|p| p.display_name.as_str())
+                .unwrap_or("—");
+            table.push_str(&format!(
+                "\n| {} | {} | @{} |",
+                agent.name, role, agent.name
+            ));
+        }
+        table
+    };
+
+    format!("{active_agents}\n\n## Workspace\n- Relay: {relay_url}\n\n{CLI_QUICK_REFERENCE}")
+}
+
+pub fn upsert_managed_section(file_path: &Path, new_section_content: &str) -> io::Result<()> {
+    let current = fs::read_to_string(file_path)?;
+
+    const BEGIN: &str = "<!-- BEGIN SPROUT MANAGED";
+    const END: &str = "<!-- END SPROUT MANAGED -->";
+
+    let replacement = format!(
+        "<!-- BEGIN SPROUT MANAGED — regenerated automatically, do not edit below -->\n{new_section_content}\n<!-- END SPROUT MANAGED -->\n"
+    );
+
+    let new_content =
+        if let (Some(begin_pos), Some(end_pos)) = (current.find(BEGIN), current.find(END)) {
+            // Find the start of the BEGIN marker's line.
+            let line_start = current[..begin_pos].rfind('\n').map(|p| p + 1).unwrap_or(0);
+            // END marker spans to the end of its content + the newline after it.
+            let end_of_end = end_pos + END.len();
+            let after_end = if current[end_of_end..].starts_with('\n') {
+                end_of_end + 1
+            } else {
+                end_of_end
+            };
+            format!(
+                "{}{}{}",
+                &current[..line_start],
+                replacement,
+                &current[after_end..]
+            )
+        } else {
+            format!("{}\n\n{}", current.trim_end_matches('\n'), replacement)
+        };
+
+    let tmp_path = file_path.with_extension(
+        file_path
+            .extension()
+            .map(|e| format!("{}.tmp", e.to_string_lossy()))
+            .unwrap_or_else(|| "tmp".to_string()),
+    );
+    fs::write(&tmp_path, new_content)?;
+    fs::rename(&tmp_path, file_path)?;
+
+    Ok(())
+}
+
+pub fn regenerate_nest_context(app: &AppHandle) -> Result<(), String> {
+    let nest = nest_dir().ok_or("cannot resolve home directory for nest")?;
+    let agents_md = nest.join("AGENTS.md");
+
+    if !agents_md.exists() {
+        return Ok(());
+    }
+
+    let personas = load_personas(app)?;
+    let agents = load_managed_agents(app)?;
+    let state = app.state::<AppState>();
+    let relay_url = relay_ws_url_with_override(&state);
+    let content = render_dynamic_section(&personas, &agents, &relay_url);
+    upsert_managed_section(&agents_md, &content)
+        .map_err(|e| format!("regenerate nest context: {e}"))?;
+
+    Ok(())
+}
+
+
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -406,4 +514,141 @@ mod tests {
         // in the Ok(_) branch of ensure_cli_symlink skips regular files).
         assert_eq!(fs::read_to_string(&link).unwrap(), "user-installed binary");
     }
+
+    fn make_persona(id: &str, display_name: &str) -> PersonaRecord {
+        PersonaRecord {
+            id: id.to_string(),
+            display_name: display_name.to_string(),
+            avatar_url: None,
+            system_prompt: String::new(),
+            provider: None,
+            model: None,
+            name_pool: vec![],
+            is_builtin: false,
+            is_active: true,
+            source_pack: None,
+            source_pack_persona_slug: None,
+            created_at: String::new(),
+            updated_at: String::new(),
+        }
+    }
+
+    fn make_agent(name: &str, persona_id: Option<&str>) -> ManagedAgentRecord {
+        ManagedAgentRecord {
+            pubkey: String::new(),
+            name: name.to_string(),
+            persona_id: persona_id.map(|s| s.to_string()),
+            private_key_nsec: String::new(),
+            auth_tag: None,
+            relay_url: String::new(),
+            acp_command: String::new(),
+            agent_command: String::new(),
+            agent_args: vec![],
+            mcp_command: String::new(),
+            turn_timeout_seconds: 0,
+            idle_timeout_seconds: None,
+            max_turn_duration_seconds: None,
+            parallelism: 1,
+            system_prompt: None,
+            model: None,
+            mcp_toolsets: None,
+            start_on_app_launch: false,
+            runtime_pid: None,
+            backend: BackendKind::default(),
+            backend_agent_id: None,
+            provider_binary_path: None,
+            persona_pack_path: None,
+            persona_name_in_pack: None,
+            created_at: String::new(),
+            updated_at: String::new(),
+            last_started_at: None,
+            last_stopped_at: None,
+            last_exit_code: None,
+            last_error: None,
+            respond_to: RespondTo::default(),
+            respond_to_allowlist: vec![],
+        }
+    }
+
+    #[test]
+    fn test_render_dynamic_section_with_agents() {
+        let personas = vec![make_persona("p1", "Builder")];
+        let agents = vec![make_agent("Kit", Some("p1"))];
+        let output = render_dynamic_section(&personas, &agents, "ws://example.com:3000");
+        assert!(output.contains("| Kit | Builder | @Kit |"));
+        assert!(output.contains("## CLI Quick Reference"));
+    }
+
+    #[test]
+    fn test_render_dynamic_section_empty() {
+        let output = render_dynamic_section(&[], &[], "ws://example.com:3000");
+        assert!(output.contains("No agents deployed yet"));
+    }
+
+    #[test]
+    fn test_render_dynamic_section_agent_no_persona() {
+        let personas = vec![make_persona("p1", "Builder")];
+        let agents = vec![make_agent("Scout", Some("nonexistent"))];
+        let output = render_dynamic_section(&personas, &agents, "ws://example.com:3000");
+        assert!(output.contains("| Scout | — | @Scout |"));
+    }
+
+    #[test]
+    fn test_upsert_managed_section_with_markers() {
+        let tmp = tempfile::tempdir().unwrap();
+        let file = tmp.path().join("AGENTS.md");
+        fs::write(
+            &file,
+            "# Header\n\nsome content\n\n<!-- BEGIN SPROUT MANAGED — regenerated automatically, do not edit below -->\nold section\n<!-- END SPROUT MANAGED -->\n\nafter\n",
+        )
+        .unwrap();
+
+        upsert_managed_section(&file, "new section").unwrap();
+
+        let result = fs::read_to_string(&file).unwrap();
+        assert!(result.contains("<!-- BEGIN SPROUT MANAGED"));
+        assert!(result.contains("<!-- END SPROUT MANAGED -->"));
+        assert!(result.contains("new section"));
+        assert!(!result.contains("old section"));
+        assert!(result.contains("# Header"));
+        assert!(result.contains("some content"));
+        assert!(result.contains("after"));
+    }
+
+    #[test]
+    fn test_upsert_managed_section_without_markers() {
+        let tmp = tempfile::tempdir().unwrap();
+        let file = tmp.path().join("AGENTS.md");
+        fs::write(&file, "# Header\n\nexisting content\n").unwrap();
+
+        upsert_managed_section(&file, "injected section").unwrap();
+
+        let result = fs::read_to_string(&file).unwrap();
+        assert!(result.contains("# Header"));
+        assert!(result.contains("existing content"));
+        assert!(result.contains("<!-- BEGIN SPROUT MANAGED"));
+        assert!(result.contains("<!-- END SPROUT MANAGED -->"));
+        assert!(result.contains("injected section"));
+        let begin_pos = result.find("<!-- BEGIN SPROUT MANAGED").unwrap();
+        let header_pos = result.find("# Header").unwrap();
+        assert!(
+            header_pos < begin_pos,
+            "original content should precede the managed section"
+        );
+    }
+
+    #[test]
+    fn test_upsert_managed_section_no_tmp_leftover() {
+        let tmp = tempfile::tempdir().unwrap();
+        let file = tmp.path().join("AGENTS.md");
+        fs::write(&file, "# Header\n").unwrap();
+
+        upsert_managed_section(&file, "content").unwrap();
+
+        let tmp_path = file.with_extension("md.tmp");
+        assert!(
+            !tmp_path.exists(),
+            ".tmp file should not exist after successful upsert"
+        );
+    }
 }
diff --git a/desktop/src-tauri/src/managed_agents/nest_agents.md b/desktop/src-tauri/src/managed_agents/nest_agents.md
index 463a6b0689..83ee19c3c2 100644
--- a/desktop/src-tauri/src/managed_agents/nest_agents.md
+++ b/desktop/src-tauri/src/managed_agents/nest_agents.md
@@ -70,3 +70,10 @@ created: 2026-01-15
 - **Never push without approval** — do not `git push` to any remote
 - **Stay on task** — only stage files relevant to your current work
 - **Tagging or @mentioning others** — you can mention other bots or users by simply @'ing them in your message, but you cannot bold, italicize, or otherwise format the mention text if you want them to actually be alerted
+
+<!-- BEGIN SPROUT MANAGED — regenerated automatically, do not edit below -->
+## Active Agents
+
+*(No agents deployed yet. Add agents in the Sprout desktop app.)*
+
+<!-- END SPROUT MANAGED -->

From 2cee21f7bc58419d431d28616f2d204bf195b94f Mon Sep 17 00:00:00 2001
From: Will Pfleger <wpfleger@block.xyz>
Date: Thu, 14 May 2026 14:50:35 -0400
Subject: [PATCH 05/18] fix: gate test-only imports behind #[cfg(test)] in
 nest.rs

BackendKind and RespondTo are only used in test helper constructors.
---
 desktop/src-tauri/src/managed_agents/nest.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/desktop/src-tauri/src/managed_agents/nest.rs b/desktop/src-tauri/src/managed_agents/nest.rs
index 28f2eb045b..65c7041947 100644
--- a/desktop/src-tauri/src/managed_agents/nest.rs
+++ b/desktop/src-tauri/src/managed_agents/nest.rs
@@ -6,9 +6,9 @@
 //!
 //! Idempotent: existing files and directories are never overwritten.
 
-use super::{
-    load_managed_agents, load_personas, BackendKind, ManagedAgentRecord, PersonaRecord, RespondTo,
-};
+use super::{load_managed_agents, load_personas, ManagedAgentRecord, PersonaRecord};
+#[cfg(test)]
+use super::{BackendKind, RespondTo};
 use crate::app_state::AppState;
 use crate::relay::relay_ws_url_with_override;
 use std::fs;

From b58f18c8d601090250e87f30850e25087429fced Mon Sep 17 00:00:00 2001
From: Will Pfleger <wpfleger@block.xyz>
Date: Thu, 14 May 2026 16:23:15 -0400
Subject: [PATCH 06/18] fix(desktop): address review findings for nest
 AGENTS.md regeneration

Fixes identified by crossfire review (Codex + Gemini) and plan author:

- Use tempfile::NamedTempFile for atomic writes instead of deterministic
  .tmp path that races under concurrent regeneration triggers
- Enforce ordered BEGIN/END marker search with line-start anchoring to
  prevent inverted slicing when markers are out of order or mid-line
- Strip orphan BEGIN markers before appending new managed section
- Escape pipe and newline characters in agent/persona names to prevent
  Markdown table corruption
- Rename "Role" column to "Persona" (display_name is a name, not a role)
- Move regenerate_nest_context calls outside lock scope in all mutation
  hooks to reduce lock hold time and eliminate future deadlock risk
- Add 7 adversarial unit tests: marker ordering, orphan cleanup,
  duplicates, code-block false positives, pipe/newline escaping,
  idempotency
---
 desktop/src-tauri/src/commands/agents.rs     |  76 ++---
 desktop/src-tauri/src/commands/personas.rs   |  12 +-
 desktop/src-tauri/src/managed_agents/nest.rs | 317 ++++++++++++++++---
 3 files changed, 325 insertions(+), 80 deletions(-)

diff --git a/desktop/src-tauri/src/commands/agents.rs b/desktop/src-tauri/src/commands/agents.rs
index 1f984b0ba9..c2f89ae1e5 100644
--- a/desktop/src-tauri/src/commands/agents.rs
+++ b/desktop/src-tauri/src/commands/agents.rs
@@ -677,48 +677,50 @@ pub fn delete_managed_agent(
     app: AppHandle,
     state: State<'_, AppState>,
 ) -> Result<(), String> {
-    let _store_guard = state
-        .managed_agents_store_lock
-        .lock()
-        .map_err(|error| error.to_string())?;
-    let mut records = load_managed_agents(&app)?;
-    let mut runtimes = state
-        .managed_agent_processes
-        .lock()
-        .map_err(|error| error.to_string())?;
+    {
+        let _store_guard = state
+            .managed_agents_store_lock
+            .lock()
+            .map_err(|error| error.to_string())?;
+        let mut records = load_managed_agents(&app)?;
+        let mut runtimes = state
+            .managed_agent_processes
+            .lock()
+            .map_err(|error| error.to_string())?;
 
-    if sync_managed_agent_processes(&mut records, &mut runtimes) {
-        save_managed_agents(&app, &records)?;
-    }
+        if sync_managed_agent_processes(&mut records, &mut runtimes) {
+            save_managed_agents(&app, &records)?;
+        }
 
-    // Guard: reject deletion of deployed remote agents unless explicitly forced.
-    // This turns "don't orphan remote infra" from a UI convention into a backend
-    // invariant — a buggy or compromised IPC caller cannot silently orphan a live
-    // remote deployment. The frontend sends force_remote_delete: true only after
-    // the user confirms the orphan warning.
-    if let Some(record) = records.iter().find(|r| r.pubkey == pubkey) {
-        if record.backend != BackendKind::Local
-            && record.backend_agent_id.is_some()
-            && !force_remote_delete.unwrap_or(false)
-        {
-            return Err(
-                "cannot delete a deployed remote agent without force_remote_delete: true"
-                    .to_string(),
-            );
+        // Guard: reject deletion of deployed remote agents unless explicitly forced.
+        // This turns "don't orphan remote infra" from a UI convention into a backend
+        // invariant — a buggy or compromised IPC caller cannot silently orphan a live
+        // remote deployment. The frontend sends force_remote_delete: true only after
+        // the user confirms the orphan warning.
+        if let Some(record) = records.iter().find(|r| r.pubkey == pubkey) {
+            if record.backend != BackendKind::Local
+                && record.backend_agent_id.is_some()
+                && !force_remote_delete.unwrap_or(false)
+            {
+                return Err(
+                    "cannot delete a deployed remote agent without force_remote_delete: true"
+                        .to_string(),
+                );
+            }
         }
-    }
 
-    if let Some(record) = records.iter_mut().find(|record| record.pubkey == pubkey) {
-        // For local agents: kills the process. For remote agents: no-op (the frontend
-        // sends !shutdown via WebSocket before calling delete). Either way, safe.
-        stop_managed_agent_process(&app, record, &mut runtimes)?;
-    }
-    let initial_len = records.len();
-    records.retain(|record| record.pubkey != pubkey);
-    if records.len() == initial_len {
-        return Err(format!("agent {pubkey} not found"));
+        if let Some(record) = records.iter_mut().find(|record| record.pubkey == pubkey) {
+            // For local agents: kills the process. For remote agents: no-op (the frontend
+            // sends !shutdown via WebSocket before calling delete). Either way, safe.
+            stop_managed_agent_process(&app, record, &mut runtimes)?;
+        }
+        let initial_len = records.len();
+        records.retain(|record| record.pubkey != pubkey);
+        if records.len() == initial_len {
+            return Err(format!("agent {pubkey} not found"));
+        }
+        save_managed_agents(&app, &records)?;
     }
-    save_managed_agents(&app, &records)?;
     if let Err(error) = regenerate_nest_context(&app) {
         eprintln!("sprout-desktop: nest context regeneration failed: {error}");
     }
diff --git a/desktop/src-tauri/src/commands/personas.rs b/desktop/src-tauri/src/commands/personas.rs
index 5312429967..39db8a987e 100644
--- a/desktop/src-tauri/src/commands/personas.rs
+++ b/desktop/src-tauri/src/commands/personas.rs
@@ -128,22 +128,20 @@ pub fn update_persona(
         .filter(|s| !s.is_empty())
         .collect();
     if let Some(env_vars) = input.env_vars {
-        // Caller explicitly sent env_vars — replace entirely (empty = clear).
         crate::managed_agents::validate_user_env_keys(&env_vars)?;
         persona.env_vars = env_vars;
     }
-    // Absent env_vars means "don't touch" — preserve existing creds when
-    // the caller only meant to edit a different field.
     persona.updated_at = now_iso();
 
     save_personas(&app, &personas)?;
+    let result = personas
+        .into_iter()
+        .find(|record| record.id == input.id)
+        .ok_or_else(|| format!("persona {} disappeared unexpectedly", input.id))?;
     if let Err(error) = regenerate_nest_context(&app) {
         eprintln!("sprout-desktop: nest context regeneration failed: {error}");
     }
-    personas
-        .into_iter()
-        .find(|record| record.id == input.id)
-        .ok_or_else(|| format!("persona {} disappeared unexpectedly", input.id))
+    Ok(result)
 }
 
 #[tauri::command]
diff --git a/desktop/src-tauri/src/managed_agents/nest.rs b/desktop/src-tauri/src/managed_agents/nest.rs
index 65c7041947..fe6497a372 100644
--- a/desktop/src-tauri/src/managed_agents/nest.rs
+++ b/desktop/src-tauri/src/managed_agents/nest.rs
@@ -35,6 +35,8 @@ const AGENTS_MD: &str = include_str!("nest_agents.md");
 /// Written to ~/.sprout/.claude/skills/sprout-cli/SKILL.md on first init.
 const SPROUT_CLI_SKILL_MD: &str = include_str!("nest_skill.md");
 
+const BEGIN_MARKER: &str = "<!-- BEGIN SPROUT MANAGED";
+const END_MARKER: &str = "<!-- END SPROUT MANAGED -->";
 /// Returns the nest root path (`~/.sprout`), or `None` if the home
 /// directory cannot be resolved.
 pub fn nest_dir() -> Option<PathBuf> {
@@ -239,6 +241,10 @@ const CLI_QUICK_REFERENCE: &str = "\
 `sprout workflows trigger --workflow <id>` — trigger a workflow
 Run `sprout --help` for the full command reference.";
 
+fn escape_md_cell(s: &str) -> String {
+    s.replace('|', "\\|").replace('\n', " ")
+}
+
 pub fn render_dynamic_section(
     personas: &[PersonaRecord],
     agents: &[ManagedAgentRecord],
@@ -249,7 +255,7 @@ pub fn render_dynamic_section(
             .to_string()
     } else {
         let mut table =
-            "## Active Agents\n\n| Name | Role | How to address |\n|------|------|----------------|"
+            "## Active Agents\n\n| Name | Persona | How to address |\n|------|---------|----------------|"
                 .to_string();
         for agent in agents {
             let role = agent
@@ -258,10 +264,9 @@ pub fn render_dynamic_section(
                 .and_then(|pid| personas.iter().find(|p| p.id == pid))
                 .map(|p| p.display_name.as_str())
                 .unwrap_or("—");
-            table.push_str(&format!(
-                "\n| {} | {} | @{} |",
-                agent.name, role, agent.name
-            ));
+            let name = escape_md_cell(&agent.name);
+            let role_escaped = escape_md_cell(role);
+            table.push_str(&format!("\n| {name} | {role_escaped} | @{name} |"));
         }
         table
     };
@@ -269,45 +274,80 @@ pub fn render_dynamic_section(
     format!("{active_agents}\n\n## Workspace\n- Relay: {relay_url}\n\n{CLI_QUICK_REFERENCE}")
 }
 
+/// Find a marker that appears at the start of a line (position 0 or preceded by `\n`).
+fn find_marker_at_line_start(content: &str, marker: &str) -> Option<usize> {
+    let mut search_from = 0;
+    while let Some(pos) = content[search_from..].find(marker) {
+        let abs_pos = search_from + pos;
+        if abs_pos == 0 || content.as_bytes()[abs_pos - 1] == b'\n' {
+            return Some(abs_pos);
+        }
+        search_from = abs_pos + 1;
+    }
+    None
+}
+
+/// Find the first valid ordered BEGIN/END marker pair, both at line starts.
+/// Returns `(begin_line_start, after_end)` byte offsets for slicing.
+fn find_managed_markers(content: &str) -> Option<(usize, usize)> {
+    let begin_pos = find_marker_at_line_start(content, BEGIN_MARKER)?;
+    let begin_line_start = content[..begin_pos].rfind('\n').map(|p| p + 1).unwrap_or(0);
+    let end_pos = content[begin_pos..].find(END_MARKER).map(|p| p + begin_pos)?;
+    let end_of_end = end_pos + END_MARKER.len();
+    let after_end = if content[end_of_end..].starts_with('\n') {
+        end_of_end + 1
+    } else {
+        end_of_end
+    };
+    Some((begin_line_start, after_end))
+}
+
+/// Remove an orphan BEGIN marker line (one with no matching END after it).
+fn strip_orphan_begin_marker(content: &str) -> String {
+    if let Some(pos) = find_marker_at_line_start(content, BEGIN_MARKER) {
+        let line_start = content[..pos].rfind('\n').map(|p| p + 1).unwrap_or(0);
+        let line_end = content[pos..].find('\n').map(|p| pos + p + 1).unwrap_or(content.len());
+        format!(
+            "{}{}",
+            &content[..line_start],
+            content[line_end..].trim_start_matches('\n')
+        )
+    } else {
+        content.to_string()
+    }
+}
+
 pub fn upsert_managed_section(file_path: &Path, new_section_content: &str) -> io::Result<()> {
     let current = fs::read_to_string(file_path)?;
 
-    const BEGIN: &str = "<!-- BEGIN SPROUT MANAGED";
-    const END: &str = "<!-- END SPROUT MANAGED -->";
-
     let replacement = format!(
-        "<!-- BEGIN SPROUT MANAGED — regenerated automatically, do not edit below -->\n{new_section_content}\n<!-- END SPROUT MANAGED -->\n"
+        "{BEGIN_MARKER} — regenerated automatically, do not edit below -->\n{new_section_content}\n{END_MARKER}\n"
     );
 
-    let new_content =
-        if let (Some(begin_pos), Some(end_pos)) = (current.find(BEGIN), current.find(END)) {
-            // Find the start of the BEGIN marker's line.
-            let line_start = current[..begin_pos].rfind('\n').map(|p| p + 1).unwrap_or(0);
-            // END marker spans to the end of its content + the newline after it.
-            let end_of_end = end_pos + END.len();
-            let after_end = if current[end_of_end..].starts_with('\n') {
-                end_of_end + 1
-            } else {
-                end_of_end
-            };
+    let new_content = match find_managed_markers(&current) {
+        Some((begin_line_start, after_end)) => {
             format!(
                 "{}{}{}",
-                &current[..line_start],
+                &current[..begin_line_start],
                 replacement,
                 &current[after_end..]
             )
-        } else {
-            format!("{}\n\n{}", current.trim_end_matches('\n'), replacement)
-        };
-
-    let tmp_path = file_path.with_extension(
-        file_path
-            .extension()
-            .map(|e| format!("{}.tmp", e.to_string_lossy()))
-            .unwrap_or_else(|| "tmp".to_string()),
-    );
-    fs::write(&tmp_path, new_content)?;
-    fs::rename(&tmp_path, file_path)?;
+        }
+        None => {
+            let cleaned = strip_orphan_begin_marker(&current);
+            format!("{}\n\n{}", cleaned.trim_end_matches('\n'), replacement)
+        }
+    };
+
+    let parent = file_path.parent().ok_or_else(|| {
+        io::Error::new(io::ErrorKind::InvalidInput, "file path has no parent directory")
+    })?;
+    let mut tmp = tempfile::NamedTempFile::new_in(parent)?;
+    {
+        use std::io::Write;
+        tmp.write_all(new_content.as_bytes())?;
+    }
+    tmp.persist(file_path).map_err(|e| e.error)?;
 
     Ok(())
 }
@@ -576,6 +616,7 @@ mod tests {
         let agents = vec![make_agent("Kit", Some("p1"))];
         let output = render_dynamic_section(&personas, &agents, "ws://example.com:3000");
         assert!(output.contains("| Kit | Builder | @Kit |"));
+        assert!(output.contains("| Name | Persona | How to address |"));
         assert!(output.contains("## CLI Quick Reference"));
     }
 
@@ -645,10 +686,214 @@ mod tests {
 
         upsert_managed_section(&file, "content").unwrap();
 
-        let tmp_path = file.with_extension("md.tmp");
+        // Verify no stray temp files in the directory
+        let entries: Vec<_> = fs::read_dir(tmp.path())
+            .unwrap()
+            .filter_map(|e| e.ok())
+            .collect();
+        assert_eq!(entries.len(), 1, "only AGENTS.md should remain, no temp files");
+        assert_eq!(entries[0].file_name(), "AGENTS.md");
+    }
+
+    #[test]
+    fn test_upsert_end_before_begin() {
+        // An END marker that precedes a BEGIN marker forms no valid ordered pair.
+        // find_managed_markers returns None (BEGIN found, but no END after it),
+        // so the orphan BEGIN line is stripped and a new block is appended.
+        // The stray END line and content between END and BEGIN remain in the file
+        // because strip_orphan_begin_marker only removes the BEGIN line itself.
+        let tmp = tempfile::tempdir().unwrap();
+        let file = tmp.path().join("AGENTS.md");
+        fs::write(
+            &file,
+            "# Header\n\n<!-- END SPROUT MANAGED -->\nsome middle content\n<!-- BEGIN SPROUT MANAGED — regenerated automatically, do not edit below -->\nold section\n",
+        )
+        .unwrap();
+
+        upsert_managed_section(&file, "new section").unwrap();
+
+        let result = fs::read_to_string(&file).unwrap();
+
+        assert!(result.contains("# Header"), "original header must survive");
+        assert!(result.contains("new section"), "new content must be present");
+        assert!(result.contains("some middle content"), "content between markers must survive");
+
+        // Exactly one BEGIN marker in the output (the orphan was stripped, new one appended).
+        assert_eq!(
+            result.matches(BEGIN_MARKER).count(),
+            1,
+            "exactly one BEGIN marker after orphan cleanup"
+        );
+
+        // The single BEGIN marker must have a matching END marker after it.
+        let begin_pos = result.find(BEGIN_MARKER).expect("BEGIN marker must be present");
+        let end_pos = result[begin_pos..].find(END_MARKER).map(|p| begin_pos + p);
+        assert!(
+            end_pos.is_some(),
+            "an END marker must appear after the appended BEGIN marker"
+        );
+    }
+
+    #[test]
+    fn test_upsert_begin_only_no_end() {
+        // A file with BEGIN but no END has an orphan marker.
+        // find_managed_markers returns None (no END found after BEGIN),
+        // so strip_orphan_begin_marker removes the BEGIN line.
+        // Content that followed the orphan BEGIN is preserved (only the marker line is stripped,
+        // not the body that came after it).
+        let tmp = tempfile::tempdir().unwrap();
+        let file = tmp.path().join("AGENTS.md");
+        fs::write(
+            &file,
+            "# Header\n\nsome content\n\n<!-- BEGIN SPROUT MANAGED — regenerated automatically, do not edit below -->\norphaned section without end marker\n",
+        )
+        .unwrap();
+
+        upsert_managed_section(&file, "fresh section").unwrap();
+
+        let result = fs::read_to_string(&file).unwrap();
+
+        assert!(result.contains("# Header"), "original header must survive");
+        assert!(result.contains("some content"), "original body must survive");
+        assert!(result.contains("fresh section"), "new content must be present");
+
+        let begin_pos = result.find(BEGIN_MARKER).expect("BEGIN marker must be present");
+        let end_pos = result.find(END_MARKER).expect("END marker must be present");
+        assert!(
+            begin_pos < end_pos,
+            "the appended BEGIN marker must precede the appended END marker"
+        );
+
+        // Exactly one BEGIN marker after orphan cleanup.
+        assert_eq!(
+            result.matches(BEGIN_MARKER).count(),
+            1,
+            "exactly one BEGIN marker after orphan cleanup"
+        );
+    }
+
+    #[test]
+    fn test_upsert_duplicate_markers() {
+        let tmp = tempfile::tempdir().unwrap();
+        let file = tmp.path().join("AGENTS.md");
+        fs::write(
+            &file,
+            "# Header\n\n<!-- BEGIN SPROUT MANAGED — regenerated automatically, do not edit below -->\nfirst block\n<!-- END SPROUT MANAGED -->\n\nbetween blocks\n\n<!-- BEGIN SPROUT MANAGED — regenerated automatically, do not edit below -->\nsecond block\n<!-- END SPROUT MANAGED -->\n",
+        )
+        .unwrap();
+
+        upsert_managed_section(&file, "replaced").unwrap();
+
+        let result = fs::read_to_string(&file).unwrap();
+
+        assert!(result.contains("replaced"), "replacement content must be present");
+        assert!(!result.contains("first block"), "first block must be replaced");
+        assert!(result.contains("second block"), "second pair content must survive");
+        assert!(result.contains("between blocks"), "text between pairs must survive");
+    }
+
+    #[test]
+    fn test_upsert_marker_in_code_block() {
+        let tmp = tempfile::tempdir().unwrap();
+        let file = tmp.path().join("AGENTS.md");
+        // Indented by 4 spaces — not at column 0, so should NOT match as a real marker.
+        fs::write(
+            &file,
+            "# Header\n\n    <!-- BEGIN SPROUT MANAGED — some indented marker -->\n\nReal content here\n",
+        )
+        .unwrap();
+
+        upsert_managed_section(&file, "appended content").unwrap();
+
+        let result = fs::read_to_string(&file).unwrap();
+
+        assert!(
+            result.contains("    <!-- BEGIN SPROUT MANAGED — some indented marker -->"),
+            "indented marker inside code block must be preserved verbatim"
+        );
+        assert!(result.contains("appended content"), "new content must be appended");
+        assert!(result.contains("Real content here"), "existing body must survive");
+
+        // The real markers appended at the end must be at line-start (column 0).
+        let begin_pos = result
+            .find("<!-- BEGIN SPROUT MANAGED — regenerated")
+            .expect("regenerated BEGIN marker must be present");
+        assert!(
+            begin_pos == 0 || result.as_bytes()[begin_pos - 1] == b'\n',
+            "appended BEGIN marker must be at line start"
+        );
+    }
+
+    #[test]
+    fn test_render_pipe_in_agent_name() {
+        let personas = vec![make_persona("p1", "Builder")];
+        let agents = vec![make_agent("Kit|Pro", Some("p1"))];
+        let output = render_dynamic_section(&personas, &agents, "ws://example.com:3000");
+
+        assert!(
+            output.contains("Kit\\|Pro"),
+            "pipe in agent name must be escaped as \\|"
+        );
+        // An unescaped bare `|` immediately adjacent to "Kit|Pro" would break table parsing.
+        assert!(
+            !output.contains("| Kit|Pro |"),
+            "unescaped pipe in agent name must not appear as a cell boundary"
+        );
+
+        // The row must start and end with `|` and the escaped name and address must appear.
+        let kit_row = output
+            .lines()
+            .find(|l| l.contains("Kit\\|Pro"))
+            .expect("Kit\\|Pro row must be present");
+        assert!(kit_row.starts_with('|'), "row must start with |");
+        assert!(kit_row.ends_with('|'), "row must end with |");
+        assert!(
+            kit_row.contains("@Kit\\|Pro"),
+            "address cell must use escaped name"
+        );
+    }
+
+    #[test]
+    fn test_render_newline_in_persona_name() {
+        let personas = vec![make_persona("p1", "Builder\nExpert")];
+        let agents = vec![make_agent("Scout", Some("p1"))];
+        let output = render_dynamic_section(&personas, &agents, "ws://example.com:3000");
+
+        assert!(
+            output.contains("Builder Expert"),
+            "newline in persona display_name must be replaced with a space"
+        );
+
+        // The table row for Scout must be a single line (no embedded newline).
+        let scout_row = output
+            .lines()
+            .find(|l| l.contains("Scout"))
+            .expect("Scout row must be present");
         assert!(
-            !tmp_path.exists(),
-            ".tmp file should not exist after successful upsert"
+            scout_row.contains("Builder Expert"),
+            "persona name with newline replaced by space must appear on the Scout row"
+        );
+    }
+
+    #[test]
+    fn test_upsert_idempotent() {
+        let tmp = tempfile::tempdir().unwrap();
+        let file = tmp.path().join("AGENTS.md");
+        fs::write(
+            &file,
+            "# Header\n\n<!-- BEGIN SPROUT MANAGED — regenerated automatically, do not edit below -->\nexisting section\n<!-- END SPROUT MANAGED -->\n",
+        )
+        .unwrap();
+
+        upsert_managed_section(&file, "same content").unwrap();
+        let after_first = fs::read_to_string(&file).unwrap();
+
+        upsert_managed_section(&file, "same content").unwrap();
+        let after_second = fs::read_to_string(&file).unwrap();
+
+        assert_eq!(
+            after_first, after_second,
+            "upsert must be idempotent: second call must not alter the file"
         );
     }
 }

From 9f7c04e12422725603f9c7b7bee6c8a013b5c81a Mon Sep 17 00:00:00 2001
From: Will Pfleger <wpfleger@block.xyz>
Date: Thu, 14 May 2026 16:24:20 -0400
Subject: [PATCH 07/18] style: apply rustfmt to review-fix commit

---
 desktop/src-tauri/src/managed_agents/nest.rs | 78 ++++++++++++++++----
 1 file changed, 62 insertions(+), 16 deletions(-)

diff --git a/desktop/src-tauri/src/managed_agents/nest.rs b/desktop/src-tauri/src/managed_agents/nest.rs
index fe6497a372..b6d747173a 100644
--- a/desktop/src-tauri/src/managed_agents/nest.rs
+++ b/desktop/src-tauri/src/managed_agents/nest.rs
@@ -292,7 +292,9 @@ fn find_marker_at_line_start(content: &str, marker: &str) -> Option<usize> {
 fn find_managed_markers(content: &str) -> Option<(usize, usize)> {
     let begin_pos = find_marker_at_line_start(content, BEGIN_MARKER)?;
     let begin_line_start = content[..begin_pos].rfind('\n').map(|p| p + 1).unwrap_or(0);
-    let end_pos = content[begin_pos..].find(END_MARKER).map(|p| p + begin_pos)?;
+    let end_pos = content[begin_pos..]
+        .find(END_MARKER)
+        .map(|p| p + begin_pos)?;
     let end_of_end = end_pos + END_MARKER.len();
     let after_end = if content[end_of_end..].starts_with('\n') {
         end_of_end + 1
@@ -306,7 +308,10 @@ fn find_managed_markers(content: &str) -> Option<(usize, usize)> {
 fn strip_orphan_begin_marker(content: &str) -> String {
     if let Some(pos) = find_marker_at_line_start(content, BEGIN_MARKER) {
         let line_start = content[..pos].rfind('\n').map(|p| p + 1).unwrap_or(0);
-        let line_end = content[pos..].find('\n').map(|p| pos + p + 1).unwrap_or(content.len());
+        let line_end = content[pos..]
+            .find('\n')
+            .map(|p| pos + p + 1)
+            .unwrap_or(content.len());
         format!(
             "{}{}",
             &content[..line_start],
@@ -340,7 +345,10 @@ pub fn upsert_managed_section(file_path: &Path, new_section_content: &str) -> io
     };
 
     let parent = file_path.parent().ok_or_else(|| {
-        io::Error::new(io::ErrorKind::InvalidInput, "file path has no parent directory")
+        io::Error::new(
+            io::ErrorKind::InvalidInput,
+            "file path has no parent directory",
+        )
     })?;
     let mut tmp = tempfile::NamedTempFile::new_in(parent)?;
     {
@@ -691,7 +699,11 @@ mod tests {
             .unwrap()
             .filter_map(|e| e.ok())
             .collect();
-        assert_eq!(entries.len(), 1, "only AGENTS.md should remain, no temp files");
+        assert_eq!(
+            entries.len(),
+            1,
+            "only AGENTS.md should remain, no temp files"
+        );
         assert_eq!(entries[0].file_name(), "AGENTS.md");
     }
 
@@ -715,8 +727,14 @@ mod tests {
         let result = fs::read_to_string(&file).unwrap();
 
         assert!(result.contains("# Header"), "original header must survive");
-        assert!(result.contains("new section"), "new content must be present");
-        assert!(result.contains("some middle content"), "content between markers must survive");
+        assert!(
+            result.contains("new section"),
+            "new content must be present"
+        );
+        assert!(
+            result.contains("some middle content"),
+            "content between markers must survive"
+        );
 
         // Exactly one BEGIN marker in the output (the orphan was stripped, new one appended).
         assert_eq!(
@@ -726,7 +744,9 @@ mod tests {
         );
 
         // The single BEGIN marker must have a matching END marker after it.
-        let begin_pos = result.find(BEGIN_MARKER).expect("BEGIN marker must be present");
+        let begin_pos = result
+            .find(BEGIN_MARKER)
+            .expect("BEGIN marker must be present");
         let end_pos = result[begin_pos..].find(END_MARKER).map(|p| begin_pos + p);
         assert!(
             end_pos.is_some(),
@@ -754,10 +774,18 @@ mod tests {
         let result = fs::read_to_string(&file).unwrap();
 
         assert!(result.contains("# Header"), "original header must survive");
-        assert!(result.contains("some content"), "original body must survive");
-        assert!(result.contains("fresh section"), "new content must be present");
+        assert!(
+            result.contains("some content"),
+            "original body must survive"
+        );
+        assert!(
+            result.contains("fresh section"),
+            "new content must be present"
+        );
 
-        let begin_pos = result.find(BEGIN_MARKER).expect("BEGIN marker must be present");
+        let begin_pos = result
+            .find(BEGIN_MARKER)
+            .expect("BEGIN marker must be present");
         let end_pos = result.find(END_MARKER).expect("END marker must be present");
         assert!(
             begin_pos < end_pos,
@@ -786,10 +814,22 @@ mod tests {
 
         let result = fs::read_to_string(&file).unwrap();
 
-        assert!(result.contains("replaced"), "replacement content must be present");
-        assert!(!result.contains("first block"), "first block must be replaced");
-        assert!(result.contains("second block"), "second pair content must survive");
-        assert!(result.contains("between blocks"), "text between pairs must survive");
+        assert!(
+            result.contains("replaced"),
+            "replacement content must be present"
+        );
+        assert!(
+            !result.contains("first block"),
+            "first block must be replaced"
+        );
+        assert!(
+            result.contains("second block"),
+            "second pair content must survive"
+        );
+        assert!(
+            result.contains("between blocks"),
+            "text between pairs must survive"
+        );
     }
 
     #[test]
@@ -811,8 +851,14 @@ mod tests {
             result.contains("    <!-- BEGIN SPROUT MANAGED — some indented marker -->"),
             "indented marker inside code block must be preserved verbatim"
         );
-        assert!(result.contains("appended content"), "new content must be appended");
-        assert!(result.contains("Real content here"), "existing body must survive");
+        assert!(
+            result.contains("appended content"),
+            "new content must be appended"
+        );
+        assert!(
+            result.contains("Real content here"),
+            "existing body must survive"
+        );
 
         // The real markers appended at the end must be at line-start (column 0).
         let begin_pos = result

From 2a8d8184519279a6abc8ef7570652d5e8eb0fd1f Mon Sep 17 00:00:00 2001
From: Will Pfleger <wpfleger@block.xyz>
Date: Fri, 15 May 2026 15:51:02 -0400
Subject: [PATCH 08/18] fix(desktop): add nest.rs to file size check overrides
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

nest.rs grew to 770 lines with regenerate_nest_context, marker
helpers, and 19 unit tests. The 500-line default is too tight for
this file — override to 800 following the established pattern.
---
 desktop/scripts/check-file-sizes.mjs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/desktop/scripts/check-file-sizes.mjs b/desktop/scripts/check-file-sizes.mjs
index 2a318254f4..5a15f7c708 100644
--- a/desktop/scripts/check-file-sizes.mjs
+++ b/desktop/scripts/check-file-sizes.mjs
@@ -52,6 +52,7 @@ const overrides = new Map([
   ["src-tauri/src/managed_agents/runtime.rs", 1110], // ... + respond-to gate env (SPROUT_ACP_RESPOND_TO[_ALLOWLIST]) + per-mode env builder + tests + persona/agent env_vars spawn merge (helper + tests now in env_vars.rs)
   ["src-tauri/src/managed_agents/discovery.rs", 680], // KNOWN_ACP_PROVIDERS catalog + resolve_command cache + login_shell_path + classify_provider (four-state: Available/AdapterMissing/CliMissing/NotInstalled) + discover_acp_providers with dynamic install_hint + known_acp_provider/known_acp_provider_exact + normalize_agent_args + 15 unit tests
   ["src-tauri/src/managed_agents/types.rs", 745], // ManagedAgentRecord/Summary + Create/Update request structs + AcpProviderCatalogEntry + InstallRuntimeResult + RespondTo enum + validate_respond_to_allowlist + tests + persona/agent env_vars field
+  ["src-tauri/src/managed_agents/nest.rs", 800], // regenerate_nest_context + render_dynamic_section + upsert_managed_section + marker helpers + 19 unit tests
   ["src-tauri/src/managed_agents/backend.rs", 700], // provider IPC, validation, discovery, binary resolution + tests + redact_secrets_with for user env values + env_secrets_from_request + redact_env_values_in (shared with model discovery)
   ["src/features/huddle/HuddleContext.tsx", 650], // huddle lifecycle context + joinHuddle + connectAndSetupMedia shared helper + activeSpeakers/isReconnecting state + PTT (reusable AudioContext) + TTS subscription + mic level analyser (10fps throttle) + agent pubkey refresh
   ["src/features/agents/hooks.ts", 550], // agent query/mutation surface + useAvailableAcpProviders (type-narrowing filter hook) + useInstallAcpRuntimeMutation + built-in persona library activation

From 6860e1ebab62df3cecfbe04b06c6daeb24d41f54 Mon Sep 17 00:00:00 2001
From: Will Pfleger <wpfleger@block.xyz>
Date: Fri, 15 May 2026 17:13:48 -0400
Subject: [PATCH 09/18] refactor: consolidate PR #583 into #584, remove
 CLI_QUICK_REFERENCE duplication

base_prompt.md (injected every turn via [Base]) already has a comprehensive
CLI reference table covering all 11 command groups. The CLI_QUICK_REFERENCE
constant in nest.rs was a less complete duplicate (4 commands). AGENTS.md's
dynamic section now focuses on what's unique to it: active agents and
workspace info.

Also bumps personas.rs file size override from 900 to 950 to accommodate
the merge_personas inequality checks added in the review-fix commit.
---
 desktop/scripts/check-file-sizes.mjs         |  2 +-
 desktop/src-tauri/src/managed_agents/nest.rs | 11 ++---------
 2 files changed, 3 insertions(+), 10 deletions(-)

diff --git a/desktop/scripts/check-file-sizes.mjs b/desktop/scripts/check-file-sizes.mjs
index 5a15f7c708..47a99aba6a 100644
--- a/desktop/scripts/check-file-sizes.mjs
+++ b/desktop/scripts/check-file-sizes.mjs
@@ -30,7 +30,7 @@ const rules = [
 
 // Exceptions should stay rare and temporary. Prefer splitting files instead.
 const overrides = new Map([
-  ["src-tauri/src/managed_agents/personas.rs", 900], // built-in persona system prompts (Solo + Kit + Scout) + persona pack import/uninstall/list + uninstall safety check
+  ["src-tauri/src/managed_agents/personas.rs", 950], // built-in persona system prompts (Solo + Kit + Scout) + merge_personas inequality checks + persona pack import/uninstall/list + uninstall safety check
   ["src-tauri/src/managed_agents/teams.rs", 580], // built-in team registry (Kit & Scout) + merge_teams + validate_team_deletion + JSON export/import + tests
   ["src-tauri/src/managed_agents/persona_card.rs", 970], // PNG/ZIP/MD persona card codec + pack-zip detection + nested root finder + provider/model/namePool fields + 27 unit tests
   ["src/app/AppShell.tsx", 815], // message edit state + handlers + ChannelPane edit prop threading + scrollback pagination + workflows view + projects view + memory-leak safeguards + home-badge state lifted here so it consumes the same NIP-RS read-state as the sidebar (single ReadStateManager)
diff --git a/desktop/src-tauri/src/managed_agents/nest.rs b/desktop/src-tauri/src/managed_agents/nest.rs
index b6d747173a..ca8ffa5cbb 100644
--- a/desktop/src-tauri/src/managed_agents/nest.rs
+++ b/desktop/src-tauri/src/managed_agents/nest.rs
@@ -233,13 +233,6 @@ pub fn ensure_cli_symlink(_exe_parent: &Path) -> Result<(), String> {
     Ok(())
 }
 
-const CLI_QUICK_REFERENCE: &str = "\
-## CLI Quick Reference
-`sprout messages send --channel <id> --content <text>` — send a message
-`sprout messages get --channel <id>` — read recent messages
-`sprout channels list` — list available channels
-`sprout workflows trigger --workflow <id>` — trigger a workflow
-Run `sprout --help` for the full command reference.";
 
 fn escape_md_cell(s: &str) -> String {
     s.replace('|', "\\|").replace('\n', " ")
@@ -271,7 +264,7 @@ pub fn render_dynamic_section(
         table
     };
 
-    format!("{active_agents}\n\n## Workspace\n- Relay: {relay_url}\n\n{CLI_QUICK_REFERENCE}")
+    format!("{active_agents}\n\n## Workspace\n- Relay: {relay_url}")
 }
 
 /// Find a marker that appears at the start of a line (position 0 or preceded by `\n`).
@@ -625,7 +618,7 @@ mod tests {
         let output = render_dynamic_section(&personas, &agents, "ws://example.com:3000");
         assert!(output.contains("| Kit | Builder | @Kit |"));
         assert!(output.contains("| Name | Persona | How to address |"));
-        assert!(output.contains("## CLI Quick Reference"));
+        assert!(output.contains("## Workspace"));
     }
 
     #[test]

From 782b9033c864093986ec8c332040cc8d00798a75 Mon Sep 17 00:00:00 2001
From: Will Pfleger <wpfleger@block.xyz>
Date: Fri, 15 May 2026 18:10:22 -0400
Subject: [PATCH 10/18] fix: address code review findings from crossfire review

Review surfaced 10 findings across 5 independent sources (3 Claude
specialists + Codex + Gemini). Key changes:

- Fix incorrect CLI syntax in base_prompt.md (missing --channel flag,
  positional arg that should be named) and stale nest_agents.md reference
- Apply line-start validation to END_MARKER in find_managed_markers,
  matching the BEGIN_MARKER contract documented in the function comment
- Extract prepend_base_prompt helper to deduplicate [Base] injection
  across format_prompt, dispatch_heartbeat, and initial_message paths
- Move base_prompt_file read from main.rs panic to Config::from_cli
  with proper ConfigError propagation and 1 MB size guard
- Extract try_regenerate_nest helper to consolidate 11 identical
  error-handling blocks across command files
- Sanitize relay_url before AGENTS.md injection (strip CR/LF)
- Fix greedy newline strip in strip_orphan_begin_marker
- Add doc comments for PromptContext.base_prompt lifetime constraint
---
 crates/sprout-acp/src/base_prompt.md          |  6 ++---
 crates/sprout-acp/src/config.rs               | 26 ++++++++++++++++---
 crates/sprout-acp/src/lib.rs                  | 14 +++++-----
 crates/sprout-acp/src/pool.rs                 | 12 ++++++---
 crates/sprout-acp/src/queue.rs                |  9 +++++++
 .../src-tauri/src/commands/agent_models.rs    |  8 +++---
 desktop/src-tauri/src/commands/agents.rs      | 16 +++++-------
 desktop/src-tauri/src/commands/personas.rs    | 26 +++++--------------
 desktop/src-tauri/src/commands/workspace.rs   |  8 ++----
 desktop/src-tauri/src/lib.rs                  |  8 +++---
 desktop/src-tauri/src/managed_agents/nest.rs  | 22 +++++++++++++---
 11 files changed, 88 insertions(+), 67 deletions(-)

diff --git a/crates/sprout-acp/src/base_prompt.md b/crates/sprout-acp/src/base_prompt.md
index 5f82e213e9..0bd8e60138 100644
--- a/crates/sprout-acp/src/base_prompt.md
+++ b/crates/sprout-acp/src/base_prompt.md
@@ -26,12 +26,12 @@ MCP tools (via `sprout-mcp`) are also available but the CLI is preferred for bat
 
 - Address agents and humans with plain `@name` — do NOT bold or italicize mention text (formatting prevents alert delivery).
 - Use `sprout messages thread` or MCP `get_thread()` when responding in-thread; post new messages for new topics.
-- No push notifications — poll with `sprout messages get --since=<unix_ts>` or MCP `get_messages(since=<ts>)`. When `since` is set without `before`, results are oldest-first (chronological).
+- No push notifications — poll with `sprout messages get --channel <UUID> --since <ts>` or MCP `get_messages(channel_id, since=<ts>)`. When `since` is set without `before`, results are oldest-first (chronological).
 
 ## Startup Recovery
 
 1. `sprout feed get` (or MCP `get_feed()`) — surface pending mentions and action items. Filter by type: `mentions`, `needs_action`, `activity`, `agent_activity`.
-2. `sprout messages get <channel_id>` on assigned channels — catch up on recent history.
+2. `sprout messages get --channel <UUID>` on assigned channels — catch up on recent history.
 3. Check `AGENTS.md` in your working directory for team context.
 4. Check `RESEARCH/`, `GUIDES/`, `PLANS/` before searching externally. Use `sprout messages search --query "..."` for cross-channel keyword lookups.
 
@@ -49,4 +49,4 @@ Your persistent workspace is in your working directory:
 | `REPOS/` | Checked-out source repositories |
 | `.scratch/` | Ephemeral working files |
 
-Knowledge files use `ALL_CAPS_WITH_UNDERSCORES.md` naming. `AGENTS.md` lists active agents and roles. See `nest_agents.md` in your working directory for full workspace conventions.
+Knowledge files use `ALL_CAPS_WITH_UNDERSCORES.md` naming. `AGENTS.md` lists active agents and roles. See `AGENTS.md` in your working directory for full workspace conventions.
diff --git a/crates/sprout-acp/src/config.rs b/crates/sprout-acp/src/config.rs
index 6bbff8fa9a..2a5053a05e 100644
--- a/crates/sprout-acp/src/config.rs
+++ b/crates/sprout-acp/src/config.rs
@@ -477,8 +477,10 @@ pub struct Config {
     pub agent_owner: Option<String>,
     /// Disable the [Base] platform-context section prepended to every prompt.
     pub no_base_prompt: bool,
-    /// Path to a custom base prompt file that overrides the compiled-in default.
-    pub base_prompt_file: Option<PathBuf>,
+    /// Resolved content from `--base-prompt-file`, read and validated in
+    /// `from_cli()`. `None` when using the compiled-in default or when
+    /// `--no-base-prompt` is set.
+    pub base_prompt_content: Option<String>,
 }
 
 /// Validate and deduplicate allowlist entries: each must be exactly 64 hex chars.
@@ -608,6 +610,22 @@ impl Config {
             None
         };
 
+        let base_prompt_content = if args.no_base_prompt {
+            None
+        } else if let Some(ref path) = args.base_prompt_file {
+            let content = std::fs::read_to_string(path)?;
+            if content.len() > 1_048_576 {
+                return Err(ConfigError::ConfigFile(format!(
+                    "base prompt file {} exceeds 1 MB limit ({} bytes)",
+                    path.display(),
+                    content.len()
+                )));
+            }
+            Some(content)
+        } else {
+            None
+        };
+
         if matches!(args.subscribe, SubscribeMode::Config) {
             if args.kinds.is_some() {
                 tracing::warn!("--kinds is ignored in config mode");
@@ -817,7 +835,7 @@ impl Config {
             relay_observer: args.relay_observer,
             agent_owner: args.agent_owner.map(|s| s.trim().to_ascii_lowercase()),
             no_base_prompt: args.no_base_prompt,
-            base_prompt_file: args.base_prompt_file,
+            base_prompt_content,
         };
 
         Ok(config)
@@ -1182,7 +1200,7 @@ mod tests {
             relay_observer: false,
             agent_owner: None,
             no_base_prompt: false,
-            base_prompt_file: None,
+            base_prompt_content: None,
         }
     }
 
diff --git a/crates/sprout-acp/src/lib.rs b/crates/sprout-acp/src/lib.rs
index a57853837a..a82d51f39a 100644
--- a/crates/sprout-acp/src/lib.rs
+++ b/crates/sprout-acp/src/lib.rs
@@ -24,7 +24,7 @@ use pool::{
     AgentPool, CancelMode, OwnedAgent, PromptContext, PromptOutcome, PromptResult, PromptSource,
     SessionState,
 };
-use queue::{EventQueue, QueuedEvent, ThreadTags};
+use queue::{prepend_base_prompt, EventQueue, QueuedEvent, ThreadTags};
 use relay::{HarnessRelay, RelayEventPublisher};
 use sprout_core::kind::{
     KIND_MEMBER_ADDED_NOTIFICATION, KIND_MEMBER_REMOVED_NOTIFICATION, KIND_STREAM_MESSAGE,
@@ -794,7 +794,7 @@ async fn tokio_main() -> Result<()> {
         .compact()
         .init();
 
-    let config = Config::from_cli().map_err(|e| anyhow::anyhow!("configuration error: {e}"))?;
+    let mut config = Config::from_cli().map_err(|e| anyhow::anyhow!("configuration error: {e}"))?;
     tracing::info!("sprout-acp starting: {}", config.summary());
 
     let observer = config
@@ -1069,6 +1069,7 @@ async fn tokio_main() -> Result<()> {
     let dedup_mode = config.dedup_mode;
     let mut queue = EventQueue::new(dedup_mode);
 
+    let base_prompt_content = config.base_prompt_content.take();
     let ctx = Arc::new(PromptContext {
         mcp_servers: build_mcp_servers(&config),
         initial_message: config.initial_message.clone(),
@@ -1078,10 +1079,7 @@ async fn tokio_main() -> Result<()> {
         system_prompt: config.system_prompt.clone(),
         base_prompt: if config.no_base_prompt {
             None
-        } else if let Some(ref path) = config.base_prompt_file {
-            let content = std::fs::read_to_string(path).unwrap_or_else(|e| {
-                panic!("failed to read base prompt file {}: {e}", path.display())
-            });
+        } else if let Some(content) = base_prompt_content {
             Some(Box::leak(content.into_boxed_str()))
         } else {
             Some(include_str!("base_prompt.md"))
@@ -2325,7 +2323,7 @@ fn dispatch_heartbeat(
         .clone()
         .unwrap_or_else(default_heartbeat_prompt);
     let prompt_text = match ctx.base_prompt {
-        Some(bp) => format!("[Base]\n{}\n\n{prompt_text}", bp.trim_end()),
+        Some(bp) => prepend_base_prompt(bp, &prompt_text),
         None => prompt_text,
     };
     let result_tx = pool.result_tx();
@@ -2823,7 +2821,7 @@ mod build_mcp_servers_tests {
             relay_observer: false,
             agent_owner: None,
             no_base_prompt: false,
-            base_prompt_file: None,
+            base_prompt_content: None,
         }
     }
 
diff --git a/crates/sprout-acp/src/pool.rs b/crates/sprout-acp/src/pool.rs
index 7b8ce93ac0..09313f6203 100644
--- a/crates/sprout-acp/src/pool.rs
+++ b/crates/sprout-acp/src/pool.rs
@@ -35,8 +35,8 @@ use crate::acp::{
 use crate::config::{DedupMode, PermissionMode};
 use crate::observer;
 use crate::queue::{
-    ContextMessage, ConversationContext, FlushBatch, PromptChannelInfo, PromptProfile,
-    PromptProfileLookup,
+    prepend_base_prompt, ContextMessage, ConversationContext, FlushBatch, PromptChannelInfo,
+    PromptProfile, PromptProfileLookup,
 };
 use crate::relay::{ChannelInfo, RestClient};
 
@@ -192,6 +192,12 @@ pub struct PromptContext {
     pub dedup_mode: DedupMode,
     pub system_prompt: Option<String>,
     pub heartbeat_prompt: Option<String>,
+    /// Base prompt content, or `None` if `--no-base-prompt` was passed.
+    ///
+    /// `'static` because `PromptContext` is `Arc`-shared across async tasks.
+    /// Content from `--base-prompt-file` is promoted via `Box::leak` in `main.rs`
+    /// after validated file read in `Config::from_cli()`. The compiled-in default
+    /// (`include_str!`) is inherently `'static`.
     pub base_prompt: Option<&'static str>,
     pub cwd: String,
     /// REST client for pre-prompt context fetches (thread/DM history).
@@ -806,7 +812,7 @@ pub async fn run_prompt_task(
             );
             // Prepend base prompt to initial_message for platform orientation.
             let init_msg = match ctx.base_prompt {
-                Some(bp) => format!("[Base]\n{}\n\n{initial_msg}", bp.trim_end()),
+                Some(bp) => prepend_base_prompt(bp, initial_msg),
                 None => initial_msg.to_string(),
             };
             let init_result = agent
diff --git a/crates/sprout-acp/src/queue.rs b/crates/sprout-acp/src/queue.rs
index feeffbd03e..c79bdb144f 100644
--- a/crates/sprout-acp/src/queue.rs
+++ b/crates/sprout-acp/src/queue.rs
@@ -936,6 +936,15 @@ pub struct FormatPromptArgs<'a> {
     pub profile_lookup: Option<&'a PromptProfileLookup>,
 }
 
+/// Prepend the `[Base]` platform-context section to a prompt body.
+///
+/// Used by the heartbeat and initial-message paths so the `[Base]` format
+/// is defined in exactly one place. (`format_prompt` uses a sections-vec
+/// approach instead, but the resulting `[Base]\n{content}` format is identical.)
+pub fn prepend_base_prompt(base: &str, body: &str) -> String {
+    format!("[Base]\n{}\n\n{body}", base.trim_end())
+}
+
 /// Format a [`FlushBatch`] into a prompt string for the agent.
 ///
 /// Produces a stable prompt with these sections (in order):
diff --git a/desktop/src-tauri/src/commands/agent_models.rs b/desktop/src-tauri/src/commands/agent_models.rs
index a016cac377..554469446f 100644
--- a/desktop/src-tauri/src/commands/agent_models.rs
+++ b/desktop/src-tauri/src/commands/agent_models.rs
@@ -8,8 +8,8 @@ use crate::{
     managed_agents::{
         build_managed_agent_summary, default_agent_workdir, find_managed_agent_mut,
         load_managed_agents, managed_agent_avatar_url, missing_command_message,
-        normalize_agent_args, regenerate_nest_context, resolve_command, save_managed_agents,
-        sync_managed_agent_processes, AgentModelInfo, AgentModelsResponse,
+        normalize_agent_args, resolve_command, save_managed_agents,
+        sync_managed_agent_processes, try_regenerate_nest, AgentModelInfo, AgentModelsResponse,
         UpdateManagedAgentRequest, UpdateManagedAgentResponse, DEFAULT_MCP_COMMAND,
     },
     relay::{relay_ws_url_with_override, sync_managed_agent_profile},
@@ -251,9 +251,7 @@ pub async fn update_managed_agent(
         (summary, sync_params)
     }; // lock dropped here
 
-    if let Err(error) = regenerate_nest_context(&app) {
-        eprintln!("sprout-desktop: nest context regeneration failed: {error}");
-    }
+    try_regenerate_nest(&app);
 
     // Phase 2: relay profile sync (async, best-effort, outside lock)
     let profile_sync_error =
diff --git a/desktop/src-tauri/src/commands/agents.rs b/desktop/src-tauri/src/commands/agents.rs
index c2f89ae1e5..a1d582456e 100644
--- a/desktop/src-tauri/src/commands/agents.rs
+++ b/desktop/src-tauri/src/commands/agents.rs
@@ -7,10 +7,10 @@ use crate::{
         build_managed_agent_summary, discover_provider_candidates, ensure_persona_is_active,
         find_managed_agent_mut, invoke_provider, load_managed_agents, load_personas,
         managed_agent_avatar_url, managed_agent_log_path, managed_agents_base_dir,
-        normalize_agent_args, provider_deploy, read_log_tail, regenerate_nest_context,
-        resolve_provider_binary, save_managed_agents, start_managed_agent_process,
-        stop_managed_agent_process, sync_managed_agent_processes, validate_provider_config,
-        BackendKind, BackendProviderInfo, CreateManagedAgentRequest, CreateManagedAgentResponse,
+        normalize_agent_args, provider_deploy, read_log_tail, resolve_provider_binary,
+        save_managed_agents, start_managed_agent_process, stop_managed_agent_process,
+        sync_managed_agent_processes, try_regenerate_nest, validate_provider_config, BackendKind,
+        BackendProviderInfo, CreateManagedAgentRequest, CreateManagedAgentResponse,
         ManagedAgentLogResponse, ManagedAgentRecord, ManagedAgentSummary, DEFAULT_ACP_COMMAND,
         DEFAULT_AGENT_COMMAND, DEFAULT_AGENT_PARALLELISM, DEFAULT_AGENT_TURN_TIMEOUT_SECONDS,
         DEFAULT_MCP_COMMAND,
@@ -453,9 +453,7 @@ pub async fn create_managed_agent(
         (agent, spawn_error)
     };
 
-    if let Err(error) = regenerate_nest_context(&app) {
-        eprintln!("sprout-desktop: nest context regeneration failed: {error}");
-    }
+    try_regenerate_nest(&app);
 
     // ── Phase 4: sync agent profile on relay (async, outside lock) ───────────
     let avatar_url = input
@@ -721,9 +719,7 @@ pub fn delete_managed_agent(
         }
         save_managed_agents(&app, &records)?;
     }
-    if let Err(error) = regenerate_nest_context(&app) {
-        eprintln!("sprout-desktop: nest context regeneration failed: {error}");
-    }
+    try_regenerate_nest(&app);
     Ok(())
 }
 
diff --git a/desktop/src-tauri/src/commands/personas.rs b/desktop/src-tauri/src/commands/personas.rs
index 39db8a987e..b3d0d45040 100644
--- a/desktop/src-tauri/src/commands/personas.rs
+++ b/desktop/src-tauri/src/commands/personas.rs
@@ -7,7 +7,7 @@ use crate::{
     managed_agents::{
         encode_persona_json, import_persona_pack, list_installed_packs, load_managed_agents,
         load_personas, load_teams, parse_json_persona, parse_md_persona, parse_png_persona,
-        parse_zip_personas, regenerate_nest_context, save_managed_agents, save_personas,
+        parse_zip_personas, save_managed_agents, save_personas, try_regenerate_nest,
         uninstall_persona_pack as do_uninstall_persona_pack, validate_persona_activation_change,
         validate_persona_deletion, CreatePersonaRequest, PackSummary, ParsePersonaFilesResult,
         PersonaRecord, UpdatePersonaRequest,
@@ -85,9 +85,7 @@ pub fn create_persona(
     };
     personas.push(persona.clone());
     save_personas(&app, &personas)?;
-    if let Err(error) = regenerate_nest_context(&app) {
-        eprintln!("sprout-desktop: nest context regeneration failed: {error}");
-    }
+    try_regenerate_nest(&app);
     Ok(persona)
 }
 
@@ -138,9 +136,7 @@ pub fn update_persona(
         .into_iter()
         .find(|record| record.id == input.id)
         .ok_or_else(|| format!("persona {} disappeared unexpectedly", input.id))?;
-    if let Err(error) = regenerate_nest_context(&app) {
-        eprintln!("sprout-desktop: nest context regeneration failed: {error}");
-    }
+    try_regenerate_nest(&app);
     Ok(result)
 }
 
@@ -186,9 +182,7 @@ pub fn delete_persona(
     if changed_agents {
         save_managed_agents(&app, &agents)?;
     }
-    if let Err(error) = regenerate_nest_context(&app) {
-        eprintln!("sprout-desktop: nest context regeneration failed: {error}");
-    }
+    try_regenerate_nest(&app);
 
     Ok(())
 }
@@ -237,9 +231,7 @@ pub fn set_persona_active(
 
     let updated = persona.clone();
     save_personas(&app, &personas)?;
-    if let Err(error) = regenerate_nest_context(&app) {
-        eprintln!("sprout-desktop: nest context regeneration failed: {error}");
-    }
+    try_regenerate_nest(&app);
     Ok(updated)
 }
 
@@ -394,9 +386,7 @@ pub fn install_persona_pack(
         return Err(format!("pack path is not a directory: {path}"));
     }
     let result = import_persona_pack(&app, &source)?;
-    if let Err(error) = regenerate_nest_context(&app) {
-        eprintln!("sprout-desktop: nest context regeneration failed: {error}");
-    }
+    try_regenerate_nest(&app);
     Ok(result)
 }
 
@@ -411,9 +401,7 @@ pub fn uninstall_persona_pack(
         .lock()
         .map_err(|e| e.to_string())?;
     do_uninstall_persona_pack(&app, &pack_id)?;
-    if let Err(error) = regenerate_nest_context(&app) {
-        eprintln!("sprout-desktop: nest context regeneration failed: {error}");
-    }
+    try_regenerate_nest(&app);
     Ok(())
 }
 
diff --git a/desktop/src-tauri/src/commands/workspace.rs b/desktop/src-tauri/src/commands/workspace.rs
index 615dd2324c..79ca43f971 100644
--- a/desktop/src-tauri/src/commands/workspace.rs
+++ b/desktop/src-tauri/src/commands/workspace.rs
@@ -3,7 +3,7 @@ use serde::Serialize;
 use tauri::{AppHandle, State};
 
 use crate::app_state::AppState;
-use crate::managed_agents::regenerate_nest_context;
+use crate::managed_agents::try_regenerate_nest;
 use crate::relay;
 
 #[derive(Serialize)]
@@ -53,11 +53,7 @@ pub fn apply_workspace(
         *keys_guard = keys;
     }
 
-    if let Err(error) = regenerate_nest_context(&app) {
-        eprintln!(
-            "sprout-desktop: failed to regenerate nest context after workspace switch: {error}"
-        );
-    }
+    try_regenerate_nest(&app);
 
     Ok(())
 }
diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs
index f5b12775a3..72e5ced0d4 100644
--- a/desktop/src-tauri/src/lib.rs
+++ b/desktop/src-tauri/src/lib.rs
@@ -24,9 +24,9 @@ use huddle::{
     speak_agent_message, start_huddle, start_stt_pipeline,
 };
 use managed_agents::{
-    ensure_nest, kill_stale_tracked_processes, load_managed_agents, regenerate_nest_context,
+    ensure_nest, kill_stale_tracked_processes, load_managed_agents,
     restore_managed_agents_on_launch, save_managed_agents, sync_managed_agent_processes,
-    BackendKind, ManagedAgentProcess,
+    try_regenerate_nest, BackendKind, ManagedAgentProcess,
 };
 use std::sync::{
     atomic::{AtomicBool, Ordering},
@@ -403,9 +403,7 @@ pub fn run() {
                 }
             }
 
-            if let Err(error) = regenerate_nest_context(&app_handle) {
-                eprintln!("sprout-desktop: failed to regenerate nest context: {error}");
-            }
+            try_regenerate_nest(&app_handle);
 
 
             // Pre-download voice models in the background so they're ready
diff --git a/desktop/src-tauri/src/managed_agents/nest.rs b/desktop/src-tauri/src/managed_agents/nest.rs
index ca8ffa5cbb..e7986715f3 100644
--- a/desktop/src-tauri/src/managed_agents/nest.rs
+++ b/desktop/src-tauri/src/managed_agents/nest.rs
@@ -264,6 +264,7 @@ pub fn render_dynamic_section(
         table
     };
 
+    let relay_url = relay_url.replace(['\n', '\r'], "");
     format!("{active_agents}\n\n## Workspace\n- Relay: {relay_url}")
 }
 
@@ -285,9 +286,8 @@ fn find_marker_at_line_start(content: &str, marker: &str) -> Option<usize> {
 fn find_managed_markers(content: &str) -> Option<(usize, usize)> {
     let begin_pos = find_marker_at_line_start(content, BEGIN_MARKER)?;
     let begin_line_start = content[..begin_pos].rfind('\n').map(|p| p + 1).unwrap_or(0);
-    let end_pos = content[begin_pos..]
-        .find(END_MARKER)
-        .map(|p| p + begin_pos)?;
+    let end_pos =
+        find_marker_at_line_start(&content[begin_pos..], END_MARKER).map(|p| p + begin_pos)?;
     let end_of_end = end_pos + END_MARKER.len();
     let after_end = if content[end_of_end..].starts_with('\n') {
         end_of_end + 1
@@ -308,7 +308,9 @@ fn strip_orphan_begin_marker(content: &str) -> String {
         format!(
             "{}{}",
             &content[..line_start],
-            content[line_end..].trim_start_matches('\n')
+            content[line_end..]
+                .strip_prefix('\n')
+                .unwrap_or(&content[line_end..])
         )
     } else {
         content.to_string()
@@ -372,6 +374,16 @@ pub fn regenerate_nest_context(app: &AppHandle) -> Result<(), String> {
     Ok(())
 }
 
+/// Convenience wrapper: regenerates nest context, logging a warning on failure.
+///
+/// All call sites treat regeneration as fire-and-forget — agents run fine with
+/// a stale AGENTS.md, so we warn and continue rather than propagating the error.
+pub fn try_regenerate_nest(app: &AppHandle) {
+    if let Err(error) = regenerate_nest_context(app) {
+        eprintln!("sprout-desktop: nest context regeneration failed: {error}");
+    }
+}
+
 
 #[cfg(test)]
 mod tests {
@@ -569,6 +581,7 @@ mod tests {
             is_active: true,
             source_pack: None,
             source_pack_persona_slug: None,
+            env_vars: std::collections::BTreeMap::new(),
             created_at: String::new(),
             updated_at: String::new(),
         }
@@ -608,6 +621,7 @@ mod tests {
             last_error: None,
             respond_to: RespondTo::default(),
             respond_to_allowlist: vec![],
+            env_vars: std::collections::BTreeMap::new(),
         }
     }
 

From 9c974ea040ed4f90cbbb8addd085088f96a0961f Mon Sep 17 00:00:00 2001
From: Will Pfleger <wpfleger@block.xyz>
Date: Fri, 22 May 2026 11:35:04 -0400
Subject: [PATCH 11/18] style: fix formatting and bump nest.rs file size
 override

rustfmt fixes after rebase onto main (extra blank lines in lib.rs and
nest.rs). Bump nest.rs file size override from 800 to 960 to account
for skill file init code merged from #613.

Signed-off-by: Will Pfleger <wpfleger@block.xyz>
---
 desktop/scripts/check-file-sizes.mjs         | 2 +-
 desktop/src-tauri/src/lib.rs                 | 1 -
 desktop/src-tauri/src/managed_agents/nest.rs | 2 --
 3 files changed, 1 insertion(+), 4 deletions(-)

diff --git a/desktop/scripts/check-file-sizes.mjs b/desktop/scripts/check-file-sizes.mjs
index 47a99aba6a..53a6834964 100644
--- a/desktop/scripts/check-file-sizes.mjs
+++ b/desktop/scripts/check-file-sizes.mjs
@@ -52,7 +52,7 @@ const overrides = new Map([
   ["src-tauri/src/managed_agents/runtime.rs", 1110], // ... + respond-to gate env (SPROUT_ACP_RESPOND_TO[_ALLOWLIST]) + per-mode env builder + tests + persona/agent env_vars spawn merge (helper + tests now in env_vars.rs)
   ["src-tauri/src/managed_agents/discovery.rs", 680], // KNOWN_ACP_PROVIDERS catalog + resolve_command cache + login_shell_path + classify_provider (four-state: Available/AdapterMissing/CliMissing/NotInstalled) + discover_acp_providers with dynamic install_hint + known_acp_provider/known_acp_provider_exact + normalize_agent_args + 15 unit tests
   ["src-tauri/src/managed_agents/types.rs", 745], // ManagedAgentRecord/Summary + Create/Update request structs + AcpProviderCatalogEntry + InstallRuntimeResult + RespondTo enum + validate_respond_to_allowlist + tests + persona/agent env_vars field
-  ["src-tauri/src/managed_agents/nest.rs", 800], // regenerate_nest_context + render_dynamic_section + upsert_managed_section + marker helpers + 19 unit tests
+  ["src-tauri/src/managed_agents/nest.rs", 960], // ensure_nest_at (AGENTS.md + SKILL.md + permissions) + ensure_cli_symlink + regenerate_nest_context + render_dynamic_section + upsert_managed_section + marker helpers + 19 unit tests
   ["src-tauri/src/managed_agents/backend.rs", 700], // provider IPC, validation, discovery, binary resolution + tests + redact_secrets_with for user env values + env_secrets_from_request + redact_env_values_in (shared with model discovery)
   ["src/features/huddle/HuddleContext.tsx", 650], // huddle lifecycle context + joinHuddle + connectAndSetupMedia shared helper + activeSpeakers/isReconnecting state + PTT (reusable AudioContext) + TTS subscription + mic level analyser (10fps throttle) + agent pubkey refresh
   ["src/features/agents/hooks.ts", 550], // agent query/mutation surface + useAvailableAcpProviders (type-narrowing filter hook) + useInstallAcpRuntimeMutation + built-in persona library activation
diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs
index 72e5ced0d4..7c32284cdb 100644
--- a/desktop/src-tauri/src/lib.rs
+++ b/desktop/src-tauri/src/lib.rs
@@ -405,7 +405,6 @@ pub fn run() {
 
             try_regenerate_nest(&app_handle);
 
-
             // Pre-download voice models in the background so they're ready
             // when the user starts their first huddle. Idempotent — no-op if
             // already downloaded. ~289 MB total (~100 MB Parakeet STT + ~189 MB Pocket TTS).
diff --git a/desktop/src-tauri/src/managed_agents/nest.rs b/desktop/src-tauri/src/managed_agents/nest.rs
index e7986715f3..f34c9d0280 100644
--- a/desktop/src-tauri/src/managed_agents/nest.rs
+++ b/desktop/src-tauri/src/managed_agents/nest.rs
@@ -233,7 +233,6 @@ pub fn ensure_cli_symlink(_exe_parent: &Path) -> Result<(), String> {
     Ok(())
 }
 
-
 fn escape_md_cell(s: &str) -> String {
     s.replace('|', "\\|").replace('\n', " ")
 }
@@ -384,7 +383,6 @@ pub fn try_regenerate_nest(app: &AppHandle) {
     }
 }
 
-
 #[cfg(test)]
 mod tests {
     use super::*;

From bfcee93443afeee77da629a8d4da764391d8ee11 Mon Sep 17 00:00:00 2001
From: Will Pfleger <wpfleger@block.xyz>
Date: Fri, 22 May 2026 20:50:47 -0400
Subject: [PATCH 12/18] refactor: replace MCP tool references with CLI commands
 in agent prompts

Agent-facing prompts (base prompt, context hints, heartbeat, AGENTS.md
template) still referenced MCP function-call syntax despite the CLI
migration. Additionally, existing users never received template updates
because nest files used write-once semantics.

Strip all MCP references from the four agent-facing sources compiled
into the binary. Add version-gated refresh to ensure_nest_at so
AGENTS.md static content (above managed markers) and SKILL.md are
updated on binary upgrades while preserving the dynamic agent table.



# Conflicts:
#	desktop/scripts/check-file-sizes.mjs
---
 crates/sprout-acp/src/base_prompt.md          |   8 +-
 crates/sprout-acp/src/lib.rs                  |  13 +-
 crates/sprout-acp/src/queue.rs                |  64 +++---
 desktop/scripts/check-file-sizes.mjs          |   2 +-
 desktop/src-tauri/src/managed_agents/nest.rs  | 210 +++++++++++++++++-
 .../src/managed_agents/nest_agents.md         |  29 +--
 6 files changed, 252 insertions(+), 74 deletions(-)

diff --git a/crates/sprout-acp/src/base_prompt.md b/crates/sprout-acp/src/base_prompt.md
index 0bd8e60138..5bec467702 100644
--- a/crates/sprout-acp/src/base_prompt.md
+++ b/crates/sprout-acp/src/base_prompt.md
@@ -20,17 +20,15 @@ The `sprout` CLI is your primary interface. Auth env vars: `SPROUT_RELAY_URL`, `
 
 Run `sprout --help` or `sprout <group> --help` for full usage.
 
-MCP tools (via `sprout-mcp`) are also available but the CLI is preferred for batch operations and scripting.
-
 ## Communication Patterns
 
 - Address agents and humans with plain `@name` — do NOT bold or italicize mention text (formatting prevents alert delivery).
-- Use `sprout messages thread` or MCP `get_thread()` when responding in-thread; post new messages for new topics.
-- No push notifications — poll with `sprout messages get --channel <UUID> --since <ts>` or MCP `get_messages(channel_id, since=<ts>)`. When `since` is set without `before`, results are oldest-first (chronological).
+- Use `sprout messages thread` when responding in-thread; post new messages for new topics.
+- No push notifications — poll with `sprout messages get --channel <UUID> --since <ts>`. When `since` is set without `before`, results are oldest-first (chronological).
 
 ## Startup Recovery
 
-1. `sprout feed get` (or MCP `get_feed()`) — surface pending mentions and action items. Filter by type: `mentions`, `needs_action`, `activity`, `agent_activity`.
+1. `sprout feed get` — surface pending mentions and action items. Filter by type: `mentions`, `needs_action`, `activity`, `agent_activity`.
 2. `sprout messages get --channel <UUID>` on assigned channels — catch up on recent history.
 3. Check `AGENTS.md` in your working directory for team context.
 4. Check `RESEARCH/`, `GUIDES/`, `PLANS/` before searching externally. Use `sprout messages search --query "..."` for cross-channel keyword lookups.
diff --git a/crates/sprout-acp/src/lib.rs b/crates/sprout-acp/src/lib.rs
index a82d51f39a..0b26ccd895 100644
--- a/crates/sprout-acp/src/lib.rs
+++ b/crates/sprout-acp/src/lib.rs
@@ -2356,14 +2356,15 @@ fn default_heartbeat_prompt() -> String {
          You have been awakened for a routine heartbeat. You have NO incoming messages or\n\
          active channel context for this turn.\n\n\
          Your tasks:\n\
-         1. Call `get_feed(types='needs_action')` to check for pending workflow approvals or\n\
+         1. Run `sprout feed get --types needs_action` to check for pending workflow approvals or\n\
             high-priority requests addressed to you.\n\
-         2. Call `get_feed(types='mentions')` to check for unanswered @mentions.\n\
-         3. If you find actionable items, address them using the appropriate tools\n\
-            (e.g., `approve_step`, `send_message`, `send_message(parent_event_id=...)`).\n\
+         2. Run `sprout feed get --types mentions` to check for unanswered @mentions.\n\
+         3. If you find actionable items, address them using the appropriate CLI commands\n\
+            (e.g., `sprout workflows approve --token <UUID>`, `sprout messages send`,\n\
+            `sprout messages send --reply-to <event-id>`).\n\
          4. If there are no pending actions or mentions, end your turn immediately.\n\n\
-         Do not call `list_channels()` or `search()` unless you have a specific reason.\n\
-         Do not invent work — only act on items surfaced by the feed tools."
+         Do not run `sprout channels list` or `sprout messages search` unless you have a specific reason.\n\
+         Do not invent work — only act on items surfaced by the feed commands."
     )
 }
 
diff --git a/crates/sprout-acp/src/queue.rs b/crates/sprout-acp/src/queue.rs
index c79bdb144f..8fba7c78b2 100644
--- a/crates/sprout-acp/src/queue.rs
+++ b/crates/sprout-acp/src/queue.rs
@@ -799,14 +799,14 @@ fn format_event_block(
 
 /// Append a reply instruction when the agent is responding to a thread event.
 ///
-/// Tells the agent to pass the triggering event's ID as `parent_event_id` on
-/// every tool call in this turn, and to leave `broadcast_to_channel` unset so
-/// replies stay inside the thread.
+/// Tells the agent to pass `--reply-to <event_id>` on every `sprout messages
+/// send` call in this turn, and not to broadcast to the channel so replies
+/// stay inside the thread.
 fn append_reply_instruction(s: &mut String, event_id: &str) {
     s.push_str(&format!(
-        "\nIMPORTANT: When responding, pass parent_event_id=\"{event_id}\" \
-         on EVERY send_message and send_diff_message call in this turn. \
-         Do not set broadcast_to_channel."
+        "\nIMPORTANT: When responding, use `--reply-to {event_id}` \
+         on EVERY `sprout messages send` call in this turn. \
+         Do not broadcast to the channel."
     ));
 }
 
@@ -828,16 +828,16 @@ fn format_context_hints(
     // and the scope should be "dm" (not "thread") because the agent is in a DM.
     if is_dm {
         let is_reply = thread_tags.root_event_id.is_some();
-        // DM replies use get_thread() because /messages excludes thread replies.
-        // DM non-replies use get_messages() for recent conversation.
+        // DM replies use thread command because /messages excludes thread replies.
+        // DM non-replies use get for recent conversation.
         let ctx_hint = if has_conversation_context && is_reply {
-            "Thread context included below. Use get_thread() for full history if truncated."
+            "Thread context included below. Use `sprout messages thread --channel <UUID> --event <ID>` for full history if truncated."
         } else if has_conversation_context {
-            "Conversation context included below. Use get_messages() for full history if truncated."
+            "Conversation context included below. Use `sprout messages get --channel <UUID>` for full history if truncated."
         } else if is_reply {
-            "Use get_thread() to fetch the reply chain."
+            "Use `sprout messages thread --channel <UUID> --event <ID>` to fetch the reply chain."
         } else {
-            "Use get_messages() for conversation context."
+            "Use `sprout messages get --channel <UUID>` for conversation context."
         };
         let mut s = format!(
             "[Context]\n\
@@ -860,9 +860,9 @@ fn format_context_hints(
         s
     } else if let Some(ref root) = thread_tags.root_event_id {
         let ctx_hint = if has_conversation_context {
-            "Thread context included below. Use get_thread() for full history if truncated."
+            "Thread context included below. Use `sprout messages thread --channel <UUID> --event <ID>` for full history if truncated."
         } else {
-            "Use get_thread() to fetch thread context."
+            "Use `sprout messages thread --channel <UUID> --event <ID>` to fetch thread context."
         };
         let mut s = format!(
             "[Context]\n\
@@ -885,7 +885,7 @@ fn format_context_hints(
             "[Context]\n\
              Scope: channel\n\
              Channel: {channel_display}\n\
-             Hint: Use get_messages() for recent messages if needed."
+             Hint: Use `sprout messages get --channel <UUID>` for recent messages if needed."
         )
     }
 }
@@ -2364,10 +2364,10 @@ mod tests {
             prompt.contains("Scope: dm"),
             "DM reply should have Scope: dm, got:\n{prompt}"
         );
-        // Hint should point to get_thread(), not get_messages().
+        // Hint should point to the thread command, not get.
         assert!(
-            prompt.contains("get_thread()"),
-            "DM reply hint should mention get_thread(), got:\n{prompt}"
+            prompt.contains("sprout messages thread"),
+            "DM reply hint should mention `sprout messages thread`, got:\n{prompt}"
         );
         // Thread structural info should be present.
         assert!(
@@ -2406,12 +2406,12 @@ mod tests {
         );
         assert!(prompt.contains("Scope: dm"));
         assert!(
-            prompt.contains("get_messages()"),
-            "DM non-reply hint should mention get_messages()"
+            prompt.contains("sprout messages get"),
+            "DM non-reply hint should mention `sprout messages get`"
         );
         assert!(
-            !prompt.contains("get_thread()"),
-            "DM non-reply should NOT mention get_thread()"
+            !prompt.contains("sprout messages thread"),
+            "DM non-reply should NOT mention `sprout messages thread`"
         );
     }
 
@@ -2801,11 +2801,11 @@ mod tests {
 
         let prompt = format_prompt(&batch, &FormatPromptArgs::default());
         assert!(
-            prompt.contains(&format!("parent_event_id=\"{event_id}\"")),
+            prompt.contains(&format!("--reply-to {event_id}")),
             "channel thread reply should include reply instruction with triggering event ID"
         );
         assert!(
-            prompt.contains("Do not set broadcast_to_channel"),
+            prompt.contains("Do not broadcast to the channel"),
             "channel thread reply should include broadcast suppression hint"
         );
     }
@@ -2841,7 +2841,7 @@ mod tests {
             },
         );
         assert!(
-            prompt.contains(&format!("parent_event_id=\"{event_id}\"")),
+            prompt.contains(&format!("--reply-to {event_id}")),
             "DM thread reply should include reply instruction"
         );
     }
@@ -2862,7 +2862,7 @@ mod tests {
 
         let prompt = format_prompt(&batch, &FormatPromptArgs::default());
         assert!(
-            !prompt.contains("parent_event_id"),
+            !prompt.contains("--reply-to"),
             "top-level message should NOT include reply instruction"
         );
     }
@@ -2893,7 +2893,7 @@ mod tests {
             },
         );
         assert!(
-            !prompt.contains("parent_event_id"),
+            !prompt.contains("--reply-to"),
             "DM non-reply should NOT include reply instruction"
         );
     }
@@ -2924,15 +2924,15 @@ mod tests {
         let prompt = format_prompt(&batch, &FormatPromptArgs::default());
         // The instruction should use the triggering event's own ID — not root or parent.
         assert!(
-            prompt.contains(&format!("parent_event_id=\"{event_id}\"")),
+            prompt.contains(&format!("--reply-to {event_id}")),
             "nested reply instruction should use the triggering event ID"
         );
         assert!(
-            !prompt.contains(&format!("parent_event_id=\"{root_id}\"")),
+            !prompt.contains(&format!("--reply-to {root_id}")),
             "instruction should NOT use root_event_id"
         );
         assert!(
-            !prompt.contains(&format!("parent_event_id=\"{parent_id}\"")),
+            !prompt.contains(&format!("--reply-to {parent_id}")),
             "instruction should NOT use parent_event_id from tags"
         );
     }
@@ -2966,7 +2966,7 @@ mod tests {
 
         let prompt = format_prompt(&batch, &FormatPromptArgs::default());
         assert!(
-            prompt.contains(&format!("parent_event_id=\"{threaded_id}\"")),
+            prompt.contains(&format!("--reply-to {threaded_id}")),
             "batched prompt should use last (threaded) event's ID"
         );
     }
@@ -2999,7 +2999,7 @@ mod tests {
 
         let prompt = format_prompt(&batch, &FormatPromptArgs::default());
         assert!(
-            !prompt.contains("parent_event_id"),
+            !prompt.contains("--reply-to"),
             "batched prompt where last event is top-level should NOT include reply instruction"
         );
     }
diff --git a/desktop/scripts/check-file-sizes.mjs b/desktop/scripts/check-file-sizes.mjs
index 53a6834964..27e717064b 100644
--- a/desktop/scripts/check-file-sizes.mjs
+++ b/desktop/scripts/check-file-sizes.mjs
@@ -52,7 +52,7 @@ const overrides = new Map([
   ["src-tauri/src/managed_agents/runtime.rs", 1110], // ... + respond-to gate env (SPROUT_ACP_RESPOND_TO[_ALLOWLIST]) + per-mode env builder + tests + persona/agent env_vars spawn merge (helper + tests now in env_vars.rs)
   ["src-tauri/src/managed_agents/discovery.rs", 680], // KNOWN_ACP_PROVIDERS catalog + resolve_command cache + login_shell_path + classify_provider (four-state: Available/AdapterMissing/CliMissing/NotInstalled) + discover_acp_providers with dynamic install_hint + known_acp_provider/known_acp_provider_exact + normalize_agent_args + 15 unit tests
   ["src-tauri/src/managed_agents/types.rs", 745], // ManagedAgentRecord/Summary + Create/Update request structs + AcpProviderCatalogEntry + InstallRuntimeResult + RespondTo enum + validate_respond_to_allowlist + tests + persona/agent env_vars field
-  ["src-tauri/src/managed_agents/nest.rs", 960], // ensure_nest_at (AGENTS.md + SKILL.md + permissions) + ensure_cli_symlink + regenerate_nest_context + render_dynamic_section + upsert_managed_section + marker helpers + 19 unit tests
+  ["src-tauri/src/managed_agents/nest.rs", 1160], // ensure_nest_at (AGENTS.md + SKILL.md + permissions) + ensure_cli_symlink + regenerate_nest_context + render_dynamic_section + upsert_managed_section + marker helpers + version-gated refresh (refresh_agents_md_if_stale + refresh_skill_md_if_stale) + 25 unit tests
   ["src-tauri/src/managed_agents/backend.rs", 700], // provider IPC, validation, discovery, binary resolution + tests + redact_secrets_with for user env values + env_secrets_from_request + redact_env_values_in (shared with model discovery)
   ["src/features/huddle/HuddleContext.tsx", 650], // huddle lifecycle context + joinHuddle + connectAndSetupMedia shared helper + activeSpeakers/isReconnecting state + PTT (reusable AudioContext) + TTS subscription + mic level analyser (10fps throttle) + agent pubkey refresh
   ["src/features/agents/hooks.ts", 550], // agent query/mutation surface + useAvailableAcpProviders (type-narrowing filter hook) + useInstallAcpRuntimeMutation + built-in persona library activation
diff --git a/desktop/src-tauri/src/managed_agents/nest.rs b/desktop/src-tauri/src/managed_agents/nest.rs
index f34c9d0280..b3255ec5da 100644
--- a/desktop/src-tauri/src/managed_agents/nest.rs
+++ b/desktop/src-tauri/src/managed_agents/nest.rs
@@ -4,7 +4,8 @@
 //! Sprout-spawned agent starts with orientation (AGENTS.md) and a
 //! place to accumulate research, plans, and logs across sessions.
 //!
-//! Idempotent: existing files and directories are never overwritten.
+//! Static template content in AGENTS.md (above the managed-section markers)
+//! and SKILL.md is refreshed when the embedded template version changes.
 
 use super::{load_managed_agents, load_personas, ManagedAgentRecord, PersonaRecord};
 #[cfg(test)]
@@ -35,6 +36,15 @@ const AGENTS_MD: &str = include_str!("nest_agents.md");
 /// Written to ~/.sprout/.claude/skills/sprout-cli/SKILL.md on first init.
 const SPROUT_CLI_SKILL_MD: &str = include_str!("nest_skill.md");
 
+/// Template content version for AGENTS.md static content (above managed markers).
+/// Bump this when changing `nest_agents.md` to trigger refresh on existing installs.
+/// Version 1 is implicitly "before this mechanism existed" (no version file).
+const NEST_AGENTS_VERSION: u32 = 2;
+
+/// Template content version for SKILL.md.
+/// Bump this when changing `nest_skill.md` to trigger refresh on existing installs.
+const NEST_SKILL_VERSION: u32 = 2;
+
 const BEGIN_MARKER: &str = "<!-- BEGIN SPROUT MANAGED";
 const END_MARKER: &str = "<!-- END SPROUT MANAGED -->";
 /// Returns the nest root path (`~/.sprout`), or `None` if the home
@@ -60,8 +70,10 @@ pub fn ensure_nest() -> Result<(), String> {
 /// - Sets 700 permissions on the root, all subdirectories, and the skill
 ///   directory tree (Unix).
 ///
-/// Idempotent: safe to call on every launch. Existing files are never
-/// overwritten — users can freely edit AGENTS.md or SKILL.md and they persist.
+/// Idempotent: safe to call on every launch. Static template content in
+/// AGENTS.md (above the managed-section markers) and SKILL.md is refreshed
+/// when the embedded template version changes. The managed section in AGENTS.md
+/// and any user content below it are preserved.
 ///
 /// Rejects symlinks at the root path to prevent redirect attacks.
 ///
@@ -134,6 +146,10 @@ pub fn ensure_nest_at(root: &Path) -> Result<(), String> {
         }
     }
 
+    // Refresh static content if the embedded template version is newer.
+    refresh_agents_md_if_stale(root)?;
+    refresh_skill_md_if_stale(root)?;
+
     // Set owner-only permissions on root and all subdirectories.
     // Skip any path that is a symlink — chmod would affect the target.
     #[cfg(unix)]
@@ -233,6 +249,99 @@ pub fn ensure_cli_symlink(_exe_parent: &Path) -> Result<(), String> {
     Ok(())
 }
 
+/// Read a version number from a file. Returns 0 if the file doesn't exist or can't be parsed.
+fn read_version_file(path: &Path) -> u32 {
+    fs::read_to_string(path)
+        .ok()
+        .and_then(|s| s.trim().parse().ok())
+        .unwrap_or(0)
+}
+
+/// Refresh AGENTS.md static content if the template version has changed.
+///
+/// Preserves everything from the `<!-- BEGIN SPROUT MANAGED` marker onward
+/// (the dynamic section managed by `upsert_managed_section`). Replaces
+/// only the static template content above the marker.
+fn refresh_agents_md_if_stale(root: &Path) -> Result<(), String> {
+    let version_path = root.join(".nest-agents-version");
+    if read_version_file(&version_path) >= NEST_AGENTS_VERSION {
+        return Ok(());
+    }
+
+    let agents_md = root.join("AGENTS.md");
+    let current =
+        fs::read_to_string(&agents_md).map_err(|e| format!("read {}: {e}", agents_md.display()))?;
+
+    let new_content = match find_marker_at_line_start(&current, BEGIN_MARKER) {
+        Some(pos) => {
+            // Find the start of the marker line (could be preceded by blank lines).
+            let marker_line_start = current[..pos].rfind('\n').map(|p| p + 1).unwrap_or(0);
+            // Template content up to (but not including) the managed section,
+            // then the existing managed section from the marker onward.
+            let template_static = match AGENTS_MD.find(BEGIN_MARKER) {
+                Some(tmpl_marker_pos) => {
+                    let tmpl_line_start = AGENTS_MD[..tmpl_marker_pos]
+                        .rfind('\n')
+                        .map(|p| p + 1)
+                        .unwrap_or(0);
+                    &AGENTS_MD[..tmpl_line_start]
+                }
+                None => AGENTS_MD,
+            };
+            format!("{}{}", template_static, &current[marker_line_start..])
+        }
+        None => {
+            // No managed section found — write full template.
+            AGENTS_MD.to_string()
+        }
+    };
+
+    // Atomic write via temp file.
+    let parent = agents_md.parent().ok_or("AGENTS.md has no parent dir")?;
+    let mut tmp = tempfile::NamedTempFile::new_in(parent)
+        .map_err(|e| format!("tempfile in {}: {e}", parent.display()))?;
+    {
+        use std::io::Write;
+        tmp.write_all(new_content.as_bytes())
+            .map_err(|e| format!("write tempfile: {e}"))?;
+    }
+    tmp.persist(&agents_md)
+        .map_err(|e| format!("persist {}: {e}", agents_md.display()))?;
+
+    fs::write(&version_path, format!("{NEST_AGENTS_VERSION}\n"))
+        .map_err(|e| format!("write {}: {e}", version_path.display()))?;
+
+    Ok(())
+}
+
+/// Refresh SKILL.md if the template version has changed.
+///
+/// SKILL.md has no user-editable sections — it is fully overwritten on version bump.
+fn refresh_skill_md_if_stale(root: &Path) -> Result<(), String> {
+    let version_path = root.join(".claude/skills/sprout-cli/.skill-version");
+    if read_version_file(&version_path) >= NEST_SKILL_VERSION {
+        return Ok(());
+    }
+
+    let skill_md = root.join(".claude/skills/sprout-cli/SKILL.md");
+    // Atomic write via temp file.
+    let parent = skill_md.parent().ok_or("SKILL.md has no parent dir")?;
+    let mut tmp = tempfile::NamedTempFile::new_in(parent)
+        .map_err(|e| format!("tempfile in {}: {e}", parent.display()))?;
+    {
+        use std::io::Write;
+        tmp.write_all(SPROUT_CLI_SKILL_MD.as_bytes())
+            .map_err(|e| format!("write tempfile: {e}"))?;
+    }
+    tmp.persist(&skill_md)
+        .map_err(|e| format!("persist {}: {e}", skill_md.display()))?;
+
+    fs::write(&version_path, format!("{NEST_SKILL_VERSION}\n"))
+        .map_err(|e| format!("write {}: {e}", version_path.display()))?;
+
+    Ok(())
+}
+
 fn escape_md_cell(s: &str) -> String {
     s.replace('|', "\\|").replace('\n', " ")
 }
@@ -947,4 +1056,99 @@ mod tests {
             "upsert must be idempotent: second call must not alter the file"
         );
     }
+
+    #[test]
+    fn refresh_agents_md_writes_version_file() {
+        let tmp = tempfile::tempdir().unwrap();
+        let root = tmp.path().join(".sprout");
+        ensure_nest_at(&root).unwrap();
+        let version = fs::read_to_string(root.join(".nest-agents-version")).unwrap();
+        assert_eq!(version.trim(), NEST_AGENTS_VERSION.to_string());
+    }
+
+    #[test]
+    fn refresh_skill_md_writes_version_file() {
+        let tmp = tempfile::tempdir().unwrap();
+        let root = tmp.path().join(".sprout");
+        ensure_nest_at(&root).unwrap();
+        let version =
+            fs::read_to_string(root.join(".claude/skills/sprout-cli/.skill-version")).unwrap();
+        assert_eq!(version.trim(), NEST_SKILL_VERSION.to_string());
+    }
+
+    #[test]
+    fn refresh_agents_md_preserves_managed_section() {
+        let tmp = tempfile::tempdir().unwrap();
+        let root = tmp.path().join(".sprout");
+        ensure_nest_at(&root).unwrap();
+
+        // Simulate a managed section update.
+        let agents_md = root.join("AGENTS.md");
+        upsert_managed_section(
+            &agents_md,
+            "## Active Agents\n\n| Name | Role |\n|------|------|\n| Kit | Builder |",
+        )
+        .unwrap();
+
+        // Remove version file to simulate an upgrade.
+        fs::remove_file(root.join(".nest-agents-version")).unwrap();
+
+        // Re-run ensure_nest_at (triggers refresh).
+        ensure_nest_at(&root).unwrap();
+
+        let content = fs::read_to_string(&agents_md).unwrap();
+        // Static content should be refreshed (from template).
+        assert!(
+            content.starts_with("# Sprout Nest"),
+            "template header must be present"
+        );
+        // Managed section should be preserved.
+        assert!(
+            content.contains("Kit"),
+            "managed section agent table must survive refresh"
+        );
+        assert!(content.contains(BEGIN_MARKER), "BEGIN marker must survive");
+        assert!(content.contains(END_MARKER), "END marker must survive");
+    }
+
+    #[test]
+    fn refresh_skips_when_version_current() {
+        let tmp = tempfile::tempdir().unwrap();
+        let root = tmp.path().join(".sprout");
+        ensure_nest_at(&root).unwrap();
+
+        // Manually change AGENTS.md content after version file is written.
+        let agents_md = root.join("AGENTS.md");
+        fs::write(&agents_md, "user modified content").unwrap();
+
+        // Re-run ensure_nest_at — version file is current, so no refresh.
+        ensure_nest_at(&root).unwrap();
+
+        let content = fs::read_to_string(&agents_md).unwrap();
+        assert_eq!(
+            content, "user modified content",
+            "should not overwrite when version is current"
+        );
+    }
+
+    #[test]
+    fn refresh_skill_overwrites_on_version_bump() {
+        let tmp = tempfile::tempdir().unwrap();
+        let root = tmp.path().join(".sprout");
+        ensure_nest_at(&root).unwrap();
+
+        let skill_md = root.join(".claude/skills/sprout-cli/SKILL.md");
+        fs::write(&skill_md, "stale skill content").unwrap();
+
+        // Remove version file to simulate upgrade.
+        let _ = fs::remove_file(root.join(".claude/skills/sprout-cli/.skill-version"));
+
+        ensure_nest_at(&root).unwrap();
+
+        let content = fs::read_to_string(&skill_md).unwrap();
+        assert_eq!(
+            content, SPROUT_CLI_SKILL_MD,
+            "SKILL.md must be refreshed on version bump"
+        );
+    }
 }
diff --git a/desktop/src-tauri/src/managed_agents/nest_agents.md b/desktop/src-tauri/src/managed_agents/nest_agents.md
index 83ee19c3c2..2dc3f4f09f 100644
--- a/desktop/src-tauri/src/managed_agents/nest_agents.md
+++ b/desktop/src-tauri/src/managed_agents/nest_agents.md
@@ -1,6 +1,6 @@
 # Sprout Nest
 
-Your persistent workspace. Created once by the Sprout desktop app — never overwritten. Edit freely.
+Your persistent workspace. Created once by the Sprout desktop app. The static content above the managed-section markers is regenerated on upgrades — add custom notes below the markers or in separate files.
 
 ## Directory Layout
 
@@ -16,32 +16,7 @@ Your persistent workspace. Created once by the Sprout desktop app — never over
 
 Filenames: `ALL_CAPS_WITH_UNDERSCORES.md` (e.g., `OAUTH_FLOW_NOTES.md`).
 
-## Communicating via Sprout
-
-You have MCP tools for channels. Use them.
-
-**Read messages:**
-- `get_messages(channel_id, limit=50)` — recent history (max 200)
-- `get_thread(channel_id, event_id)` — drill into a thread
-- `get_feed()` — personalized: your mentions, needs-action items
-
-**Post messages:**
-- `send_message(channel_id, content)` — new message
-- `send_message(channel_id, content, parent_event_id)` — threaded reply
-
-**Poll for new messages** (no push — poll with sleep):
-- Call `get_messages(channel_id, since=<last_seen_unix_ts>)` where the value is the `created_at` timestamp of the last message you saw
-- When `since` is set without `before`, results are **oldest-first** (chronological)
-- Sleep 10–30 seconds between polls
-
-**Search:**
-- `search(q="your query")` — searches across all channels
-
-## Recovering Context on Startup
-
-1. Call `get_feed()` — surface mentions and items needing your action
-2. Call `get_messages` on your assigned channel(s) to read recent history
-3. Check `RESEARCH/`, `PLANS/`, `GUIDES/` before researching from scratch
+The `sprout` CLI is your primary tool interface — run `sprout --help` for commands. The CLI skill file has the full reference.
 
 ## Knowledge File Conventions
 

From c55e533481e47188af1aad49e6c208b6dc59df6a Mon Sep 17 00:00:00 2001
From: Will Pfleger <wpfleger@block.xyz>
Date: Fri, 22 May 2026 15:45:51 -0400
Subject: [PATCH 13/18] fix: skip AGENTS.md write when managed section content
 is unchanged

upsert_managed_section always wrote via NamedTempFile even when the
new content was identical, bumping mtime on every app launch. Add an
early return when content matches to make the function truly
idempotent at the filesystem level.
---
 desktop/src-tauri/src/managed_agents/nest.rs | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/desktop/src-tauri/src/managed_agents/nest.rs b/desktop/src-tauri/src/managed_agents/nest.rs
index b3255ec5da..a9661140bd 100644
--- a/desktop/src-tauri/src/managed_agents/nest.rs
+++ b/desktop/src-tauri/src/managed_agents/nest.rs
@@ -447,6 +447,11 @@ pub fn upsert_managed_section(file_path: &Path, new_section_content: &str) -> io
         }
     };
 
+    // Skip write when content is unchanged — avoids bumping mtime on every launch.
+    if new_content == current {
+        return Ok(());
+    }
+
     let parent = file_path.parent().ok_or_else(|| {
         io::Error::new(
             io::ErrorKind::InvalidInput,

From 70a28b025f6d9b6ae5945b223a5aa5961feee1b1 Mon Sep 17 00:00:00 2001
From: Will Pfleger <wpfleger@block.xyz>
Date: Fri, 22 May 2026 17:09:26 -0400
Subject: [PATCH 14/18] fix(desktop): gate MCP server by provider discovery +
 harness-agnostic skill path

Agents whose provider declares mcp_command: None (goose, Claude Code,
Codex) were getting sprout-mcp-server injected via the ACP session,
giving them callable MCP tools that override text-based CLI instructions.
Reinterpret None as "no MCP needed" and gate at creation time (empty
string stored) and spawn time (empty env var -> empty vec from
build_mcp_servers). Only sprout-agent retains its sprout-dev-mcp.

Move SKILL.md from .claude/skills/sprout-cli/ to the open-standard
.agents/skills/sprout-cli/ with a relative symlink for Claude Code
compat. Migrate pre-existing real directories, preserving user-edited
content. Remove duplicate @mention guideline from nest AGENTS.md (already
in base_prompt.md). Bump version constants to 3 to trigger refresh.
---
 crates/sprout-acp/src/lib.rs                  |  14 ++
 desktop/scripts/check-file-sizes.mjs          |   2 +-
 desktop/src-tauri/src/commands/agents.rs      |  21 +-
 .../src-tauri/src/managed_agents/discovery.rs |   2 +
 desktop/src-tauri/src/managed_agents/nest.rs  | 185 +++++++++++++++---
 .../src/managed_agents/nest_agents.md         |   1 -
 .../src-tauri/src/managed_agents/runtime.rs   |  20 +-
 7 files changed, 207 insertions(+), 38 deletions(-)

diff --git a/crates/sprout-acp/src/lib.rs b/crates/sprout-acp/src/lib.rs
index 0b26ccd895..01b3496f30 100644
--- a/crates/sprout-acp/src/lib.rs
+++ b/crates/sprout-acp/src/lib.rs
@@ -2611,6 +2611,9 @@ async fn run_models(args: ModelsArgs) -> Result<()> {
 }
 
 fn build_mcp_servers(config: &Config) -> Vec<McpServer> {
+    if config.mcp_command.is_empty() {
+        return vec![];
+    }
     vec![McpServer {
         name: "sprout-mcp".to_string(),
         command: config.mcp_command.clone(),
@@ -2877,4 +2880,15 @@ mod build_mcp_servers_tests {
             "empty SPROUT_AUTH_TAG should not be forwarded"
         );
     }
+
+    #[test]
+    fn empty_mcp_command_returns_no_servers() {
+        let mut config = test_config();
+        config.mcp_command = "".into();
+        let servers = build_mcp_servers(&config);
+        assert!(
+            servers.is_empty(),
+            "empty mcp_command should produce no MCP servers"
+        );
+    }
 }
diff --git a/desktop/scripts/check-file-sizes.mjs b/desktop/scripts/check-file-sizes.mjs
index 27e717064b..d98c658d23 100644
--- a/desktop/scripts/check-file-sizes.mjs
+++ b/desktop/scripts/check-file-sizes.mjs
@@ -30,6 +30,7 @@ const rules = [
 
 // Exceptions should stay rare and temporary. Prefer splitting files instead.
 const overrides = new Map([
+  ["src-tauri/src/managed_agents/nest.rs", 1300], // version-gated AGENTS.md + SKILL.md refresh + .agents/.claude symlink migration + managed section upsert + dynamic agent context + tests
   ["src-tauri/src/managed_agents/personas.rs", 950], // built-in persona system prompts (Solo + Kit + Scout) + merge_personas inequality checks + persona pack import/uninstall/list + uninstall safety check
   ["src-tauri/src/managed_agents/teams.rs", 580], // built-in team registry (Kit & Scout) + merge_teams + validate_team_deletion + JSON export/import + tests
   ["src-tauri/src/managed_agents/persona_card.rs", 970], // PNG/ZIP/MD persona card codec + pack-zip detection + nested root finder + provider/model/namePool fields + 27 unit tests
@@ -52,7 +53,6 @@ const overrides = new Map([
   ["src-tauri/src/managed_agents/runtime.rs", 1110], // ... + respond-to gate env (SPROUT_ACP_RESPOND_TO[_ALLOWLIST]) + per-mode env builder + tests + persona/agent env_vars spawn merge (helper + tests now in env_vars.rs)
   ["src-tauri/src/managed_agents/discovery.rs", 680], // KNOWN_ACP_PROVIDERS catalog + resolve_command cache + login_shell_path + classify_provider (four-state: Available/AdapterMissing/CliMissing/NotInstalled) + discover_acp_providers with dynamic install_hint + known_acp_provider/known_acp_provider_exact + normalize_agent_args + 15 unit tests
   ["src-tauri/src/managed_agents/types.rs", 745], // ManagedAgentRecord/Summary + Create/Update request structs + AcpProviderCatalogEntry + InstallRuntimeResult + RespondTo enum + validate_respond_to_allowlist + tests + persona/agent env_vars field
-  ["src-tauri/src/managed_agents/nest.rs", 1160], // ensure_nest_at (AGENTS.md + SKILL.md + permissions) + ensure_cli_symlink + regenerate_nest_context + render_dynamic_section + upsert_managed_section + marker helpers + version-gated refresh (refresh_agents_md_if_stale + refresh_skill_md_if_stale) + 25 unit tests
   ["src-tauri/src/managed_agents/backend.rs", 700], // provider IPC, validation, discovery, binary resolution + tests + redact_secrets_with for user env values + env_secrets_from_request + redact_env_values_in (shared with model discovery)
   ["src/features/huddle/HuddleContext.tsx", 650], // huddle lifecycle context + joinHuddle + connectAndSetupMedia shared helper + activeSpeakers/isReconnecting state + PTT (reusable AudioContext) + TTS subscription + mic level analyser (10fps throttle) + agent pubkey refresh
   ["src/features/agents/hooks.ts", 550], // agent query/mutation surface + useAvailableAcpProviders (type-narrowing filter hook) + useInstallAcpRuntimeMutation + built-in persona library activation
diff --git a/desktop/src-tauri/src/commands/agents.rs b/desktop/src-tauri/src/commands/agents.rs
index a1d582456e..c666af6632 100644
--- a/desktop/src-tauri/src/commands/agents.rs
+++ b/desktop/src-tauri/src/commands/agents.rs
@@ -335,6 +335,19 @@ pub async fn create_managed_agent(
                 .collect::<Vec<_>>(),
         );
 
+        let mcp_command = input
+            .mcp_command
+            .as_deref()
+            .map(str::trim)
+            .filter(|value| !value.is_empty())
+            .map(str::to_string)
+            .unwrap_or_else(
+                || match crate::managed_agents::known_acp_provider(&agent_command) {
+                    Some(p) => p.mcp_command.unwrap_or("").to_string(),
+                    None => DEFAULT_MCP_COMMAND.to_string(),
+                },
+            );
+
         // For pack-backed personas, resolve the installed pack path and the
         // persona's internal name (slug). ACP's resolve_persona_by_name()
         // matches on this internal name, NOT display_name.
@@ -367,13 +380,7 @@ pub async fn create_managed_agent(
                 .to_string(),
             agent_command,
             agent_args,
-            mcp_command: input
-                .mcp_command
-                .as_deref()
-                .map(str::trim)
-                .filter(|value| !value.is_empty())
-                .unwrap_or(DEFAULT_MCP_COMMAND)
-                .to_string(),
+            mcp_command,
             turn_timeout_seconds: input
                 .turn_timeout_seconds
                 .filter(|seconds| *seconds > 0)
diff --git a/desktop/src-tauri/src/managed_agents/discovery.rs b/desktop/src-tauri/src/managed_agents/discovery.rs
index 683bb1431c..e3957ca369 100644
--- a/desktop/src-tauri/src/managed_agents/discovery.rs
+++ b/desktop/src-tauri/src/managed_agents/discovery.rs
@@ -14,6 +14,8 @@ pub(crate) struct KnownAcpProvider {
     pub aliases: &'static [&'static str],
     pub avatar_url: &'static str,
     /// MCP server binary to use instead of the default `sprout-mcp-server`.
+    /// `None` means this provider does not need a Sprout MCP server —
+    /// no MCP tools will be registered for the agent session.
     pub mcp_command: Option<&'static str>,
     /// Whether to enable MCP hook tools (`_Stop`, `_PostCompact`) for this agent.
     pub mcp_hooks: bool,
diff --git a/desktop/src-tauri/src/managed_agents/nest.rs b/desktop/src-tauri/src/managed_agents/nest.rs
index a9661140bd..eee32d94fd 100644
--- a/desktop/src-tauri/src/managed_agents/nest.rs
+++ b/desktop/src-tauri/src/managed_agents/nest.rs
@@ -33,17 +33,17 @@ const NEST_DIRS: &[&str] = &[
 const AGENTS_MD: &str = include_str!("nest_agents.md");
 
 /// Default SKILL.md content for the sprout-cli Claude Code skill.
-/// Written to ~/.sprout/.claude/skills/sprout-cli/SKILL.md on first init.
+/// Written to ~/.sprout/.agents/skills/sprout-cli/SKILL.md on first init.
 const SPROUT_CLI_SKILL_MD: &str = include_str!("nest_skill.md");
 
 /// Template content version for AGENTS.md static content (above managed markers).
 /// Bump this when changing `nest_agents.md` to trigger refresh on existing installs.
 /// Version 1 is implicitly "before this mechanism existed" (no version file).
-const NEST_AGENTS_VERSION: u32 = 2;
+const NEST_AGENTS_VERSION: u32 = 3;
 
 /// Template content version for SKILL.md.
 /// Bump this when changing `nest_skill.md` to trigger refresh on existing installs.
-const NEST_SKILL_VERSION: u32 = 2;
+const NEST_SKILL_VERSION: u32 = 3;
 
 const BEGIN_MARKER: &str = "<!-- BEGIN SPROUT MANAGED";
 const END_MARKER: &str = "<!-- END SPROUT MANAGED -->";
@@ -66,7 +66,8 @@ pub fn ensure_nest() -> Result<(), String> {
 ///
 /// - Creates the root directory and all subdirectories.
 /// - Writes `AGENTS.md` only if it doesn't already exist.
-/// - Writes `.claude/skills/sprout-cli/SKILL.md` only if it doesn't already exist.
+/// - Writes `.agents/skills/sprout-cli/SKILL.md` only if it doesn't already exist.
+/// - Creates a `.claude/skills/sprout-cli` symlink to the `.agents` location.
 /// - Sets 700 permissions on the root, all subdirectories, and the skill
 ///   directory tree (Unix).
 ///
@@ -125,11 +126,14 @@ pub fn ensure_nest_at(root: &Path) -> Result<(), String> {
         }
     }
 
-    // Write sprout-cli skill alongside AGENTS.md (same idempotent pattern).
-    let skill_dir = root.join(".claude/skills/sprout-cli");
-    fs::create_dir_all(&skill_dir).map_err(|e| format!("create {}: {e}", skill_dir.display()))?;
+    // Write sprout-cli skill to the harness-agnostic .agents path.
+    // The first-init write uses the new canonical path; migration from
+    // the old .claude path is handled in refresh_skill_md_if_stale.
+    let agents_skill_dir = root.join(".agents/skills/sprout-cli");
+    fs::create_dir_all(&agents_skill_dir)
+        .map_err(|e| format!("create {}: {e}", agents_skill_dir.display()))?;
 
-    let skill_md = root.join(".claude/skills/sprout-cli/SKILL.md");
+    let skill_md = agents_skill_dir.join("SKILL.md");
     match fs::OpenOptions::new()
         .write(true)
         .create_new(true)
@@ -146,6 +150,25 @@ pub fn ensure_nest_at(root: &Path) -> Result<(), String> {
         }
     }
 
+    // Create .claude/skills/sprout-cli symlink for Claude Code compatibility.
+    #[cfg(unix)]
+    {
+        let claude_skills_dir = root.join(".claude/skills");
+        fs::create_dir_all(&claude_skills_dir)
+            .map_err(|e| format!("create {}: {e}", claude_skills_dir.display()))?;
+        let symlink_path = root.join(".claude/skills/sprout-cli");
+        // Only create symlink if it doesn't already exist as a symlink.
+        // If it's a real directory (pre-migration), refresh_skill_md_if_stale handles migration.
+        let is_symlink = symlink_path
+            .symlink_metadata()
+            .map(|m| m.file_type().is_symlink())
+            .unwrap_or(false);
+        if !is_symlink && !symlink_path.exists() {
+            std::os::unix::fs::symlink("../../.agents/skills/sprout-cli", &symlink_path)
+                .map_err(|e| format!("symlink {}: {e}", symlink_path.display()))?;
+        }
+    }
+
     // Refresh static content if the embedded template version is newer.
     refresh_agents_md_if_stale(root)?;
     refresh_skill_md_if_stale(root)?;
@@ -169,13 +192,15 @@ pub fn ensure_nest_at(root: &Path) -> Result<(), String> {
                     .map_err(|e| format!("set permissions on {}: {e}", path.display()))?;
             }
         }
-        // Skill directory and its intermediate parents inside root get 700.
-        // create_dir_all creates .claude/ and .claude/skills/ with umask
-        // defaults — lock them down the same way we do NEST_DIRS.
+        // .agents skill dir tree and .claude parents inside root get 700.
+        // create_dir_all creates them with umask defaults — lock them down
+        // the same way we do NEST_DIRS. Skip symlinks (chmod affects target).
         for dir in [
+            root.join(".agents"),
+            root.join(".agents/skills"),
+            agents_skill_dir.clone(),
             root.join(".claude"),
             root.join(".claude/skills"),
-            skill_dir.clone(),
         ] {
             let is_symlink = dir
                 .symlink_metadata()
@@ -318,24 +343,71 @@ fn refresh_agents_md_if_stale(root: &Path) -> Result<(), String> {
 ///
 /// SKILL.md has no user-editable sections — it is fully overwritten on version bump.
 fn refresh_skill_md_if_stale(root: &Path) -> Result<(), String> {
-    let version_path = root.join(".claude/skills/sprout-cli/.skill-version");
+    let agents_skill_dir = root.join(".agents/skills/sprout-cli");
+    let version_path = agents_skill_dir.join(".skill-version");
     if read_version_file(&version_path) >= NEST_SKILL_VERSION {
         return Ok(());
     }
 
-    let skill_md = root.join(".claude/skills/sprout-cli/SKILL.md");
+    // Migration: if .claude/skills/sprout-cli exists as a real directory
+    // (pre-migration install), copy user's SKILL.md to the new location
+    // then remove the old directory so we can replace it with a symlink.
+    let old_skill_dir = root.join(".claude/skills/sprout-cli");
+    let old_is_real_dir = old_skill_dir
+        .symlink_metadata()
+        .map(|m| m.file_type().is_dir())
+        .unwrap_or(false);
+
+    let skill_content = if old_is_real_dir {
+        // Preserve user-edited content during migration.
+        fs::read_to_string(old_skill_dir.join("SKILL.md"))
+            .unwrap_or_else(|_| SPROUT_CLI_SKILL_MD.to_string())
+    } else {
+        SPROUT_CLI_SKILL_MD.to_string()
+    };
+
+    // Ensure the canonical .agents skill directory exists.
+    fs::create_dir_all(&agents_skill_dir)
+        .map_err(|e| format!("create {}: {e}", agents_skill_dir.display()))?;
+
     // Atomic write via temp file.
-    let parent = skill_md.parent().ok_or("SKILL.md has no parent dir")?;
-    let mut tmp = tempfile::NamedTempFile::new_in(parent)
-        .map_err(|e| format!("tempfile in {}: {e}", parent.display()))?;
+    let skill_md = agents_skill_dir.join("SKILL.md");
+    let mut tmp = tempfile::NamedTempFile::new_in(&agents_skill_dir)
+        .map_err(|e| format!("tempfile in {}: {e}", agents_skill_dir.display()))?;
     {
         use std::io::Write;
-        tmp.write_all(SPROUT_CLI_SKILL_MD.as_bytes())
+        tmp.write_all(skill_content.as_bytes())
             .map_err(|e| format!("write tempfile: {e}"))?;
     }
     tmp.persist(&skill_md)
         .map_err(|e| format!("persist {}: {e}", skill_md.display()))?;
 
+    // Replace old real directory with a symlink.
+    if old_is_real_dir {
+        fs::remove_dir_all(&old_skill_dir)
+            .map_err(|e| format!("remove {}: {e}", old_skill_dir.display()))?;
+    }
+
+    // Create/replace the .claude/skills/sprout-cli symlink.
+    #[cfg(unix)]
+    {
+        let claude_skills_dir = root.join(".claude/skills");
+        fs::create_dir_all(&claude_skills_dir)
+            .map_err(|e| format!("create {}: {e}", claude_skills_dir.display()))?;
+        let symlink_path = root.join(".claude/skills/sprout-cli");
+        // Remove any stale symlink before (re)creating.
+        let symlink_exists = symlink_path
+            .symlink_metadata()
+            .map(|m| m.file_type().is_symlink())
+            .unwrap_or(false);
+        if symlink_exists {
+            fs::remove_file(&symlink_path)
+                .map_err(|e| format!("remove symlink {}: {e}", symlink_path.display()))?;
+        }
+        std::os::unix::fs::symlink("../../.agents/skills/sprout-cli", &symlink_path)
+            .map_err(|e| format!("symlink {}: {e}", symlink_path.display()))?;
+    }
+
     fs::write(&version_path, format!("{NEST_SKILL_VERSION}\n"))
         .map_err(|e| format!("write {}: {e}", version_path.display()))?;
 
@@ -582,10 +654,22 @@ mod tests {
         let tmp = tempfile::tempdir().unwrap();
         let root = tmp.path().join(".sprout");
         ensure_nest_at(&root).unwrap();
-        let skill = root.join(".claude/skills/sprout-cli/SKILL.md");
-        assert!(skill.exists(), "SKILL.md should exist");
+
+        // Canonical location under .agents.
+        let skill = root.join(".agents/skills/sprout-cli/SKILL.md");
+        assert!(skill.exists(), "SKILL.md should exist at .agents path");
         let content = fs::read_to_string(&skill).unwrap();
         assert_eq!(content, SPROUT_CLI_SKILL_MD);
+
+        // .claude/skills/sprout-cli is a symlink on Unix.
+        #[cfg(unix)]
+        {
+            let symlink = root.join(".claude/skills/sprout-cli");
+            assert!(
+                symlink.symlink_metadata().unwrap().file_type().is_symlink(),
+                ".claude/skills/sprout-cli should be a symlink"
+            );
+        }
     }
 
     #[test]
@@ -593,8 +677,10 @@ mod tests {
         let tmp = tempfile::tempdir().unwrap();
         let root = tmp.path().join(".sprout");
         ensure_nest_at(&root).unwrap();
-        let skill = root.join(".claude/skills/sprout-cli/SKILL.md");
+
+        let skill = root.join(".agents/skills/sprout-cli/SKILL.md");
         fs::write(&skill, "custom skill content").unwrap();
+
         ensure_nest_at(&root).unwrap();
         assert_eq!(fs::read_to_string(&skill).unwrap(), "custom skill content");
     }
@@ -606,8 +692,15 @@ mod tests {
         let tmp = tempfile::tempdir().unwrap();
         let root = tmp.path().join(".sprout");
         ensure_nest_at(&root).unwrap();
-        // All three dirs in the skill path should be locked down.
-        for dir in [".claude", ".claude/skills", ".claude/skills/sprout-cli"] {
+        // Real dirs in .agents tree and .claude parents should be 700.
+        // .claude/skills/sprout-cli is a symlink — excluded from chmod check.
+        for dir in [
+            ".agents",
+            ".agents/skills",
+            ".agents/skills/sprout-cli",
+            ".claude",
+            ".claude/skills",
+        ] {
             let path = root.join(dir);
             let mode = fs::metadata(&path).unwrap().permissions().mode() & 0o777;
             assert_eq!(mode, 0o700, "{dir} should be 700");
@@ -643,6 +736,46 @@ mod tests {
         );
     }
 
+    #[cfg(unix)]
+    #[test]
+    fn ensure_nest_migrates_old_skill_dir() {
+        let tmp = tempfile::tempdir().unwrap();
+        let root = tmp.path().join(".sprout");
+
+        // Simulate a pre-migration install: real directory at old path.
+        // Create the nest first to get all dirs, then simulate old layout.
+        ensure_nest_at(&root).unwrap();
+
+        // Remove the symlink and new skill dir, recreate old real dir.
+        let _ = fs::remove_file(root.join(".claude/skills/sprout-cli"));
+        let _ = fs::remove_dir_all(root.join(".agents/skills/sprout-cli"));
+        let old_skill_dir = root.join(".claude/skills/sprout-cli");
+        fs::create_dir_all(&old_skill_dir).unwrap();
+        fs::write(old_skill_dir.join("SKILL.md"), "user edited skill").unwrap();
+
+        // Delete version file to force refresh.
+        let _ = fs::remove_file(root.join(".agents/skills/sprout-cli/.skill-version"));
+
+        // Re-run ensure_nest_at — should trigger migration in refresh_skill_md_if_stale.
+        ensure_nest_at(&root).unwrap();
+
+        // New canonical location exists with user's content preserved.
+        let new_skill = root.join(".agents/skills/sprout-cli/SKILL.md");
+        assert!(new_skill.exists(), "SKILL.md should exist at new path");
+        assert_eq!(fs::read_to_string(&new_skill).unwrap(), "user edited skill");
+
+        // Old path is now a symlink, not a real directory.
+        let old_path = root.join(".claude/skills/sprout-cli");
+        assert!(
+            old_path
+                .symlink_metadata()
+                .unwrap()
+                .file_type()
+                .is_symlink(),
+            "old path should now be a symlink"
+        );
+    }
+
     #[cfg(unix)]
     #[test]
     fn ensure_cli_symlink_creates_symlink() {
@@ -1077,7 +1210,7 @@ mod tests {
         let root = tmp.path().join(".sprout");
         ensure_nest_at(&root).unwrap();
         let version =
-            fs::read_to_string(root.join(".claude/skills/sprout-cli/.skill-version")).unwrap();
+            fs::read_to_string(root.join(".agents/skills/sprout-cli/.skill-version")).unwrap();
         assert_eq!(version.trim(), NEST_SKILL_VERSION.to_string());
     }
 
@@ -1142,11 +1275,11 @@ mod tests {
         let root = tmp.path().join(".sprout");
         ensure_nest_at(&root).unwrap();
 
-        let skill_md = root.join(".claude/skills/sprout-cli/SKILL.md");
+        let skill_md = root.join(".agents/skills/sprout-cli/SKILL.md");
         fs::write(&skill_md, "stale skill content").unwrap();
 
         // Remove version file to simulate upgrade.
-        let _ = fs::remove_file(root.join(".claude/skills/sprout-cli/.skill-version"));
+        let _ = fs::remove_file(root.join(".agents/skills/sprout-cli/.skill-version"));
 
         ensure_nest_at(&root).unwrap();
 
diff --git a/desktop/src-tauri/src/managed_agents/nest_agents.md b/desktop/src-tauri/src/managed_agents/nest_agents.md
index 2dc3f4f09f..0a8f1ef026 100644
--- a/desktop/src-tauri/src/managed_agents/nest_agents.md
+++ b/desktop/src-tauri/src/managed_agents/nest_agents.md
@@ -44,7 +44,6 @@ created: 2026-01-15
 - **`.scratch/` is disposable** — don't rely on it across sessions
 - **Never push without approval** — do not `git push` to any remote
 - **Stay on task** — only stage files relevant to your current work
-- **Tagging or @mentioning others** — you can mention other bots or users by simply @'ing them in your message, but you cannot bold, italicize, or otherwise format the mention text if you want them to actually be alerted
 
 <!-- BEGIN SPROUT MANAGED — regenerated automatically, do not edit below -->
 ## Active Agents
diff --git a/desktop/src-tauri/src/managed_agents/runtime.rs b/desktop/src-tauri/src/managed_agents/runtime.rs
index 770618fdb4..2cf2951540 100644
--- a/desktop/src-tauri/src/managed_agents/runtime.rs
+++ b/desktop/src-tauri/src/managed_agents/runtime.rs
@@ -529,8 +529,15 @@ pub fn spawn_agent_child(
     let agent_args = normalize_agent_args(&record.agent_command, record.agent_args.clone());
     let resolved_acp_command = resolve_command(&record.acp_command, Some(app))
         .ok_or_else(|| missing_command_message(&record.acp_command, "ACP harness command"))?;
-    let resolved_mcp_command = resolve_command(&record.mcp_command, Some(app))
-        .ok_or_else(|| missing_command_message(&record.mcp_command, "MCP server command"))?;
+    let resolved_mcp_command: Option<std::path::PathBuf> = if record.mcp_command.is_empty() {
+        None
+    } else {
+        Some(
+            resolve_command(&record.mcp_command, Some(app)).ok_or_else(|| {
+                missing_command_message(&record.mcp_command, "MCP server command")
+            })?,
+        )
+    };
     // Resolve agent command to a full path (DMG launches have minimal PATH).
     let resolved_agent_command = resolve_command(&record.agent_command, Some(app))
         .map(|p| p.display().to_string())
@@ -575,7 +582,14 @@ pub fn spawn_agent_child(
     command.env("SPROUT_RELAY_URL", &record.relay_url);
     command.env("SPROUT_ACP_AGENT_COMMAND", &resolved_agent_command);
     command.env("SPROUT_ACP_AGENT_ARGS", agent_args.join(","));
-    command.env("SPROUT_ACP_MCP_COMMAND", &resolved_mcp_command);
+    match &resolved_mcp_command {
+        Some(mcp_cmd) => {
+            command.env("SPROUT_ACP_MCP_COMMAND", mcp_cmd);
+        }
+        None => {
+            command.env("SPROUT_ACP_MCP_COMMAND", "");
+        }
+    }
     // Enable MCP hook tools (_Stop, _PostCompact) for agents that need them.
     // Uses "*" because build_mcp_servers() hard-codes the server name to "sprout-mcp".
     if known_acp_provider(&record.agent_command).is_some_and(|p| p.mcp_hooks) {

From 6c71ac75d49b2d756ee55b092b26c28c3853602a Mon Sep 17 00:00:00 2001
From: Will Pfleger <wpfleger@block.xyz>
Date: Fri, 22 May 2026 20:52:26 -0400
Subject: [PATCH 15/18] refactor(desktop): generalize skill symlinks via
 KnownAcpProvider

Only Claude Code got a symlink for skill discovery; Goose, Codex, and
future harnesses were ignored. Add a skill_dir field to
KnownAcpProvider so each harness declares its own skill path, then
loop over all providers to create relative symlinks from each
harness dir to the canonical .agents/skills/sprout-cli.

Moves the real SKILL.md to .agents/skills/sprout-cli (agent-neutral
canonical path) with symlinks at .goose/skills/, .claude/skills/,
and .codex/skills/.



# Conflicts:
#	desktop/src-tauri/src/managed_agents/discovery.rs
---
 .../src-tauri/src/managed_agents/discovery.rs |  14 ++
 desktop/src-tauri/src/managed_agents/nest.rs  | 189 ++++++++++++++----
 2 files changed, 165 insertions(+), 38 deletions(-)

diff --git a/desktop/src-tauri/src/managed_agents/discovery.rs b/desktop/src-tauri/src/managed_agents/discovery.rs
index e3957ca369..0fc8a42f94 100644
--- a/desktop/src-tauri/src/managed_agents/discovery.rs
+++ b/desktop/src-tauri/src/managed_agents/discovery.rs
@@ -31,6 +31,11 @@ pub(crate) struct KnownAcpProvider {
     pub cli_install_hint: &'static str,
     /// Human-readable hint about installing the ACP adapter.
     pub adapter_install_hint: &'static str,
+    /// Harness-specific skill discovery directory (e.g. `.goose/skills`).
+    /// `Some(dir)` → Sprout creates a symlink at `<nest>/<dir>/sprout-cli`
+    /// pointing to the canonical `.agents/skills/sprout-cli`. `None` → this
+    /// provider reads the canonical path directly or has no skill support.
+    pub skill_dir: Option<&'static str>,
 }
 
 const GOOSE_AVATAR_URL: &str = "https://goose-docs.ai/img/logo_dark.png";
@@ -76,6 +81,7 @@ const KNOWN_ACP_PROVIDERS: &[KnownAcpProvider] = &[
         install_instructions_url: "https://block.github.io/goose/",
         cli_install_hint: "Install Goose via the official install script.",
         adapter_install_hint: "",
+        skill_dir: Some(".goose/skills"),
     },
     KnownAcpProvider {
         id: "claude",
@@ -91,6 +97,7 @@ const KNOWN_ACP_PROVIDERS: &[KnownAcpProvider] = &[
         install_instructions_url: "https://github.com/agentclientprotocol/claude-agent-acp",
         cli_install_hint: "Install the Claude Code CLI via the official install script.",
         adapter_install_hint: "Install the Claude Code ACP adapter via npm.",
+        skill_dir: Some(".claude/skills"),
     },
     KnownAcpProvider {
         id: "codex",
@@ -106,6 +113,7 @@ const KNOWN_ACP_PROVIDERS: &[KnownAcpProvider] = &[
         install_instructions_url: "https://github.com/zed-industries/codex-acp",
         cli_install_hint: "Install the Codex CLI via the official install script.",
         adapter_install_hint: "Install the Codex ACP adapter via npm.",
+        skill_dir: Some(".codex/skills"),
     },
     KnownAcpProvider {
         id: "sprout-agent",
@@ -121,9 +129,15 @@ const KNOWN_ACP_PROVIDERS: &[KnownAcpProvider] = &[
         install_instructions_url: "https://github.com/block/sprout",
         cli_install_hint: "Ships with the Sprout desktop app.",
         adapter_install_hint: "",
+        skill_dir: None,
     },
 ];
 
+/// Skill discovery directories declared by known providers.
+pub(crate) fn known_skill_dirs() -> impl Iterator<Item = &'static str> {
+    KNOWN_ACP_PROVIDERS.iter().filter_map(|p| p.skill_dir)
+}
+
 fn workspace_root_dir() -> PathBuf {
     PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..")
 }
diff --git a/desktop/src-tauri/src/managed_agents/nest.rs b/desktop/src-tauri/src/managed_agents/nest.rs
index eee32d94fd..00c5dc3558 100644
--- a/desktop/src-tauri/src/managed_agents/nest.rs
+++ b/desktop/src-tauri/src/managed_agents/nest.rs
@@ -17,6 +17,8 @@ use std::io;
 use std::path::{Path, PathBuf};
 use tauri::{AppHandle, Manager};
 
+use crate::managed_agents::discovery::known_skill_dirs;
+
 /// Subdirectories created inside the nest.
 const NEST_DIRS: &[&str] = &[
     "GUIDES",
@@ -47,6 +49,9 @@ const NEST_SKILL_VERSION: u32 = 3;
 
 const BEGIN_MARKER: &str = "<!-- BEGIN SPROUT MANAGED";
 const END_MARKER: &str = "<!-- END SPROUT MANAGED -->";
+
+/// Canonical skill directory path relative to the nest root.
+const CANONICAL_SKILL_DIR: &str = ".agents/skills/sprout-cli";
 /// Returns the nest root path (`~/.sprout`), or `None` if the home
 /// directory cannot be resolved.
 pub fn nest_dir() -> Option<PathBuf> {
@@ -67,7 +72,8 @@ pub fn ensure_nest() -> Result<(), String> {
 /// - Creates the root directory and all subdirectories.
 /// - Writes `AGENTS.md` only if it doesn't already exist.
 /// - Writes `.agents/skills/sprout-cli/SKILL.md` only if it doesn't already exist.
-/// - Creates a `.claude/skills/sprout-cli` symlink to the `.agents` location.
+/// - Creates harness-specific symlinks (e.g. `.claude/skills/sprout-cli`) pointing
+///   to the canonical `.agents/skills/sprout-cli` directory.
 /// - Sets 700 permissions on the root, all subdirectories, and the skill
 ///   directory tree (Unix).
 ///
@@ -129,7 +135,7 @@ pub fn ensure_nest_at(root: &Path) -> Result<(), String> {
     // Write sprout-cli skill to the harness-agnostic .agents path.
     // The first-init write uses the new canonical path; migration from
     // the old .claude path is handled in refresh_skill_md_if_stale.
-    let agents_skill_dir = root.join(".agents/skills/sprout-cli");
+    let agents_skill_dir = root.join(CANONICAL_SKILL_DIR);
     fs::create_dir_all(&agents_skill_dir)
         .map_err(|e| format!("create {}: {e}", agents_skill_dir.display()))?;
 
@@ -150,29 +156,16 @@ pub fn ensure_nest_at(root: &Path) -> Result<(), String> {
         }
     }
 
-    // Create .claude/skills/sprout-cli symlink for Claude Code compatibility.
-    #[cfg(unix)]
-    {
-        let claude_skills_dir = root.join(".claude/skills");
-        fs::create_dir_all(&claude_skills_dir)
-            .map_err(|e| format!("create {}: {e}", claude_skills_dir.display()))?;
-        let symlink_path = root.join(".claude/skills/sprout-cli");
-        // Only create symlink if it doesn't already exist as a symlink.
-        // If it's a real directory (pre-migration), refresh_skill_md_if_stale handles migration.
-        let is_symlink = symlink_path
-            .symlink_metadata()
-            .map(|m| m.file_type().is_symlink())
-            .unwrap_or(false);
-        if !is_symlink && !symlink_path.exists() {
-            std::os::unix::fs::symlink("../../.agents/skills/sprout-cli", &symlink_path)
-                .map_err(|e| format!("symlink {}: {e}", symlink_path.display()))?;
-        }
-    }
+    // Create harness-specific symlinks for all known providers.
+    // Migration of the old .claude/skills/sprout-cli real dir is handled in
+    // refresh_skill_md_if_stale; ensure_skill_symlinks skips paths that already exist.
+    ensure_skill_symlinks(root)?;
 
     // Refresh static content if the embedded template version is newer.
     refresh_agents_md_if_stale(root)?;
     refresh_skill_md_if_stale(root)?;
 
+
     // Set owner-only permissions on root and all subdirectories.
     // Skip any path that is a symlink — chmod would affect the target.
     #[cfg(unix)]
@@ -192,16 +185,25 @@ pub fn ensure_nest_at(root: &Path) -> Result<(), String> {
                     .map_err(|e| format!("set permissions on {}: {e}", path.display()))?;
             }
         }
-        // .agents skill dir tree and .claude parents inside root get 700.
-        // create_dir_all creates them with umask defaults — lock them down
-        // the same way we do NEST_DIRS. Skip symlinks (chmod affects target).
-        for dir in [
-            root.join(".agents"),
-            root.join(".agents/skills"),
-            agents_skill_dir.clone(),
-            root.join(".claude"),
-            root.join(".claude/skills"),
-        ] {
+        // Skill directory trees inside root get 700.
+        // Build the list from canonical path + all known provider skill dirs.
+        let mut skill_perm_dirs = Vec::new();
+        {
+            let mut accumulated = std::path::PathBuf::new();
+            for component in std::path::Path::new(CANONICAL_SKILL_DIR).components() {
+                accumulated.push(component);
+                skill_perm_dirs.push(root.join(&accumulated));
+            }
+        }
+        for skill_dir in known_skill_dirs() {
+            // Ensure every ancestor dir gets 700, not just the leaf.
+            let mut accumulated = std::path::PathBuf::new();
+            for component in std::path::Path::new(skill_dir).components() {
+                accumulated.push(component);
+                skill_perm_dirs.push(root.join(&accumulated));
+            }
+        }
+        for dir in skill_perm_dirs {
             let is_symlink = dir
                 .symlink_metadata()
                 .map(|m| m.file_type().is_symlink())
@@ -216,6 +218,32 @@ pub fn ensure_nest_at(root: &Path) -> Result<(), String> {
     Ok(())
 }
 
+/// Create harness-specific skill symlinks for each known provider.
+/// Idempotent: skips any path where `symlink_metadata` succeeds — real
+/// directories, valid symlinks, and dangling symlinks are all left alone.
+#[cfg(unix)]
+fn ensure_skill_symlinks(root: &Path) -> Result<(), String> {
+    for skill_dir in known_skill_dirs() {
+        let parent = root.join(skill_dir);
+        fs::create_dir_all(&parent).map_err(|e| format!("create {}: {e}", parent.display()))?;
+        let link = parent.join("sprout-cli");
+        if link.symlink_metadata().is_ok() {
+            continue; // symlink or real path exists — skip
+        }
+        let depth = std::path::Path::new(skill_dir).components().count();
+        let prefix = "../".repeat(depth);
+        let target = format!("{prefix}{CANONICAL_SKILL_DIR}");
+        std::os::unix::fs::symlink(&target, &link)
+            .map_err(|e| format!("symlink {} → {}: {e}", link.display(), target))?;
+    }
+    Ok(())
+}
+
+#[cfg(not(unix))]
+fn ensure_skill_symlinks(_root: &Path) -> Result<(), String> {
+    Ok(())
+}
+
 /// Ensures `~/.local/bin/sprout` is a symlink to the bundled CLI binary.
 ///
 /// Creates the symlink if it doesn't exist, updates it if it already points
@@ -661,14 +689,20 @@ mod tests {
         let content = fs::read_to_string(&skill).unwrap();
         assert_eq!(content, SPROUT_CLI_SKILL_MD);
 
-        // .claude/skills/sprout-cli is a symlink on Unix.
+        // On unix, harness-specific symlinks should resolve to the canonical dir.
         #[cfg(unix)]
         {
-            let symlink = root.join(".claude/skills/sprout-cli");
-            assert!(
-                symlink.symlink_metadata().unwrap().file_type().is_symlink(),
-                ".claude/skills/sprout-cli should be a symlink"
-            );
+            for dir in [".goose/skills", ".claude/skills", ".codex/skills"] {
+                let link = root.join(dir).join("sprout-cli");
+                assert!(
+                    link.symlink_metadata().unwrap().file_type().is_symlink(),
+                    "{dir}/sprout-cli should be a symlink"
+                );
+                assert!(
+                    link.join("SKILL.md").exists(),
+                    "symlink at {dir}/sprout-cli should resolve to dir with SKILL.md"
+                );
+            }
         }
     }
 
@@ -692,14 +726,18 @@ mod tests {
         let tmp = tempfile::tempdir().unwrap();
         let root = tmp.path().join(".sprout");
         ensure_nest_at(&root).unwrap();
-        // Real dirs in .agents tree and .claude parents should be 700.
-        // .claude/skills/sprout-cli is a symlink — excluded from chmod check.
+        // Canonical path and all provider parent dirs should be locked down.
+        // Symlinks (e.g. .goose/skills/sprout-cli) are skipped by the chmod loop.
         for dir in [
             ".agents",
             ".agents/skills",
             ".agents/skills/sprout-cli",
+            ".goose",
+            ".goose/skills",
             ".claude",
             ".claude/skills",
+            ".codex",
+            ".codex/skills",
         ] {
             let path = root.join(dir);
             let mode = fs::metadata(&path).unwrap().permissions().mode() & 0o777;
@@ -776,6 +814,81 @@ mod tests {
         );
     }
 
+    #[cfg(unix)]
+    #[test]
+    fn ensure_skill_symlinks_are_idempotent() {
+        let tmp = tempfile::tempdir().unwrap();
+        let root = tmp.path().join(".sprout");
+        ensure_nest_at(&root).unwrap();
+        // Second call should succeed without errors.
+        ensure_nest_at(&root).unwrap();
+        // All symlinks still valid and point to relative targets.
+        for dir in [".goose/skills", ".claude/skills", ".codex/skills"] {
+            let link = root.join(dir).join("sprout-cli");
+            assert!(link.symlink_metadata().unwrap().file_type().is_symlink());
+            assert!(
+                link.join("SKILL.md").exists(),
+                "symlink at {dir}/sprout-cli should resolve to dir with SKILL.md"
+            );
+            let target = fs::read_link(&link).unwrap();
+            assert_eq!(
+                target.to_str().unwrap(),
+                format!("../../{CANONICAL_SKILL_DIR}"),
+                "symlink at {dir}/sprout-cli should use relative target"
+            );
+        }
+    }
+
+    #[cfg(unix)]
+    #[test]
+    fn ensure_skill_symlinks_skip_real_directory() {
+        let tmp = tempfile::tempdir().unwrap();
+        let root = tmp.path().join(".sprout");
+        // Pre-create a real directory where a symlink would go.
+        let real_dir = root.join(".claude/skills/sprout-cli");
+        fs::create_dir_all(&real_dir).unwrap();
+        fs::write(real_dir.join("custom.md"), "user content").unwrap();
+
+        ensure_nest_at(&root).unwrap();
+
+        // Real directory should be preserved, not replaced with a symlink.
+        assert!(real_dir.is_dir());
+        assert!(!real_dir
+            .symlink_metadata()
+            .unwrap()
+            .file_type()
+            .is_symlink());
+        assert_eq!(
+            fs::read_to_string(real_dir.join("custom.md")).unwrap(),
+            "user content"
+        );
+    }
+
+    #[cfg(unix)]
+    #[test]
+    fn ensure_skill_symlinks_skip_dangling_symlink() {
+        let tmp = tempfile::tempdir().unwrap();
+        let root = tmp.path().join(".sprout");
+        // Pre-create a dangling symlink where the .codex link would go.
+        let codex_skills = root.join(".codex/skills");
+        fs::create_dir_all(&codex_skills).unwrap();
+        let dangling = codex_skills.join("sprout-cli");
+        std::os::unix::fs::symlink("/nonexistent/target", &dangling).unwrap();
+
+        ensure_nest_at(&root).unwrap();
+
+        // Dangling symlink should be left alone (not clobbered).
+        assert!(dangling
+            .symlink_metadata()
+            .unwrap()
+            .file_type()
+            .is_symlink());
+        assert_eq!(
+            fs::read_link(&dangling).unwrap().to_str().unwrap(),
+            "/nonexistent/target"
+        );
+    }
+
     #[cfg(unix)]
     #[test]
     fn ensure_cli_symlink_creates_symlink() {

From a4b3342d81fc39bc4c2d94384a61a407fed86e9a Mon Sep 17 00:00:00 2001
From: Will Pfleger <wpfleger@block.xyz>
Date: Fri, 22 May 2026 19:44:46 -0400
Subject: [PATCH 16/18] style(desktop): remove stale Claude Code references
 from nest comments

Doc comment on SPROUT_CLI_SKILL_MD still said "Claude Code skill" and
the ensure_nest_at docstring used .claude/skills as an inline example
rather than describing the generic provider pattern.
---
 desktop/src-tauri/src/managed_agents/nest.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/desktop/src-tauri/src/managed_agents/nest.rs b/desktop/src-tauri/src/managed_agents/nest.rs
index 00c5dc3558..b88d12ee7a 100644
--- a/desktop/src-tauri/src/managed_agents/nest.rs
+++ b/desktop/src-tauri/src/managed_agents/nest.rs
@@ -34,7 +34,7 @@ const NEST_DIRS: &[&str] = &[
 /// Fully static — no runtime interpolation, no secrets, no user paths.
 const AGENTS_MD: &str = include_str!("nest_agents.md");
 
-/// Default SKILL.md content for the sprout-cli Claude Code skill.
+/// Default SKILL.md content for the sprout-cli skill.
 /// Written to ~/.sprout/.agents/skills/sprout-cli/SKILL.md on first init.
 const SPROUT_CLI_SKILL_MD: &str = include_str!("nest_skill.md");
 
@@ -72,8 +72,8 @@ pub fn ensure_nest() -> Result<(), String> {
 /// - Creates the root directory and all subdirectories.
 /// - Writes `AGENTS.md` only if it doesn't already exist.
 /// - Writes `.agents/skills/sprout-cli/SKILL.md` only if it doesn't already exist.
-/// - Creates harness-specific symlinks (e.g. `.claude/skills/sprout-cli`) pointing
-///   to the canonical `.agents/skills/sprout-cli` directory.
+/// - Creates harness-specific symlinks pointing to the canonical
+///   `.agents/skills/sprout-cli` directory for each known provider.
 /// - Sets 700 permissions on the root, all subdirectories, and the skill
 ///   directory tree (Unix).
 ///

From d648d32ead2fe63b5ac4b44c955f14249e10a2c2 Mon Sep 17 00:00:00 2001
From: Will Pfleger <wpfleger@block.xyz>
Date: Fri, 22 May 2026 20:37:46 -0400
Subject: [PATCH 17/18] fixup: adjust test + size override for merged migration
 behavior

ensure_skill_symlinks_skip_real_directory assumed no migration path;
refresh_skill_md_if_stale converts real dirs at .claude/skills/sprout-cli
to symlinks, so the test was updated to match the actual merged behavior.
Bump nest.rs file-size override to accommodate new provider symlink tests.
---
 desktop/scripts/check-file-sizes.mjs         |  2 +-
 desktop/src-tauri/src/managed_agents/nest.rs | 32 +++++++++++++-------
 2 files changed, 22 insertions(+), 12 deletions(-)

diff --git a/desktop/scripts/check-file-sizes.mjs b/desktop/scripts/check-file-sizes.mjs
index d98c658d23..35fd60fa45 100644
--- a/desktop/scripts/check-file-sizes.mjs
+++ b/desktop/scripts/check-file-sizes.mjs
@@ -30,7 +30,7 @@ const rules = [
 
 // Exceptions should stay rare and temporary. Prefer splitting files instead.
 const overrides = new Map([
-  ["src-tauri/src/managed_agents/nest.rs", 1300], // version-gated AGENTS.md + SKILL.md refresh + .agents/.claude symlink migration + managed section upsert + dynamic agent context + tests
+  ["src-tauri/src/managed_agents/nest.rs", 1420], // version-gated AGENTS.md + SKILL.md refresh + .agents/.claude symlink migration + ensure_skill_symlinks (all known providers) + managed section upsert + dynamic agent context + tests
   ["src-tauri/src/managed_agents/personas.rs", 950], // built-in persona system prompts (Solo + Kit + Scout) + merge_personas inequality checks + persona pack import/uninstall/list + uninstall safety check
   ["src-tauri/src/managed_agents/teams.rs", 580], // built-in team registry (Kit & Scout) + merge_teams + validate_team_deletion + JSON export/import + tests
   ["src-tauri/src/managed_agents/persona_card.rs", 970], // PNG/ZIP/MD persona card codec + pack-zip detection + nested root finder + provider/model/namePool fields + 27 unit tests
diff --git a/desktop/src-tauri/src/managed_agents/nest.rs b/desktop/src-tauri/src/managed_agents/nest.rs
index b88d12ee7a..563ac462d7 100644
--- a/desktop/src-tauri/src/managed_agents/nest.rs
+++ b/desktop/src-tauri/src/managed_agents/nest.rs
@@ -841,26 +841,36 @@ mod tests {
 
     #[cfg(unix)]
     #[test]
-    fn ensure_skill_symlinks_skip_real_directory() {
+    fn ensure_skill_symlinks_skips_existing_path_during_initial_pass() {
+        // ensure_skill_symlinks skips any path where symlink_metadata succeeds.
+        // However, refresh_skill_md_if_stale (called after ensure_skill_symlinks)
+        // migrates pre-existing real directories at .claude/skills/sprout-cli to
+        // symlinks. This test verifies the end-to-end behavior: a pre-existing real
+        // dir at the claude path is migrated to a symlink.
         let tmp = tempfile::tempdir().unwrap();
         let root = tmp.path().join(".sprout");
         // Pre-create a real directory where a symlink would go.
         let real_dir = root.join(".claude/skills/sprout-cli");
         fs::create_dir_all(&real_dir).unwrap();
-        fs::write(real_dir.join("custom.md"), "user content").unwrap();
+        // Place SKILL.md so migration preserves it.
+        fs::write(real_dir.join("SKILL.md"), "custom skill content").unwrap();
 
         ensure_nest_at(&root).unwrap();
 
-        // Real directory should be preserved, not replaced with a symlink.
-        assert!(real_dir.is_dir());
-        assert!(!real_dir
-            .symlink_metadata()
-            .unwrap()
-            .file_type()
-            .is_symlink());
+        // Migration converts the real dir to a symlink; content is moved to canonical path.
+        assert!(
+            real_dir
+                .symlink_metadata()
+                .unwrap()
+                .file_type()
+                .is_symlink(),
+            ".claude/skills/sprout-cli should be migrated to a symlink"
+        );
+        // The canonical path now holds the migrated content.
+        let canonical = root.join(".agents/skills/sprout-cli/SKILL.md");
         assert_eq!(
-            fs::read_to_string(real_dir.join("custom.md")).unwrap(),
-            "user content"
+            fs::read_to_string(&canonical).unwrap(),
+            "custom skill content"
         );
     }
 

From 7f39683643175d02238d724dfa37646577c419de Mon Sep 17 00:00:00 2001
From: Will Pfleger <wpfleger@block.xyz>
Date: Tue, 26 May 2026 15:49:31 -0400
Subject: [PATCH 18/18] style(desktop): remove spurious blank line in nest.rs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Fixes cargo fmt violation at nest.rs:165 — extra blank line between
refresh_skill_md_if_stale and the permissions comment block.
---
 desktop/src-tauri/src/commands/agent_models.rs | 6 +++---
 desktop/src-tauri/src/managed_agents/nest.rs   | 1 -
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/desktop/src-tauri/src/commands/agent_models.rs b/desktop/src-tauri/src/commands/agent_models.rs
index 554469446f..3d7bc12f20 100644
--- a/desktop/src-tauri/src/commands/agent_models.rs
+++ b/desktop/src-tauri/src/commands/agent_models.rs
@@ -8,9 +8,9 @@ use crate::{
     managed_agents::{
         build_managed_agent_summary, default_agent_workdir, find_managed_agent_mut,
         load_managed_agents, managed_agent_avatar_url, missing_command_message,
-        normalize_agent_args, resolve_command, save_managed_agents,
-        sync_managed_agent_processes, try_regenerate_nest, AgentModelInfo, AgentModelsResponse,
-        UpdateManagedAgentRequest, UpdateManagedAgentResponse, DEFAULT_MCP_COMMAND,
+        normalize_agent_args, resolve_command, save_managed_agents, sync_managed_agent_processes,
+        try_regenerate_nest, AgentModelInfo, AgentModelsResponse, UpdateManagedAgentRequest,
+        UpdateManagedAgentResponse, DEFAULT_MCP_COMMAND,
     },
     relay::{relay_ws_url_with_override, sync_managed_agent_profile},
     util::now_iso,
diff --git a/desktop/src-tauri/src/managed_agents/nest.rs b/desktop/src-tauri/src/managed_agents/nest.rs
index 563ac462d7..02476d8ea4 100644
--- a/desktop/src-tauri/src/managed_agents/nest.rs
+++ b/desktop/src-tauri/src/managed_agents/nest.rs
@@ -165,7 +165,6 @@ pub fn ensure_nest_at(root: &Path) -> Result<(), String> {
     refresh_agents_md_if_stale(root)?;
     refresh_skill_md_if_stale(root)?;
 
-
     // Set owner-only permissions on root and all subdirectories.
     // Skip any path that is a symlink — chmod would affect the target.
     #[cfg(unix)]
