zubo 0.1.20 → 0.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zubo",
3
- "version": "0.1.20",
3
+ "version": "0.1.21",
4
4
  "description": "Your AI agent that never forgets. Persistent memory, 25+ tools, 7 channels, 11+ LLM providers — runs entirely on your machine.",
5
5
  "license": "MIT",
6
6
  "author": "thomaskanze",
@@ -89,11 +89,11 @@
89
89
  <p>By default, Zubo operates as a single agent that handles all messages across every connected channel using a unified session identified as "owner." This default agent has access to all registered tools &mdash; both built-in tools and any user-installed skills &mdash; and its personality and behavior are defined by the system prompt stored at <code>~/.zubo/workspace/SYSTEM.md</code>.</p>
90
90
  <p>For many use cases, the default agent is all you need. It can search the web, manage your calendar, write code, read and write memory, and use any skill you install. Custom agents become valuable when you want to restrict tool access, provide specialized instructions, or build multi-step workflows.</p>
91
91
 
92
- <h2>Custom System Prompt</h2>
92
+ <h2>Personality</h2>
93
93
  <p>The system prompt defines your agent's personality, rules, and background knowledge. There are two ways to customize it:</p>
94
94
  <ul>
95
95
  <li><strong>Edit the file directly</strong> &mdash; Open <code>~/.zubo/workspace/SYSTEM.md</code> in any text editor and modify it.</li>
96
- <li><strong>Use the dashboard</strong> &mdash; Navigate to the System Prompt panel in the web dashboard and edit it there. Changes are saved to <code>SYSTEM.md</code> automatically.</li>
96
+ <li><strong>Use the dashboard</strong> &mdash; Navigate to the Personality panel in the web dashboard and edit it there. Changes are saved to <code>SYSTEM.md</code> automatically.</li>
97
97
  </ul>
98
98
  <p>Here is an example <code>SYSTEM.md</code> that defines a personalized assistant:</p>
99
99
  <pre><code># System Prompt
@@ -200,7 +200,7 @@ file: &lt;document&gt;</code></pre>
200
200
  "Status": "running"
201
201
  }</code></pre>
202
202
 
203
- <h3>System Prompt</h3>
203
+ <h3>Personality</h3>
204
204
  <pre><code>GET /api/dashboard/system</code></pre>
205
205
  <p>Retrieve the current system prompt.</p>
206
206
  <pre><code>PUT /api/dashboard/system
@@ -583,7 +583,7 @@ Content-Type: application/json
583
583
  <pre><code>GET /api/dashboard/channel-status</code></pre>
584
584
  <p>Returns the configuration and connection status for each channel (webchat, Telegram, Discord, Slack, WhatsApp, Signal). Each channel reports whether it is configured and whether it is currently enabled.</p>
585
585
 
586
- <h3>Secrets Management</h3>
586
+ <h3>API Keys Management</h3>
587
587
  <pre><code>GET /api/dashboard/secrets</code></pre>
588
588
  <p>List all stored secrets. Values are masked in the response for security.</p>
589
589
  <pre><code>GET /api/dashboard/secrets/:name</code></pre>
@@ -69,7 +69,7 @@
69
69
  <a href="/docs/conversations">Conversation History</a>
70
70
  <a href="/docs/webhooks">Webhooks</a>
71
71
  <a href="/docs/workflows">Visual Workflows</a>
72
- <a href="/docs/marketplace">MCP Marketplace</a>
72
+ <a href="/docs/marketplace">Extensions Marketplace</a>
73
73
  </div>
74
74
  </div>
75
75
  <div class="docs-sidebar-section">
@@ -300,10 +300,10 @@ docker compose up -d</code></pre>
300
300
 
301
301
  <p>The wizard walks you through 4 steps:</p>
302
302
  <ul>
303
- <li><strong>Step 1: LLM Provider</strong> &mdash; choose from 15 supported providers (Anthropic, OpenAI, Ollama, Groq, Together, OpenRouter, DeepSeek, xAI, MiniMax, Fireworks, Cerebras, LM Studio, Claude Code, Codex, or any OpenAI-compatible endpoint) and enter your API key. Optionally configure a fallback provider for automatic failover.</li>
303
+ <li><strong>Step 1: AI Provider</strong> &mdash; choose from 15 supported providers (Anthropic, OpenAI, Ollama, Groq, Together, OpenRouter, DeepSeek, xAI, MiniMax, Fireworks, Cerebras, LM Studio, Claude Code, Codex, or any OpenAI-compatible endpoint) and enter your API key. Optionally configure a fallback provider for automatic failover.</li>
304
304
  <li><strong>Step 2: Channels</strong> &mdash; enable any combination of Telegram, Discord, Slack, WhatsApp, Signal, and Email. Enter the required tokens and credentials for each. Web Chat is always on and requires no configuration.</li>
305
305
  <li><strong>Step 3: Personalization</strong> &mdash; set your agent's name and describe its personality. This shapes how Zubo talks to you across all channels.</li>
306
- <li><strong>Step 4: Smart Routing</strong> &mdash; optionally configure a fast model (e.g., Groq) for simple queries. Smart routing automatically detects low-complexity messages and routes them to the cheaper, faster model, saving 50&ndash;80% on costs without sacrificing quality for complex tasks.</li>
306
+ <li><strong>Step 4: Smart Cost Savings</strong> &mdash; optionally configure a fast model (e.g., Groq) for simple queries. Smart routing automatically detects low-complexity messages and routes them to the cheaper, faster model, saving 50&ndash;80% on costs without sacrificing quality for complex tasks.</li>
307
307
  </ul>
308
308
  <p>The wizard also creates the <code>~/.zubo</code> directory and all required subdirectories, generates your <code>~/.zubo/config.json</code> file, and downloads the all-MiniLM-L6-v2 embedding model (~80 MB) for local semantic memory.</p>
309
309
 
@@ -624,7 +624,7 @@ zubo start --daemon</code></pre>
624
624
  <li><strong>Use <code>zubo start --daemon</code></strong> for always-on operation. Zubo writes a PID file and rotates logs automatically.</li>
625
625
  <li><strong>Check <code>zubo status</code> and <code>zubo logs</code></strong> for troubleshooting. The status command shows uptime, memory usage, connected channels, and pending scheduled jobs.</li>
626
626
  <li><strong>Back up your data</strong> with <code>zubo export</code> for a full JSON export, or rely on the automatic daily SQLite backups in <code>~/.zubo/workspace/backups/</code>.</li>
627
- <li><strong>Enable smart routing</strong> to automatically send simple queries to fast, cheap models. Set <code>smartRouting.enabled</code> to <code>true</code> and configure a <code>fastProvider</code> (e.g., Groq) alongside your primary. This can cut costs significantly.</li>
627
+ <li><strong>Enable smart cost savings</strong> to automatically send simple queries to fast, cheap models. Set <code>smartRouting.enabled</code> to <code>true</code> and configure a <code>fastProvider</code> (e.g., Groq) alongside your primary. This can cut costs significantly.</li>
628
628
  <li><strong>Set a budget</strong> to avoid surprise bills: <code>zubo config set budget.dailyLimit 5</code>. Cost tracking is always active in the dashboard under Analytics &rarr; Costs.</li>
629
629
  <li><strong>Configure failover providers</strong> so your agent stays available even if your primary LLM provider has an outage. For example, set Anthropic as primary and Ollama as failover for fully offline operation when the cloud is down.</li>
630
630
  <li><strong>Keep skills small and focused</strong> &mdash; one skill per task. This makes them easier to test, share, and debug.</li>
@@ -644,7 +644,7 @@ zubo start --daemon</code></pre>
644
644
  <li><a href="/docs/conversations"><strong>Conversation History</strong></a> &mdash; unified cross-channel history with FTS5 search, dashboard browsing, and API access for searching and analyzing past conversations across all channels.</li>
645
645
  <li><a href="/docs/webhooks"><strong>Webhooks</strong></a> &mdash; create webhook endpoints for GitHub, Stripe, CI/CD, and any external service. HMAC signature verification, prompt templates with <code>{{payload}}</code> substitution, and dashboard management.</li>
646
646
  <li><a href="/docs/workflows"><strong>Visual Workflows</strong></a> &mdash; build multi-step automations with the drag-and-drop workflow builder. Step types (tool, agent, condition, message, delay), triggers (manual, cron, webhook), and template variables.</li>
647
- <li><a href="/docs/marketplace"><strong>MCP Marketplace</strong></a> &mdash; browse, install, and manage MCP servers from the official registry. One-click installation with automatic tool registration.</li>
647
+ <li><a href="/docs/marketplace"><strong>Extensions Marketplace</strong></a> &mdash; browse, install, and manage MCP servers from the official registry. One-click installation with automatic tool registration.</li>
648
648
  <li><a href="/docs/integrations"><strong>Integrations</strong></a> &mdash; connect Zubo to GitHub, Google Workspace, Notion, Linear, Jira, and more. <a href="/docs/integrations#oauth">OAuth 2.0 authentication</a> with automatic token refresh, API key setup, and usage examples.</li>
649
649
  <li><a href="/docs/security"><strong>Security &amp; Auth</strong></a> &mdash; harden your Zubo instance: API key management, tool permission levels, confirmation tokens, rate limiting, file access restrictions, and network security.</li>
650
650
  <li><a href="/docs/api"><strong>API Reference</strong></a> &mdash; complete HTTP API documentation for programmatic access: endpoints, request/response formats, authentication, and WebSocket streaming.</li>
@@ -101,7 +101,7 @@
101
101
  <p>There are three ways to connect a service:</p>
102
102
  <ol>
103
103
  <li><strong>Chat:</strong> Tell Zubo directly &mdash; for example, <code>"Connect GitHub with token ghp_abc123"</code>. Zubo will store the secret and install the skill pack automatically.</li>
104
- <li><strong>Dashboard:</strong> Navigate to Settings &rarr; Secrets &rarr; Add Secret. Enter the secret name and value, then Zubo detects the associated integration and installs the skills.</li>
104
+ <li><strong>Dashboard:</strong> Navigate to Settings &rarr; API Keys. Enter the secret name and value, then Zubo detects the associated integration and installs the skills.</li>
105
105
  <li><strong>CLI:</strong> Run <code>zubo start</code>, then use the <code>connect_service</code> tool programmatically to provide the credentials.</li>
106
106
  </ol>
107
107
  <p>When you connect a service, Zubo performs the following steps:</p>
@@ -384,11 +384,11 @@ zubo mcp-serve</code></pre>
384
384
  </tbody>
385
385
  </table>
386
386
 
387
- <h2 id="managing-secrets">Managing Secrets</h2>
387
+ <h2 id="managing-secrets">Managing API Keys</h2>
388
388
  <p>All integration secrets are managed through the same unified secret system.</p>
389
389
  <h3>Dashboard</h3>
390
390
  <ul>
391
- <li>Navigate to Settings &rarr; Secrets &amp; API Keys</li>
391
+ <li>Navigate to Settings &rarr; API Keys</li>
392
392
  <li>Values are displayed as <code>&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;</code> by default</li>
393
393
  <li>Click <strong>&ldquo;Reveal&rdquo;</strong> to show the actual secret value</li>
394
394
  <li>Click <strong>&ldquo;Edit&rdquo;</strong> to update a secret with a new value</li>
@@ -3,18 +3,18 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>MCP Marketplace — Zubo Docs</title>
6
+ <title>Extensions Marketplace — Zubo Docs</title>
7
7
  <meta name="description" content="Browse, install, and manage MCP servers from the built-in marketplace. Extend Zubo with community-built tools, one-click installs, and automatic configuration.">
8
8
  <meta name="theme-color" content="#060608">
9
9
  <link rel="canonical" href="https://zubo.bot/docs/marketplace">
10
- <meta property="og:title" content="MCP Marketplace — Zubo Docs">
10
+ <meta property="og:title" content="Extensions Marketplace — Zubo Docs">
11
11
  <meta property="og:description" content="Browse, install, and manage MCP servers from the built-in marketplace. Extend Zubo with community-built tools, one-click installs, and automatic configuration.">
12
12
  <meta property="og:type" content="website">
13
13
  <meta property="og:url" content="https://zubo.bot/docs/marketplace">
14
14
  <meta property="og:image" content="https://zubo.bot/og-image.png">
15
15
  <meta property="og:site_name" content="Zubo">
16
16
  <meta name="twitter:card" content="summary_large_image">
17
- <meta name="twitter:title" content="MCP Marketplace — Zubo Docs">
17
+ <meta name="twitter:title" content="Extensions Marketplace — Zubo Docs">
18
18
  <meta name="twitter:description" content="Browse, install, and manage MCP servers from the built-in marketplace. Extend Zubo with community-built tools, one-click installs, and automatic configuration.">
19
19
  <meta name="twitter:image" content="https://zubo.bot/og-image.png">
20
20
  <meta name="twitter:creator" content="@thomaskanze">
@@ -67,7 +67,7 @@
67
67
  <a href="/docs/conversations">Conversation History</a>
68
68
  <a href="/docs/webhooks">Webhooks</a>
69
69
  <a href="/docs/workflows">Visual Workflows</a>
70
- <a href="/docs/marketplace" class="active">MCP Marketplace</a>
70
+ <a href="/docs/marketplace" class="active">Extensions Marketplace</a>
71
71
  </div>
72
72
  </div>
73
73
  <div class="docs-sidebar-section">
@@ -89,12 +89,12 @@
89
89
  </aside>
90
90
 
91
91
  <main class="docs-content">
92
- <div class="docs-breadcrumb"><a href="/">Home</a><span>/</span><a href="/docs/">Docs</a><span>/</span>MCP Marketplace</div>
92
+ <div class="docs-breadcrumb"><a href="/">Home</a><span>/</span><a href="/docs/">Docs</a><span>/</span>Extensions Marketplace</div>
93
93
 
94
- <h1>MCP Marketplace</h1>
94
+ <h1>Extensions Marketplace</h1>
95
95
 
96
96
  <p>
97
- The MCP Marketplace lets you browse, install, and manage MCP (Model Context Protocol) servers from the official registry directly through the Zubo dashboard or API. Instead of manually configuring MCP server commands and arguments, you can discover servers from the community, install them with one click, and have their tools automatically registered in Zubo.
97
+ The Extensions Marketplace lets you browse, install, and manage MCP (Model Context Protocol) servers from the official registry directly through the Zubo dashboard or API. Instead of manually configuring MCP server commands and arguments, you can discover servers from the community, install them with one click, and have their tools automatically registered in Zubo.
98
98
  </p>
99
99
 
100
100
  <!-- ================================================================ -->
@@ -107,7 +107,7 @@
107
107
  <h3>Via the Dashboard</h3>
108
108
 
109
109
  <ol>
110
- <li>Open the web dashboard and navigate to the <strong>MCP</strong> panel in the sidebar.</li>
110
+ <li>Open the web dashboard and navigate to the <strong>Extensions</strong> panel in the sidebar.</li>
111
111
  <li>Click the <strong>Marketplace</strong> tab to view the available servers from the registry.</li>
112
112
  <li>Use the search bar to filter servers by name or keyword (e.g., "filesystem", "database", "github").</li>
113
113
  <li>Each server card shows the name, description, author, tool count, and install status.</li>
@@ -291,7 +291,7 @@ Content-Type: application/json
291
291
  "itemListElement": [
292
292
  { "@type": "ListItem", "position": 1, "name": "Home", "item": "https://zubo.bot/" },
293
293
  { "@type": "ListItem", "position": 2, "name": "Docs", "item": "https://zubo.bot/docs/" },
294
- { "@type": "ListItem", "position": 3, "name": "MCP Marketplace", "item": "https://zubo.bot/docs/marketplace" }
294
+ { "@type": "ListItem", "position": 3, "name": "Extensions Marketplace", "item": "https://zubo.bot/docs/marketplace" }
295
295
  ]
296
296
  }
297
297
  </script>
@@ -169,18 +169,18 @@
169
169
 
170
170
  <h2 id="secret-management">Secret Management</h2>
171
171
  <p>Secrets (API keys, tokens, passwords) are stored securely in the local SQLite <code>secrets</code> table. The agent can use secrets by name but <strong>never sees their actual values</strong> in conversation context.</p>
172
- <h3>Storing Secrets</h3>
172
+ <h3>Storing API Keys</h3>
173
173
  <p>There are three ways to store a secret:</p>
174
174
  <ul>
175
175
  <li><strong>Chat:</strong> Tell Zubo directly &mdash; <code>"Store my GitHub token: ghp_abc123xyz"</code></li>
176
176
  <li><strong>Tool:</strong> The <code>secret_set</code> tool can be called programmatically</li>
177
- <li><strong>Dashboard:</strong> Navigate to Settings &rarr; Secrets and use the form</li>
177
+ <li><strong>Dashboard:</strong> Navigate to Settings &rarr; API Keys and use the form</li>
178
178
  </ul>
179
- <h3>Accessing Secrets in Skills</h3>
179
+ <h3>Accessing API Keys in Skills</h3>
180
180
  <p>User-installed skills can access secrets via environment variables:</p>
181
181
  <pre><code>const token = process.env.ZUBO_SECRET_GITHUB_TOKEN;</code></pre>
182
182
  <p>Only secrets explicitly declared in the skill manifest are passed to the skill process.</p>
183
- <h3>Managing Secrets</h3>
183
+ <h3>Managing API Keys</h3>
184
184
  <ul>
185
185
  <li><strong>Dashboard:</strong> View masked values (<code>&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;</code>), click &ldquo;Reveal&rdquo; to show the actual value, click &ldquo;Edit&rdquo; to update, or &ldquo;Delete&rdquo; to remove</li>
186
186
  <li><strong>Naming:</strong> Secret names must match the pattern <code>[a-z0-9_]+</code> (lowercase alphanumeric and underscores only)</li>
@@ -162,7 +162,7 @@ export default async function (input: Record&lt;string, unknown&gt;): Promise&lt
162
162
  <li><strong>Cannot import from Zubo internals</strong> &mdash; skills run in a sandboxed subprocess and have no access to Zubo's core modules, database, or session state</li>
163
163
  </ul>
164
164
 
165
- <h2>Accessing Secrets</h2>
165
+ <h2>Accessing API Keys</h2>
166
166
  <p>Skills often need API keys or credentials to call external services. Zubo provides a secure way to pass secrets to skill handlers via environment variables:</p>
167
167
  <pre><code>export default async function (input: Record&lt;string, unknown&gt;): Promise&lt;string&gt; {
168
168
  const apiKey = process.env.ZUBO_SECRET_WEATHER_API_KEY;
package/site/index.html CHANGED
@@ -4,18 +4,18 @@
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Zubo — Your AI Agent. Your Machine. Your Rules.</title>
7
- <meta name="description" content="Open-source AI agent that runs on your machine. One command to install, one file to configure. Persistent memory, 25+ tools, 7 messaging channels, 12+ LLM providers. MCP compatible. Zero complexity.">
7
+ <meta name="description" content="Open-source AI agent that runs on your machine. One command to install, one file to configure. Persistent memory, 25+ tools, 7 messaging channels, 12+ AI providers. Extension compatible. Zero complexity.">
8
8
  <meta name="theme-color" content="#060608">
9
9
  <link rel="canonical" href="https://zubo.bot/">
10
10
  <meta property="og:title" content="Zubo — Your AI Agent. Your Machine. Your Rules.">
11
- <meta property="og:description" content="Open-source AI agent that runs on your machine. Persistent memory, 25+ tools, works across Telegram, Discord, Slack, WhatsApp, Email, and more. MCP compatible. One install, zero cloud.">
11
+ <meta property="og:description" content="Open-source AI agent that runs on your machine. Persistent memory, 25+ tools, works across Telegram, Discord, Slack, WhatsApp, Email, and more. Extension compatible. One install, zero cloud.">
12
12
  <meta property="og:type" content="website">
13
13
  <meta property="og:url" content="https://zubo.bot/">
14
14
  <meta property="og:image" content="https://zubo.bot/og-image.png">
15
15
  <meta property="og:site_name" content="Zubo">
16
16
  <meta name="twitter:card" content="summary_large_image">
17
17
  <meta name="twitter:title" content="Zubo — Your AI Agent. Your Machine. Your Rules.">
18
- <meta name="twitter:description" content="Open-source AI agent that runs on your machine. Persistent memory, 25+ tools, works across Telegram, Discord, Slack, WhatsApp, Email, and more. MCP compatible. One install, zero cloud.">
18
+ <meta name="twitter:description" content="Open-source AI agent that runs on your machine. Persistent memory, 25+ tools, works across Telegram, Discord, Slack, WhatsApp, Email, and more. Extension compatible. One install, zero cloud.">
19
19
  <meta name="twitter:image" content="https://zubo.bot/og-image.png">
20
20
  <meta name="twitter:creator" content="@thomaskanze">
21
21
  <link rel="preconnect" href="https://fonts.googleapis.com">
@@ -264,7 +264,7 @@
264
264
  <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></svg>
265
265
  </div>
266
266
  <h3>25+ Smart Tools</h3>
267
- <p>Web search, file operations, code interpreter, image generation, APIs, webhooks, and more. Knowledge graph memory, MCP support, and sub-agent delegation for complex tasks.</p>
267
+ <p>Web search, file operations, code interpreter, image generation, APIs, webhooks, and more. Knowledge graph memory, extension support, and sub-agent delegation for complex tasks.</p>
268
268
  </div>
269
269
 
270
270
  <div class="bento-card tilt-card" data-feature="privacy">
package/site/install.sh CHANGED
@@ -29,7 +29,9 @@ ARCH="$(uname -m)"
29
29
  case "$OS" in
30
30
  Linux*) PLATFORM="linux" ;;
31
31
  Darwin*) PLATFORM="darwin" ;;
32
- *) fail "Unsupported OS: $OS. Zubo supports macOS and Linux." ;;
32
+ MINGW*|MSYS*|CYGWIN*)
33
+ fail "Windows detected. Use WSL (Windows Subsystem for Linux) to run Zubo:\n\n ${DIM}wsl --install${RESET}\n Then run this installer inside WSL." ;;
34
+ *) fail "Unsupported OS: $OS. Zubo supports macOS, Linux, and Windows (via WSL)." ;;
33
35
  esac
34
36
 
35
37
  case "$ARCH" in
@@ -45,7 +47,7 @@ if command -v bun &>/dev/null; then
45
47
  BUN_VERSION=$(bun --version 2>/dev/null || echo "unknown")
46
48
  ok "Bun already installed (v${BUN_VERSION})"
47
49
  else
48
- info "Installing Bun runtime..."
50
+ info "Installing Bun (a fast JavaScript runtime Zubo needs)..."
49
51
  curl -fsSL https://bun.sh/install | bash
50
52
 
51
53
  # Source the updated profile so bun is on PATH
@@ -55,7 +57,7 @@ else
55
57
  if command -v bun &>/dev/null; then
56
58
  ok "Bun installed (v$(bun --version))"
57
59
  else
58
- fail "Bun installation failed. Install manually: https://bun.sh"
60
+ fail "Bun installation failed. Visit https://bun.sh for manual install instructions."
59
61
  fi
60
62
  fi
61
63
 
@@ -78,9 +80,13 @@ else
78
80
  # Bun global bin might not be on PATH yet
79
81
  ZUBO_BIN="${HOME}/.bun/bin/zubo"
80
82
  if [ -f "$ZUBO_BIN" ]; then
81
- warn "Zubo installed but not on PATH. Add this to your shell profile:"
83
+ warn "Zubo installed but your terminal can't find it yet."
82
84
  echo ""
83
- echo -e " ${DIM}export PATH=\"\$HOME/.bun/bin:\$PATH\"${RESET}"
85
+ echo -e " Run this command, then restart your terminal:"
86
+ echo ""
87
+ echo -e " ${BOLD}echo 'export PATH=\"\$HOME/.bun/bin:\$PATH\"' >> ~/.bashrc && source ~/.bashrc${RESET}"
88
+ echo ""
89
+ echo -e " ${DIM}(On macOS with zsh, use ~/.zshrc instead of ~/.bashrc)${RESET}"
84
90
  echo ""
85
91
  else
86
92
  fail "Zubo binary not found after install"
@@ -928,7 +928,7 @@ export const DASHBOARD_HTML = `<!DOCTYPE html>
928
928
  <span class="nav-svg-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg></span> Dashboard
929
929
  </a>
930
930
  <a href="#memory" onclick="showPanel('memory')">
931
- <span class="nav-svg-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2C8.5 2 6 4.5 6 7c0 1.5.5 2.8 1.4 3.8C6.5 12 6 13.5 6 15c0 3.5 2.5 7 6 7s6-3.5 6-7c0-1.5-.5-3-1.4-4.2C17.5 9.8 18 8.5 18 7c0-2.5-2.5-5-6-5z"/><path d="M9 10h6"/><path d="M9 14h6"/></svg></span> Memory
931
+ <span class="nav-svg-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2C8.5 2 6 4.5 6 7c0 1.5.5 2.8 1.4 3.8C6.5 12 6 13.5 6 15c0 3.5 2.5 7 6 7s6-3.5 6-7c0-1.5-.5-3-1.4-4.2C17.5 9.8 18 8.5 18 7c0-2.5-2.5-5-6-5z"/><path d="M9 10h6"/><path d="M9 14h6"/></svg></span> Knowledge
932
932
  </a>
933
933
  <a href="#skills" onclick="showPanel('skills')">
934
934
  <span class="nav-svg-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg></span> Skills
@@ -940,7 +940,7 @@ export const DASHBOARD_HTML = `<!DOCTYPE html>
940
940
  <span class="nav-svg-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M18 16.98h1.67c2.49 0 4.5-2.01 4.5-4.49 0-2.48-2.01-4.49-4.5-4.49h-.16C19.17 5.35 16.68 3 13.67 3 11.23 3 9.14 4.56 8.34 6.78c-.3-.05-.6-.08-.91-.08-2.76 0-5 2.24-5 5s2.24 5 5 5h1.48"/><polyline points="12 13 12 21"/><polyline points="9 18 12 21 15 18"/></svg></span> Webhooks
941
941
  </a>
942
942
  <a href="#mcp" onclick="showPanel('mcp')">
943
- <span class="nav-svg-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="20" height="12" rx="2"/><path d="M6 12h4"/><path d="M14 12h4"/><circle cx="8" cy="12" r="1"/><circle cx="16" cy="12" r="1"/></svg></span> MCP
943
+ <span class="nav-svg-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="20" height="12" rx="2"/><path d="M6 12h4"/><path d="M14 12h4"/><circle cx="8" cy="12" r="1"/><circle cx="16" cy="12" r="1"/></svg></span> Extensions
944
944
  </a>
945
945
  <div class="sidebar-divider"></div>
946
946
  <div class="sidebar-section">Settings</div>
@@ -989,11 +989,11 @@ export const DASHBOARD_HTML = `<!DOCTYPE html>
989
989
  <div class="suggestion-chips-group">
990
990
  <div class="chip-row">
991
991
  <button class="suggestion-chip" onclick="useSuggestion(this)">What can you do?</button>
992
- <button class="suggestion-chip" onclick="useSuggestion(this)">Check my schedule</button>
992
+ <button class="suggestion-chip" onclick="useSuggestion(this)">Set a reminder for tomorrow</button>
993
993
  </div>
994
994
  <div class="chip-row">
995
- <button class="suggestion-chip" onclick="useSuggestion(this)">Summarize recent emails</button>
996
- <button class="suggestion-chip" onclick="useSuggestion(this)">Set a reminder</button>
995
+ <button class="suggestion-chip" onclick="useSuggestion(this)">Help me write an email</button>
996
+ <button class="suggestion-chip" onclick="useSuggestion(this)">Explain something to me</button>
997
997
  </div>
998
998
  </div>
999
999
  </div>
@@ -1099,6 +1099,9 @@ export const DASHBOARD_HTML = `<!DOCTYPE html>
1099
1099
  <!-- MEMORY PANEL -->
1100
1100
  <div id="panel-memory" class="panel">
1101
1101
  <div class="panel-body">
1102
+ <div style="margin-bottom:20px;">
1103
+ <p class="settings-desc" style="margin-bottom:0;">Everything Zubo remembers about you and your conversations. Edit the persistent memory file directly, or search through individual memory chunks below.</p>
1104
+ </div>
1102
1105
  <div class="editor-wrap">
1103
1106
  <div class="editor-toolbar">
1104
1107
  <button class="btn btn-primary" onclick="saveMemory()">Save MEMORY.md</button>
@@ -1122,6 +1125,9 @@ export const DASHBOARD_HTML = `<!DOCTYPE html>
1122
1125
  <!-- SKILLS PANEL (with Browse/Registry tab) -->
1123
1126
  <div id="panel-skills" class="panel">
1124
1127
  <div class="panel-body">
1128
+ <div style="margin-bottom:16px;">
1129
+ <p class="settings-desc" style="margin-bottom:0;">Skills are custom capabilities you can add to Zubo. Browse the community registry to install new ones, or build your own in TypeScript.</p>
1130
+ </div>
1125
1131
  <div class="tab-bar" id="skills-tabs">
1126
1132
  <button class="tab active" onclick="switchTab('skills','installed')">Installed</button>
1127
1133
  <button class="tab" onclick="switchTab('skills','browse')">Browse Registry</button>
@@ -1206,6 +1212,9 @@ export const DASHBOARD_HTML = `<!DOCTYPE html>
1206
1212
  <!-- WORKFLOWS PANEL -->
1207
1213
  <div id="panel-workflows" class="panel">
1208
1214
  <div class="panel-body">
1215
+ <div style="margin-bottom:16px;">
1216
+ <p class="settings-desc" style="margin-bottom:0;">Automate multi-step tasks by chaining actions together. Use pre-built recipes, ask Zubo to create one in chat, or build visually with drag-and-drop.</p>
1217
+ </div>
1209
1218
  <div class="tab-bar" id="workflows-tabs">
1210
1219
  <button class="tab active" onclick="switchTab('workflows','recipes')">Recipes</button>
1211
1220
  <button class="tab" onclick="switchTab('workflows','custom')">Custom Workflows</button>
@@ -1305,6 +1314,9 @@ export const DASHBOARD_HTML = `<!DOCTYPE html>
1305
1314
  <!-- MCP MARKETPLACE PANEL -->
1306
1315
  <div id="panel-mcp" class="panel">
1307
1316
  <div class="panel-body">
1317
+ <div style="margin-bottom:16px;">
1318
+ <p class="settings-desc" style="margin-bottom:0;">Extensions use the <strong>MCP (Model Context Protocol)</strong> standard to give Zubo new tools — like accessing files, databases, GitHub, and more. Browse the marketplace or add your own.</p>
1319
+ </div>
1308
1320
  <div class="tab-bar" id="mcp-tabs">
1309
1321
  <button class="tab active" onclick="switchTab('mcp','installed')">Installed</button>
1310
1322
  <button class="tab" onclick="switchTab('mcp','marketplace')">Marketplace</button>
@@ -1314,22 +1326,22 @@ export const DASHBOARD_HTML = `<!DOCTYPE html>
1314
1326
  <div id="mcp-installed-list" style="display:flex;flex-direction:column;gap:12px;"></div>
1315
1327
  <div id="mcp-installed-empty" class="empty-state-card" style="display:none;">
1316
1328
  <div class="empty-icon"><svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="20" height="12" rx="2"/><path d="M6 12h4"/><path d="M14 12h4"/></svg></div>
1317
- <h4>No MCP servers installed</h4>
1318
- <p>Browse the marketplace to add powerful tool servers.</p>
1329
+ <h4>No extensions installed</h4>
1330
+ <p>Browse the marketplace to add powerful extensions.</p>
1319
1331
  <button class="btn btn-primary" onclick="switchTab('mcp','marketplace')">Browse Marketplace</button>
1320
1332
  </div>
1321
1333
  </div>
1322
1334
 
1323
1335
  <div class="tab-content" id="mcp-tab-marketplace">
1324
1336
  <div class="search-bar">
1325
- <input id="mcp-marketplace-search" type="text" placeholder="Search MCP servers (e.g. filesystem, github, database...)" onkeydown="if(event.key==='Enter')searchMcpMarketplace()">
1337
+ <input id="mcp-marketplace-search" type="text" placeholder="Search extensions (e.g. filesystem, github, database...)" onkeydown="if(event.key==='Enter')searchMcpMarketplace()">
1326
1338
  <button class="btn btn-primary" onclick="searchMcpMarketplace()">Search</button>
1327
1339
  </div>
1328
1340
  <div class="mcp-marketplace-grid" id="mcp-marketplace-results"></div>
1329
1341
  <div id="mcp-marketplace-empty" class="empty-state-card">
1330
1342
  <div class="empty-icon"><svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg></div>
1331
- <h4>Discover MCP Servers</h4>
1332
- <p>Search the official MCP registry to find and install tool servers.</p>
1343
+ <h4>Discover Extensions</h4>
1344
+ <p>Search the marketplace to find and install extensions.</p>
1333
1345
  </div>
1334
1346
  </div>
1335
1347
  </div>
@@ -1398,12 +1410,12 @@ export const DASHBOARD_HTML = `<!DOCTYPE html>
1398
1410
  <button class="tab active" onclick="switchTab('settings','general')">General</button>
1399
1411
  <button class="tab" onclick="switchTab('settings','providers')">Providers</button>
1400
1412
  <button class="tab" onclick="switchTab('settings','channels')">Channels</button>
1401
- <button class="tab" onclick="switchTab('settings','mcp')">MCP</button>
1402
- <button class="tab" onclick="switchTab('settings','routing')">Routing</button>
1413
+ <button class="tab" onclick="switchTab('settings','mcp')">Extensions</button>
1414
+ <button class="tab" onclick="switchTab('settings','routing')">Cost Savings</button>
1403
1415
  <button class="tab" onclick="switchTab('settings','data')">Data</button>
1404
- <button class="tab" onclick="switchTab('settings','secrets')">Secrets</button>
1405
- <button class="tab" onclick="switchTab('settings','system')">System Prompt</button>
1406
- <button class="tab" onclick="switchTab('settings','cron')">Cron</button>
1416
+ <button class="tab" onclick="switchTab('settings','secrets')">API Keys</button>
1417
+ <button class="tab" onclick="switchTab('settings','system')">Personality</button>
1418
+ <button class="tab" onclick="switchTab('settings','cron')">Scheduled Tasks</button>
1407
1419
  <button class="tab" onclick="switchTab('settings','logs')">Logs</button>
1408
1420
  <button class="tab" onclick="switchTab('settings','privacy')">Privacy</button>
1409
1421
  <button class="tab" onclick="switchTab('settings','budget')">Budget</button>
@@ -1413,11 +1425,11 @@ export const DASHBOARD_HTML = `<!DOCTYPE html>
1413
1425
  <!-- General Tab -->
1414
1426
  <div class="tab-content active" id="settings-tab-general">
1415
1427
  <div class="settings-section">
1416
- <h3 class="settings-title" data-tooltip="Select which AI model powers Zubo">LLM Provider</h3>
1417
- <p class="settings-desc">Select which provider and model Zubo uses.</p>
1428
+ <h3 class="settings-title" data-tooltip="Choose which AI powers your agent">AI Model</h3>
1429
+ <p class="settings-desc">Choose which AI service and model your agent uses for conversations.</p>
1418
1430
  <div class="settings-grid">
1419
1431
  <div class="settings-field">
1420
- <label class="settings-label" data-tooltip="Cloud AI service" for="settings-provider">Provider</label>
1432
+ <label class="settings-label" data-tooltip="AI service (e.g. Anthropic, OpenAI)" for="settings-provider">Provider</label>
1421
1433
  <select id="settings-provider" class="settings-select" onchange="onProviderChange()"></select>
1422
1434
  </div>
1423
1435
  <div class="settings-field">
@@ -1433,11 +1445,11 @@ export const DASHBOARD_HTML = `<!DOCTYPE html>
1433
1445
  </div>
1434
1446
 
1435
1447
  <div class="settings-section">
1436
- <h3 class="settings-title" data-tooltip="Background task frequency">Heartbeat Interval</h3>
1437
- <p class="settings-desc">How often the background heartbeat runs. Default: 30 minutes.</p>
1448
+ <h3 class="settings-title" data-tooltip="How often Zubo checks for tasks">Background Check Interval</h3>
1449
+ <p class="settings-desc">How often Zubo checks for reminders, scheduled tasks, and updates. Default: every 30 minutes.</p>
1438
1450
  <div class="settings-grid">
1439
1451
  <div class="settings-field">
1440
- <label class="settings-label" data-tooltip="Minutes between heartbeats" for="settings-heartbeat">Interval (minutes)</label>
1452
+ <label class="settings-label" data-tooltip="Minutes between checks" for="settings-heartbeat">Interval (minutes)</label>
1441
1453
  <input id="settings-heartbeat" type="number" class="settings-input" min="1" max="1440" step="1" placeholder="30">
1442
1454
  </div>
1443
1455
  </div>
@@ -1456,8 +1468,8 @@ export const DASHBOARD_HTML = `<!DOCTYPE html>
1456
1468
  <!-- Providers Tab -->
1457
1469
  <div class="tab-content" id="settings-tab-providers">
1458
1470
  <div class="settings-section">
1459
- <h3 class="settings-title">LLM Providers</h3>
1460
- <p class="settings-desc">Configure AI model providers. Set one as active for immediate use.</p>
1471
+ <h3 class="settings-title">AI Providers</h3>
1472
+ <p class="settings-desc">Configure AI services. Set one as active for your agent to use.</p>
1461
1473
  <div id="providers-list" style="display:flex;flex-direction:column;gap:12px;"></div>
1462
1474
  <div style="margin-top:20px;">
1463
1475
  <button class="btn btn-primary" onclick="showAddProviderForm()">Add Provider</button>
@@ -1468,22 +1480,23 @@ export const DASHBOARD_HTML = `<!DOCTYPE html>
1468
1480
  <div class="settings-field">
1469
1481
  <label class="settings-label" for="new-provider-name">Provider</label>
1470
1482
  <select id="new-provider-name" class="settings-select" onchange="onNewProviderSelect()">
1471
- <option value="">-- Select --</option>
1472
- <option value="anthropic">Anthropic</option>
1473
- <option value="openai">OpenAI</option>
1474
- <option value="groq">Groq</option>
1475
- <option value="together">Together</option>
1476
- <option value="openrouter">OpenRouter</option>
1483
+ <option value="">-- Select a provider --</option>
1484
+ <option value="anthropic">Anthropic (Claude)</option>
1485
+ <option value="openai">OpenAI (GPT)</option>
1486
+ <option value="groq">Groq (fast, free tier)</option>
1487
+ <option value="together">Together AI</option>
1488
+ <option value="openrouter">OpenRouter (many models)</option>
1477
1489
  <option value="deepseek">DeepSeek</option>
1478
1490
  <option value="xai">xAI (Grok)</option>
1479
- <option value="ollama">Ollama (local)</option>
1480
- <option value="lmstudio">LM Studio (local)</option>
1481
- <option value="custom">Custom (OpenAI-compat)</option>
1491
+ <option value="ollama">Ollama (free, runs locally)</option>
1492
+ <option value="lmstudio">LM Studio (free, runs locally)</option>
1493
+ <option value="custom">Custom (advanced)</option>
1482
1494
  </select>
1483
1495
  </div>
1484
1496
  <div class="settings-field">
1485
1497
  <label class="settings-label" for="new-provider-key">API Key</label>
1486
1498
  <input id="new-provider-key" type="password" class="settings-input" placeholder="sk-...">
1499
+ <span id="provider-key-help" class="settings-hint" style="font-size:11px;color:var(--text-faint);margin-top:4px;display:none;"></span>
1487
1500
  </div>
1488
1501
  <div class="settings-field">
1489
1502
  <label class="settings-label" for="new-provider-model">Model</label>
@@ -1532,14 +1545,14 @@ export const DASHBOARD_HTML = `<!DOCTYPE html>
1532
1545
  <!-- MCP Tab -->
1533
1546
  <div class="tab-content" id="settings-tab-mcp">
1534
1547
  <div class="settings-section">
1535
- <h3 class="settings-title">MCP Servers</h3>
1536
- <p class="settings-desc">Model Context Protocol servers extend Zubo with additional tools. Changes apply immediately.</p>
1548
+ <h3 class="settings-title">Extensions</h3>
1549
+ <p class="settings-desc">Extensions give Zubo new abilities like accessing files, databases, and APIs. Install from the marketplace or add manually.</p>
1537
1550
  <div id="mcp-servers-list" style="display:flex;flex-direction:column;gap:12px;"></div>
1538
1551
  <div style="margin-top:20px;">
1539
- <button class="btn btn-primary" onclick="showAddMcpForm()">Add MCP Server</button>
1552
+ <button class="btn btn-primary" onclick="showAddMcpForm()">Add Extension</button>
1540
1553
  </div>
1541
1554
  <div id="mcp-add-form" style="display:none;margin-top:16px;padding:16px;background:var(--bg-surface);border:1px solid var(--border);border-radius:var(--radius);">
1542
- <h4 style="margin-bottom:12px;font-family:var(--display);font-weight:600;">Add MCP Server</h4>
1555
+ <h4 style="margin-bottom:12px;font-family:var(--display);font-weight:600;">Add Extension</h4>
1543
1556
  <div class="settings-grid">
1544
1557
  <div class="settings-field">
1545
1558
  <label class="settings-label" for="mcp-name">Name</label>
@@ -1570,8 +1583,8 @@ export const DASHBOARD_HTML = `<!DOCTYPE html>
1570
1583
  <!-- Routing Tab -->
1571
1584
  <div class="tab-content" id="settings-tab-routing">
1572
1585
  <div class="settings-section">
1573
- <h3 class="settings-title" data-tooltip="Route simple queries to a cheaper/faster model">Smart Routing</h3>
1574
- <p class="settings-desc">Automatically route simple queries to a fast, cheap model and complex ones to your primary model. Saves cost without sacrificing quality.</p>
1586
+ <h3 class="settings-title" data-tooltip="Use a cheaper AI for simple questions">Smart Cost Savings</h3>
1587
+ <p class="settings-desc">Use a cheaper, faster AI for simple questions and your main AI for complex ones. Saves money without sacrificing quality.</p>
1575
1588
  <div class="settings-grid">
1576
1589
  <div class="settings-field">
1577
1590
  <label class="settings-label" for="sr-enabled">Enabled</label>
@@ -1615,8 +1628,8 @@ export const DASHBOARD_HTML = `<!DOCTYPE html>
1615
1628
  <!-- Secrets Tab -->
1616
1629
  <div class="tab-content" id="settings-tab-secrets">
1617
1630
  <div class="settings-section" style="max-width:700px;">
1618
- <h3 class="settings-title">Secrets &amp; API Keys</h3>
1619
- <p class="settings-desc">Manage API keys and credentials for integrations. Values are stored encrypted in your local database and never sent to external services by Zubo.</p>
1631
+ <h3 class="settings-title">API Keys &amp; Credentials</h3>
1632
+ <p class="settings-desc">Manage API keys for integrations. Your keys are encrypted and stored securely on your device Zubo never sends them anywhere.</p>
1620
1633
  <div style="display:flex;gap:10px;margin-bottom:16px;flex-wrap:wrap;">
1621
1634
  <button class="btn btn-primary" onclick="showAddSecretForm()">Add Secret</button>
1622
1635
  <button class="btn btn-ghost" onclick="loadSecrets()">Refresh</button>
@@ -1648,6 +1661,7 @@ export const DASHBOARD_HTML = `<!DOCTYPE html>
1648
1661
 
1649
1662
  <!-- System Prompt Tab -->
1650
1663
  <div class="tab-content" id="settings-tab-system">
1664
+ <p class="settings-desc" style="margin-bottom:12px;">Customize your agent&#39;s personality and instructions. This controls how Zubo thinks and responds. Be careful — incorrect changes may cause errors.</p>
1651
1665
  <div class="editor-wrap" style="min-height:calc(100vh - 220px);">
1652
1666
  <div class="editor-toolbar">
1653
1667
  <button class="btn btn-primary" onclick="saveSystem()">Save</button>
@@ -1728,7 +1742,7 @@ export const DASHBOARD_HTML = `<!DOCTYPE html>
1728
1742
  <div class="cards" id="budget-summary-cards"></div>
1729
1743
  <div class="settings-section" style="margin-top:24px;">
1730
1744
  <h3 class="settings-title">Budget Limits</h3>
1731
- <p class="settings-desc">Set spending limits to control costs. The agent will pause when limits are reached.</p>
1745
+ <p class="settings-desc">Set spending limits to control costs. Zubo will stop responding when limits are reached — you can raise them anytime. Typical usage: ~100 messages/day costs $0.50–$2.00 depending on your AI model.</p>
1732
1746
  <div class="settings-grid">
1733
1747
  <div class="settings-field">
1734
1748
  <label class="settings-label" for="budget-daily">Daily Limit (USD)</label>
@@ -1907,7 +1921,7 @@ export const DASHBOARD_HTML = `<!DOCTYPE html>
1907
1921
  <script>
1908
1922
  // --- Panel routing ---
1909
1923
  var panelNames = ['agent','history','dashboard','memory','skills','workflows','webhooks','mcp','integrations','settings'];
1910
- var panelTitles = { agent:'Chat', history:'History', dashboard:'Dashboard', memory:'Memory', skills:'Skills', workflows:'Workflows', webhooks:'Webhooks', mcp:'MCP', integrations:'Integrations', settings:'Settings' };
1924
+ var panelTitles = { agent:'Chat', history:'History', dashboard:'Dashboard', memory:'Knowledge', skills:'Skills', workflows:'Workflows', webhooks:'Webhooks', mcp:'Extensions', integrations:'Integrations', settings:'Settings' };
1911
1925
 
1912
1926
  // Legacy panel name mapping (old names -> new names + tab)
1913
1927
  var legacyPanelMap = {
@@ -3790,10 +3804,28 @@ function onNewProviderSelect() {
3790
3804
  document.getElementById('new-provider-url-field').style.display = showUrl ? '' : 'none';
3791
3805
  // Local providers don't need API key
3792
3806
  var keyInput = document.getElementById('new-provider-key');
3807
+ var helpEl = document.getElementById('provider-key-help');
3793
3808
  if (name === 'ollama' || name === 'lmstudio') {
3794
- keyInput.placeholder = 'Optional for local providers';
3809
+ keyInput.placeholder = 'Not needed for local models';
3810
+ helpEl.style.display = 'none';
3795
3811
  } else {
3796
3812
  keyInput.placeholder = 'sk-...';
3813
+ // Show where to get the API key
3814
+ var keyLinks = {
3815
+ anthropic: 'console.anthropic.com/settings/keys',
3816
+ openai: 'platform.openai.com/api-keys',
3817
+ groq: 'console.groq.com/keys',
3818
+ together: 'api.together.xyz/settings/api-keys',
3819
+ openrouter: 'openrouter.ai/keys',
3820
+ deepseek: 'platform.deepseek.com/api_keys',
3821
+ xai: 'console.x.ai'
3822
+ };
3823
+ if (keyLinks[name]) {
3824
+ helpEl.textContent = 'Get your key at ' + keyLinks[name];
3825
+ helpEl.style.display = 'block';
3826
+ } else {
3827
+ helpEl.style.display = 'none';
3828
+ }
3797
3829
  }
3798
3830
  }
3799
3831
 
@@ -3857,7 +3889,7 @@ function loadMcpServers() {
3857
3889
  if (!servers.length) {
3858
3890
  var empty = document.createElement('div');
3859
3891
  empty.className = 'empty-state';
3860
- empty.textContent = 'No MCP servers configured. Add one to extend Zubo with new tools.';
3892
+ empty.textContent = 'No extensions configured. Add one to extend Zubo with new tools.';
3861
3893
  list.appendChild(empty);
3862
3894
  return;
3863
3895
  }
@@ -3921,7 +3953,7 @@ function restartMcpServer(name) {
3921
3953
  }
3922
3954
 
3923
3955
  function removeMcpServer(name) {
3924
- if (!confirm('Remove MCP server "' + name + '"? This will disconnect it.')) return;
3956
+ if (!confirm('Remove extension "' + name + '"? This will disconnect it.')) return;
3925
3957
  api('/mcp/servers/' + encodeURIComponent(name), { method: 'DELETE' }).then(function(data) {
3926
3958
  if (data.ok) {
3927
3959
  toast(name + ' removed');
@@ -4363,19 +4395,19 @@ function renderCmdResults(query) {
4363
4395
  var subTabs = [
4364
4396
  { title: 'Analytics', action: function() { showPanel('dashboard'); switchTab('dashboard','analytics'); } },
4365
4397
  { title: 'Performance', action: function() { showPanel('dashboard'); switchTab('dashboard','performance'); } },
4366
- { title: 'System Prompt', action: function() { showPanel('settings'); switchTab('settings','system'); } },
4367
- { title: 'Cron Jobs', action: function() { showPanel('settings'); switchTab('settings','cron'); } },
4398
+ { title: 'Personality', action: function() { showPanel('settings'); switchTab('settings','system'); } },
4399
+ { title: 'Scheduled Tasks', action: function() { showPanel('settings'); switchTab('settings','cron'); } },
4368
4400
  { title: 'Logs', action: function() { showPanel('settings'); switchTab('settings','logs'); } },
4369
4401
  { title: 'Privacy & Data', action: function() { showPanel('settings'); switchTab('settings','privacy'); } },
4370
4402
  { title: 'Budget', action: function() { showPanel('settings'); switchTab('settings','budget'); } },
4371
- { title: 'Secrets', action: function() { showPanel('settings'); switchTab('settings','secrets'); } },
4403
+ { title: 'API Keys', action: function() { showPanel('settings'); switchTab('settings','secrets'); } },
4372
4404
  { title: 'Channels', action: function() { showPanel('settings'); switchTab('settings','channels'); } },
4373
4405
  { title: 'Providers', action: function() { showPanel('settings'); switchTab('settings','providers'); } },
4374
- { title: 'MCP Servers', action: function() { showPanel('settings'); switchTab('settings','mcp'); } },
4375
- { title: 'Smart Routing', action: function() { showPanel('settings'); switchTab('settings','routing'); } },
4406
+ { title: 'Extensions', action: function() { showPanel('settings'); switchTab('settings','mcp'); } },
4407
+ { title: 'Cost Savings', action: function() { showPanel('settings'); switchTab('settings','routing'); } },
4376
4408
  { title: 'Browse Registry', action: function() { showPanel('skills'); switchTab('skills','browse'); } },
4377
4409
  { title: 'Visual Builder', action: function() { showPanel('workflows'); switchTab('workflows','visual'); } },
4378
- { title: 'MCP Marketplace', action: function() { showPanel('mcp'); switchTab('mcp','marketplace'); } },
4410
+ { title: 'Extensions Marketplace', action: function() { showPanel('mcp'); switchTab('mcp','marketplace'); } },
4379
4411
  { title: 'Email Digests', action: function() { showPanel('settings'); switchTab('settings','digests'); } },
4380
4412
  ];
4381
4413
  subTabs.forEach(function(st) { items.push({ name: st.title.toLowerCase(), title: st.title, action: st.action }); });
@@ -4516,7 +4548,7 @@ function clearChatMessages() {
4516
4548
  subtext.textContent = 'Ask me anything, or try a suggestion below';
4517
4549
  var chipsGroup = document.createElement('div');
4518
4550
  chipsGroup.className = 'suggestion-chips-group';
4519
- var rows = [['What can you do?','Check my schedule'],['Summarize recent emails','Set a reminder']];
4551
+ var rows = [['What can you do?','Set a reminder for tomorrow'],['Help me write an email','Explain something to me']];
4520
4552
  rows.forEach(function(rowLabels) {
4521
4553
  var row = document.createElement('div');
4522
4554
  row.className = 'chip-row';
@@ -18,22 +18,22 @@ function escapeHtml(s: string): string {
18
18
  }
19
19
 
20
20
  /** Convert raw error messages to user-friendly messages. Prevents leaking internal details. */
21
- function friendlyError(err: any): string {
22
- const msg = err?.message ?? String(err);
23
- if (msg.includes("401") || msg.includes("Unauthorized") || msg.includes("invalid"))
24
- return "API authentication failed. Check your API key in the dashboard settings.";
25
- if (msg.includes("429") || msg.includes("rate limit"))
26
- return "Rate limit reached. Please wait a moment and try again.";
27
- if (msg.includes("404") || msg.includes("not found"))
28
- return "Model not found. Check your model name in settings.";
29
- if (msg.includes("ECONNREFUSED") || msg.includes("fetch failed") || msg.includes("Connection refused"))
30
- return "Cannot reach the AI provider. Make sure the server is running.";
31
- if (msg.includes("timed out") || msg.includes("timeout"))
32
- return "Request timed out. The AI provider may be overloaded — try again.";
33
- if (msg.includes("context") || msg.includes("too long"))
34
- return "Message too long for the model's context window. Try a shorter message.";
35
- return "Something went wrong. Check the logs for details.";
36
- }
21
+ function friendlyError(err: any): string {
22
+ const msg = err?.message ?? String(err);
23
+ if (msg.includes("401") || msg.includes("Unauthorized") || msg.includes("invalid"))
24
+ return "Authentication failed. Check your API key in Settings > API Keys.";
25
+ if (msg.includes("429") || msg.includes("rate limit"))
26
+ return "Too many messages too quickly. Wait a moment and try again.";
27
+ if (msg.includes("404") || msg.includes("not found"))
28
+ return "The AI model wasn't found. Check your model name in Settings > AI Model.";
29
+ if (msg.includes("ECONNREFUSED") || msg.includes("fetch failed") || msg.includes("Connection refused"))
30
+ return "Can't reach the AI service. Check your internet connection or try again.";
31
+ if (msg.includes("timed out") || msg.includes("timeout"))
32
+ return "The request took too long. The AI service may be busy — try again in a moment.";
33
+ if (msg.includes("context") || msg.includes("too long"))
34
+ return "Your message is too long. Try splitting it into shorter questions.";
35
+ return "Something went wrong. Try again, or check Settings if this keeps happening.";
36
+ }
37
37
 
38
38
  /** Add security headers to all HTTP responses */
39
39
  function addSecurityHeaders(res: Response): Response {
@@ -11,7 +11,7 @@ export class ClaudeCodeProvider implements LlmProvider {
11
11
  model: string;
12
12
  contextWindow = 200_000;
13
13
 
14
- constructor(model: string = "claude-sonnet-4-5-20250929") {
14
+ constructor(model: string = "default") {
15
15
  this.model = model;
16
16
  }
17
17
 
@@ -55,7 +55,6 @@ export class ClaudeCodeProvider implements LlmProvider {
55
55
  const prompt = parts.join("\n\n");
56
56
 
57
57
  const args = ["claude", "-p", prompt, "--output-format", "json"];
58
- if (this.model) args.push("--model", this.model);
59
58
 
60
59
  try {
61
60
  const proc = Bun.spawn(args, {
package/src/llm/codex.ts CHANGED
@@ -11,7 +11,7 @@ export class CodexProvider implements LlmProvider {
11
11
  model: string;
12
12
  contextWindow = 200_000;
13
13
 
14
- constructor(model: string = "o4-mini") {
14
+ constructor(model: string = "default") {
15
15
  this.model = model;
16
16
  }
17
17
 
@@ -52,7 +52,6 @@ export class CodexProvider implements LlmProvider {
52
52
  const prompt = parts.join("\n\n");
53
53
 
54
54
  const args = ["codex", "exec"];
55
- if (this.model) args.push("--model", this.model);
56
55
  args.push(prompt);
57
56
 
58
57
  try {
@@ -588,10 +588,10 @@ export const SETUP_WIZARD_HTML = `<!DOCTYPE html>
588
588
  </div>
589
589
 
590
590
  <div class="stepper" id="stepper">
591
- <div class="stepper-item active" data-step="1"><div class="stepper-dot">1</div><span>Provider</span></div>
591
+ <div class="stepper-item active" data-step="1"><div class="stepper-dot">1</div><span>AI Provider</span></div>
592
592
  <div class="stepper-item" data-step="2"><div class="stepper-dot">2</div><span>Channels</span></div>
593
- <div class="stepper-item" data-step="3"><div class="stepper-dot">3</div><span>Agent</span></div>
594
- <div class="stepper-item" data-step="4"><div class="stepper-dot">4</div><span>Routing</span></div>
593
+ <div class="stepper-item" data-step="3"><div class="stepper-dot">3</div><span>Personalize</span></div>
594
+ <div class="stepper-item" data-step="4"><div class="stepper-dot">4</div><span>Cost Savings</span></div>
595
595
  </div>
596
596
 
597
597
  <div class="step-panel" id="stepPanel">
@@ -725,8 +725,8 @@ function prevStep() {
725
725
 
726
726
  // ── Step 1: Provider ──
727
727
  function renderProvider() {
728
- var html = '<h3 class="step-title">LLM Provider</h3>';
729
- html += '<p class="step-desc">Choose the AI provider that powers your agent.</p>';
728
+ var html = '<h3 class="step-title">AI Provider</h3>';
729
+ html += '<p class="step-desc">Choose the AI service that powers your agent.</p>';
730
730
  html += '<div class="provider-grid">';
731
731
  PROVIDERS.forEach(function(p) {
732
732
  html += '<div class="provider-card' + (state.activeProvider === p.id ? ' selected' : '') + '" data-pid="' + p.id + '">';
@@ -978,7 +978,7 @@ function collectProviderData() {
978
978
  if (!p) return;
979
979
 
980
980
  if (p.cli) {
981
- var model = p.id === 'claude-code' ? 'claude-sonnet-4-5-20250929' : 'o4-mini';
981
+ var model = 'default';
982
982
  state.providers[p.id] = { model: model };
983
983
  } else if (p.local) {
984
984
  var m = document.getElementById('model')?.value || p.defaultModel;
@@ -1006,7 +1006,7 @@ function collectProviderData() {
1006
1006
  var fb = PROVIDERS.find(function(x) { return x.id === state.fallbackProvider; });
1007
1007
  if (fb) {
1008
1008
  if (fb.cli) {
1009
- var fbm = fb.id === 'claude-code' ? 'claude-sonnet-4-5-20250929' : 'o4-mini';
1009
+ var fbm = 'default';
1010
1010
  state.providers[fb.id] = { model: fbm };
1011
1011
  } else if (fb.local) {
1012
1012
  var fbModel = document.getElementById('fb_model')?.value || fb.defaultModel;
@@ -1149,9 +1149,9 @@ function collectAgentData() {
1149
1149
 
1150
1150
  // ── Step 4: Smart Routing ──
1151
1151
  function renderRouting() {
1152
- var html = '<h3 class="step-title">Smart Routing</h3>';
1152
+ var html = '<h3 class="step-title">Smart Cost Savings</h3>';
1153
1153
  html += '<div class="routing-card">';
1154
- html += '<p>Smart routing sends simple queries (greetings, one-liners) to a fast, cheap model \\u{2014} and uses your main provider for complex tasks. This can save 50-80% on API costs.</p>';
1154
+ html += '<p>Use a cheaper, faster AI for simple questions (greetings, one-liners) and your main AI for complex tasks. This can save 50-80% on costs.</p>';
1155
1155
 
1156
1156
  var hasSecondProvider = state.failover.length > 0;
1157
1157
 
package/src/setup.ts CHANGED
@@ -350,12 +350,12 @@ const PROVIDER_OPTIONS: ProviderOption[] = [
350
350
  console.log(` ${DIM}npm install -g @anthropic-ai/claude-code${RESET}\n`);
351
351
  const cont = await prompt(" Press Enter after installing, or 'skip' to continue anyway: ");
352
352
  if (cont.toLowerCase() === "skip") {
353
- return { name: "claude-code", config: { model: "claude-sonnet-4-5-20250929" } };
353
+ return { name: "claude-code", config: { model: "default" } };
354
354
  }
355
355
  const recheck = Bun.spawnSync(["which", "claude"], { stdout: "pipe", stderr: "pipe" });
356
356
  if (recheck.exitCode !== 0) {
357
357
  warn("Still not found. Config saved — install 'claude' CLI before starting.");
358
- return { name: "claude-code", config: { model: "claude-sonnet-4-5-20250929" } };
358
+ return { name: "claude-code", config: { model: "default" } };
359
359
  }
360
360
  }
361
361
  ok("'claude' CLI found");
@@ -380,7 +380,7 @@ const PROVIDER_OPTIONS: ProviderOption[] = [
380
380
  warn("Still not authenticated. Run 'claude' in a terminal to log in before starting Zubo.");
381
381
  }
382
382
  }
383
- return { name: "claude-code", config: { model: "claude-sonnet-4-5-20250929" } };
383
+ return { name: "claude-code", config: { model: "default" } };
384
384
  },
385
385
  },
386
386
  {
@@ -394,12 +394,12 @@ const PROVIDER_OPTIONS: ProviderOption[] = [
394
394
  console.log(` ${DIM}npm install -g @openai/codex${RESET}\n`);
395
395
  const cont = await prompt(" Press Enter after installing, or 'skip' to continue anyway: ");
396
396
  if (cont.toLowerCase() === "skip") {
397
- return { name: "codex", config: { model: "o4-mini" } };
397
+ return { name: "codex", config: { model: "default" } };
398
398
  }
399
399
  const recheck = Bun.spawnSync(["which", "codex"], { stdout: "pipe", stderr: "pipe" });
400
400
  if (recheck.exitCode !== 0) {
401
401
  warn("Still not found. Config saved — install 'codex' CLI before starting.");
402
- return { name: "codex", config: { model: "o4-mini" } };
402
+ return { name: "codex", config: { model: "default" } };
403
403
  }
404
404
  }
405
405
  ok("'codex' CLI found");
@@ -412,7 +412,7 @@ const PROVIDER_OPTIONS: ProviderOption[] = [
412
412
  } else {
413
413
  ok("Codex ready");
414
414
  }
415
- return { name: "codex", config: { model: "o4-mini" } };
415
+ return { name: "codex", config: { model: "default" } };
416
416
  },
417
417
  },
418
418
  {
@@ -121,7 +121,7 @@ export async function executeTool(
121
121
  logger.warn(`Tool blocked by allowedTools: ${name}`);
122
122
  return {
123
123
  tool_use_id: toolUseId,
124
- content: `Error: Tool '${name}' is not available in this agent context.`,
124
+ content: `Error: The '${name}' feature is not available right now.`,
125
125
  is_error: true,
126
126
  };
127
127
  }
@@ -141,7 +141,7 @@ export async function executeTool(
141
141
  logger.warn(`Tool denied: ${name}`);
142
142
  return {
143
143
  tool_use_id: toolUseId,
144
- content: `Error: Tool '${name}' is not permitted.`,
144
+ content: `Error: The '${name}' feature is not permitted. You can change permissions in Settings.`,
145
145
  is_error: true,
146
146
  };
147
147
  }
@@ -46,7 +46,7 @@ export async function searchRegistry(
46
46
  if (cached) return cached;
47
47
 
48
48
  try {
49
- const url = `${BASE_URL}/servers?q=${encodeURIComponent(query)}&limit=${limit}`;
49
+ const url = `${BASE_URL}/servers?search=${encodeURIComponent(query)}&limit=${limit}`;
50
50
  const res = await fetch(url);
51
51
  if (!res.ok) {
52
52
  logger.warn(`MCP registry search failed: ${res.status} ${res.statusText}`);