Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,6 @@ crates/docs_preprocessor/actions.json
/december-2025-releases.md
/docs/december-2025-documentation-gaps.md
site/

# AI Dock smoke-test screenshots (verification evidence — local only)
aidock-*.png
26 changes: 26 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ members = [
"crates/paddleboard_sandbox_prereqs_state",
"crates/paddleboard_sandbox_prereqs_ui",
"crates/paddleboard_sandbox_settings",
"crates/paddleboard_ai_dock",
"crates/windows_resources",
"crates/zeta_prompt",
"crates/zlog",
Expand Down Expand Up @@ -501,6 +502,7 @@ paddleboard_sandbox_prereqs = { path = "crates/paddleboard_sandbox_prereqs" }
paddleboard_sandbox_prereqs_state = { path = "crates/paddleboard_sandbox_prereqs_state" }
paddleboard_sandbox_prereqs_ui = { path = "crates/paddleboard_sandbox_prereqs_ui" }
paddleboard_sandbox_settings = { path = "crates/paddleboard_sandbox_settings" }
paddleboard_ai_dock = { path = "crates/paddleboard_ai_dock" }
edit_prediction = { path = "crates/edit_prediction" }
edit_prediction_metrics = { path = "crates/edit_prediction_metrics" }
zeta_prompt = { path = "crates/zeta_prompt" }
Expand Down
82 changes: 82 additions & 0 deletions RECAPS.md

Large diffs are not rendered by default.

17 changes: 15 additions & 2 deletions WELCOME.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ Most editors run **MCP (Model Context Protocol) servers** directly on your host.

PaddleBoard adds a fourth context-server transport, `sandboxed_stdio`, that runs the MCP server inside a `podman run -i --rm --runtime=runsc` container. Stdin and stdout are proxied transparently, so the JSON-RPC framing keeps working without any change on the agent side.

**The MCP Servers settings page** (command palette → `zed: Mcp Servers`) gives you a UI for adding, filtering (All / Running / Stopped / Error), and inspecting servers without hand-editing JSON. Use the "Add Server" popover to declare a new server; the page surfaces live status as the connection comes up.
**Manage servers in the AI Dock** — `paddleboard: Mcp Servers` (or `ai_dock: Open` then the **MCP Servers** tab) opens the PaddleBoard AI Dock with the absorbed server view. You get the full add/filter (All / Running / Stopped / Error) / inspect surface plus a side-by-side **Available** catalog of well-known servers without hand-editing JSON.

You can still configure servers by hand in `settings.json` if you prefer:

Expand All @@ -103,6 +103,19 @@ The original `stdio` transport (which runs the binary directly on your host) is

---

### AI Dock

One place to browse and install everything the agent talks to. Think of it as the marina where every external collaborator your PaddleBoard talks to ties up.

- Open it from the command palette (`ai_dock: Open`) or the **Open the AI Dock** button on the Welcome screen. The Welcome screen also shows a small **Featured** strip of well-known agents (Claude, Codex, Copilot, Cursor) — clicking any pill opens the Dock so first-run users have something concrete to recognize.
- Three tabs: **Agents** (Zed, Claude, Codex, Copilot, Cursor, …), **Skills** (slash commands shipped with the project or installed in `~/.claude/commands/`), and **MCP Servers** (the absorbed management page plus a catalog of common servers).
- Installed items show a green badge; missing ones show an **Install / Sign In / Learn More** action that does the right thing for the category — agent installs are a one-click settings write, sign-in flows route to your existing identity, MCP server adds delegate to the existing setup machinery, and bundled skills (currently `/build` and `/update-tour`) install with **Add to project** / **Add to user** buttons that drop a markdown file into the right `.claude/commands/` directory.
- The catalog itself is `assets/ai_dock/catalog.json` in this repo — adding an entry is a PR, not a network fetch, so what shows up in the Dock is exactly what the team has reviewed.

The AI Dock replaces the old hardcoded 5-card "Agent Setup" row on the Welcome screen and the standalone MCP Servers pane — both routes now land here.

---

### Step-through mode

Step-through mode lets you approve every tool call before the agent executes it — useful when you want to watch exactly what the agent is doing or sanity-check a risky operation.
Expand Down Expand Up @@ -185,7 +198,7 @@ Everything else: multi-buffer editor, LSP, DAP debugger, git panel, terminal, Vi
| Enable step-through mode | Click the ⏭ icon in the agent thread toolbar |
| See all agent threads | Click the list-tree icon in the panel bar |
| Switch LLM provider | Open the LLM Picker panel from the panel bar |
| Configure MCP servers | `Cmd-Shift-P` → `zed: Mcp Servers` |
| Configure MCP servers | `Cmd-Shift-P` → `paddleboard: Mcp Servers` |
| Switch / create a worktree | `Cmd-Shift-P` → `git: Worktree` |
| Run code in a sandbox | Ask the agent to run a command — it uses the Sandbox Tool automatically |
| Run a service in a sandbox | Ask the agent to start a server (e.g. `python3 -m http.server 8000`) — it uses the Sandbox Service Tool, and the URL appears in the Forwarded Ports row of the browser panel |
Expand Down
125 changes: 125 additions & 0 deletions assets/ai_dock/catalog.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
{
"$schema_note": "PaddleBoard AI Dock catalog. Edit via PR. See crates/paddleboard_ai_dock/src/catalog.rs for the schema.",
"agents": [
{
"id": "zed-agent",
"name": "Zed Agent",
"description": "First-party agent backed by Anthropic, OpenAI, and Google models. Sign in to use.",
"homepage": "https://zed.dev/agent",
"featured": true,
"builtin_zed": true
},
{
"id": "claude-acp",
"name": "Claude Agent",
"description": "Anthropic's Claude agent over ACP. Streaming tool use, persistent threads, multi-modal.",
"homepage": "https://docs.claude.com/en/docs/claude-code/overview",
"featured": true
},
{
"id": "codex-acp",
"name": "Codex CLI",
"description": "OpenAI's terminal coding agent. Runs locally; bring your own API key.",
"homepage": "https://github.com/openai/codex",
"featured": true
},
{
"id": "github-copilot-cli",
"name": "GitHub Copilot",
"description": "GitHub's coding assistant. Sign in with your GitHub account.",
"homepage": "https://github.com/features/copilot",
"featured": true
},
{
"id": "cursor",
"name": "Cursor",
"description": "Cursor's agent over ACP. Connects to the Cursor backend.",
"homepage": "https://www.cursor.com/",
"featured": false
}
],
"skills": [
{
"id": "build",
"name": "/build",
"description": "Build PaddleBoard via cargo. Use `bundle` for a macOS .app, `install` to drop it into /Applications.",
"homepage": null,
"featured": true
},
{
"id": "update-tour",
"name": "/update-tour",
"description": "Sync the in-app first-launch tour with the latest WELCOME.md after a user-facing change.",
"homepage": null,
"featured": true
},
{
"id": "verify",
"name": "/verify",
"description": "Run the app and confirm a change actually does what it's supposed to do.",
"homepage": null,
"featured": false
},
{
"id": "review",
"name": "/review",
"description": "Review a pull request.",
"homepage": null,
"featured": false
},
{
"id": "security-review",
"name": "/security-review",
"description": "Run a complete security review of pending changes on the current branch.",
"homepage": null,
"featured": false
}
],
"mcp_servers": [
{
"id": "filesystem",
"name": "Filesystem",
"description": "Read, write, and list files under a directory you allow.",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "."],
"homepage": "https://github.com/modelcontextprotocol/servers/tree/main/src/filesystem",
"featured": true
},
{
"id": "fetch",
"name": "Fetch",
"description": "HTTP fetch for URLs, returning markdown-converted text.",
"command": "uvx",
"args": ["mcp-server-fetch"],
"homepage": "https://github.com/modelcontextprotocol/servers/tree/main/src/fetch",
"featured": true
},
{
"id": "git",
"name": "Git",
"description": "Inspect git history, branches, diffs, and blame for a repository.",
"command": "uvx",
"args": ["mcp-server-git", "--repository", "."],
"homepage": "https://github.com/modelcontextprotocol/servers/tree/main/src/git",
"featured": true
},
{
"id": "github",
"name": "GitHub",
"description": "Read and write to GitHub repos, issues, and PRs via the GitHub API.",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"homepage": "https://github.com/modelcontextprotocol/servers/tree/main/src/github",
"featured": false
},
{
"id": "puppeteer",
"name": "Puppeteer",
"description": "Headless browser automation: navigate pages, take screenshots, scrape content.",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-puppeteer"],
"homepage": "https://github.com/modelcontextprotocol/servers/tree/main/src/puppeteer",
"featured": false
}
]
}
24 changes: 4 additions & 20 deletions crates/agent_ui/src/agent_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ pub use crate::agent_panel::{
};
pub use crate::orchestration_panel::OrchestrationPanel;
use crate::agent_registry_ui::AgentRegistryPage;
use crate::mcp_servers_ui::McpServersPage;
pub use crate::mcp_servers_ui::McpServersView;
pub use crate::inline_assistant::InlineAssistant;
pub use crate::thread_metadata_store::ThreadId;
pub use agent_diff::{AgentDiffPane, AgentDiffToolbar};
Expand Down Expand Up @@ -572,25 +572,9 @@ pub fn init(
}
},
);
workspace.register_action(
move |workspace: &mut Workspace,
_: &paddleboard_actions::McpServers,
window: &mut Window,
cx: &mut Context<Workspace>| {
let existing = workspace
.active_pane()
.read(cx)
.items()
.find_map(|item| item.downcast::<McpServersPage>());

if let Some(existing) = existing {
workspace.activate_item(&existing, true, true, window, cx);
} else {
let page = McpServersPage::new(workspace, window, cx);
workspace.add_item_to_active_pane(Box::new(page), None, true, window, cx);
}
},
);
// PaddleBoard: `McpServers` is registered by `paddleboard_store::init`
// — opening the MCP Servers UI now routes through the Store modal, so
// the legacy pane-item handler that used to live here has moved.
})
.detach();
cx.observe_new(|workspace: &mut Workspace, _window, _cx| {
Expand Down
42 changes: 6 additions & 36 deletions crates/agent_ui/src/mcp_servers_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ use editor::{Editor, EditorElement, EditorStyle};
use extension_host::ExtensionStore;
use fs::Fs;
use gpui::{
Action, Anchor as Corner, AnyElement, App, Context, Entity, EventEmitter, Focusable,
KeyContext,
Action, Anchor as Corner, AnyElement, App, Context, Entity, Focusable, KeyContext,
ParentElement, Render, RenderOnce, SharedString, Styled, Task, TextStyle,
UniformListScrollHandle, WeakEntity, Window, point, uniform_list,
};
Expand All @@ -24,10 +23,7 @@ use ui::{
WithScrollbar, prelude::*,
};
use util::ResultExt as _;
use workspace::{
Workspace,
item::{Item, ItemEvent},
};
use workspace::Workspace;

use crate::agent_configuration::{
ConfigureContextServerModal, ConfigureContextServerToolsModal,
Expand Down Expand Up @@ -81,7 +77,7 @@ impl RenderOnce for McpServerCard {
}
}

pub struct McpServersPage {
pub struct McpServersView {
fs: Arc<dyn Fs>,
language_registry: Arc<LanguageRegistry>,
workspace: WeakEntity<Workspace>,
Expand All @@ -95,7 +91,7 @@ pub struct McpServersPage {
_subscriptions: Vec<gpui::Subscription>,
}

impl McpServersPage {
impl McpServersView {
pub fn new(
workspace: &Workspace,
window: &mut Window,
Expand Down Expand Up @@ -751,7 +747,7 @@ impl McpServersPage {
}
}

impl Render for McpServersPage {
impl Render for McpServersView {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let total = self.server_ids.len();
let running = self
Expand Down Expand Up @@ -864,34 +860,8 @@ impl Render for McpServersPage {
}
}

impl EventEmitter<ItemEvent> for McpServersPage {}

impl Focusable for McpServersPage {
impl Focusable for McpServersView {
fn focus_handle(&self, cx: &App) -> gpui::FocusHandle {
self.query_editor.read(cx).focus_handle(cx)
}
}

impl Item for McpServersPage {
type Event = ItemEvent;

fn tab_content_text(&self, _detail: usize, _cx: &App) -> SharedString {
"MCP Servers".into()
}

fn tab_icon(&self, _window: &Window, _cx: &App) -> Option<Icon> {
Some(Icon::new(IconName::Server))
}

fn telemetry_event_text(&self) -> Option<&'static str> {
Some("MCP Servers Page Opened")
}

fn show_toolbar(&self) -> bool {
false
}

fn to_item_events(event: &Self::Event, f: &mut dyn FnMut(workspace::item::ItemEvent)) {
f(*event)
}
}
17 changes: 17 additions & 0 deletions crates/command_palette/src/command_palette.rs
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,18 @@ impl PickerDelegate for CommandPaletteDelegate {
}

pub fn humanize_action_name(name: &str) -> String {
// PaddleBoard: rename the `zed` action namespace to `paddleboard` for
// user-facing display (command palette, which-key, keymap editor, menus).
// The underlying action name returned by `Action::name()` is still
// `zed::...`, so every binding in `assets/keymaps/` keeps resolving — this
// is presentation-only, not a real namespace rename.
let renamed;
let name = if let Some(rest) = name.strip_prefix("zed::") {
renamed = format!("paddleboard::{rest}");
renamed.as_str()
} else {
name
};
let capacity = name.len() + name.chars().filter(|c| c.is_uppercase()).count();
let mut result = String::with_capacity(capacity);
for char in name.chars() {
Expand Down Expand Up @@ -753,6 +765,11 @@ mod tests {
humanize_action_name("go_to_line::Deploy"),
"go to line: deploy"
);
// PaddleBoard: `zed::` namespace is remapped to `paddleboard:` for display.
assert_eq!(
humanize_action_name("zed::OpenOnboarding"),
"paddleboard: open onboarding"
);
}

#[test]
Expand Down
Loading
Loading