zubo 0.1.0

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.
Files changed (222) hide show
  1. package/.github/workflows/ci.yml +35 -0
  2. package/README.md +149 -0
  3. package/bun.lock +216 -0
  4. package/desktop/README.md +57 -0
  5. package/desktop/package.json +12 -0
  6. package/desktop/src-tauri/Cargo.toml +25 -0
  7. package/desktop/src-tauri/build.rs +3 -0
  8. package/desktop/src-tauri/icons/README.md +17 -0
  9. package/desktop/src-tauri/icons/icon.png +0 -0
  10. package/desktop/src-tauri/src/main.rs +189 -0
  11. package/desktop/src-tauri/tauri.conf.json +68 -0
  12. package/docs/ROADMAP.md +490 -0
  13. package/migrations/001_init.sql +9 -0
  14. package/migrations/002_memory.sql +33 -0
  15. package/migrations/003_cron.sql +24 -0
  16. package/migrations/004_usage.sql +12 -0
  17. package/migrations/005_secrets.sql +8 -0
  18. package/migrations/006_agents.sql +1 -0
  19. package/migrations/007_workflows.sql +22 -0
  20. package/migrations/008_proactive.sql +24 -0
  21. package/migrations/009_uploads.sql +9 -0
  22. package/migrations/010_observability.sql +22 -0
  23. package/migrations/011_api_keys.sql +7 -0
  24. package/migrations/012_indexes.sql +5 -0
  25. package/migrations/013_budget.sql +11 -0
  26. package/migrations/014_usage_session_idx.sql +2 -0
  27. package/package.json +39 -0
  28. package/site/404.html +156 -0
  29. package/site/CNAME +1 -0
  30. package/site/docs/agents.html +294 -0
  31. package/site/docs/api.html +446 -0
  32. package/site/docs/channels.html +345 -0
  33. package/site/docs/cli.html +238 -0
  34. package/site/docs/config.html +1034 -0
  35. package/site/docs/index.html +433 -0
  36. package/site/docs/integrations.html +381 -0
  37. package/site/docs/memory.html +254 -0
  38. package/site/docs/security.html +375 -0
  39. package/site/docs/skills.html +322 -0
  40. package/site/docs.css +412 -0
  41. package/site/index.html +638 -0
  42. package/site/install.sh +98 -0
  43. package/site/logo.svg +1 -0
  44. package/site/og-image.png +0 -0
  45. package/site/robots.txt +4 -0
  46. package/site/script.js +361 -0
  47. package/site/sitemap.xml +63 -0
  48. package/site/skills.html +532 -0
  49. package/site/style.css +1686 -0
  50. package/src/agent/agents.ts +159 -0
  51. package/src/agent/compaction.ts +53 -0
  52. package/src/agent/context.ts +18 -0
  53. package/src/agent/delegate.ts +118 -0
  54. package/src/agent/loop.ts +318 -0
  55. package/src/agent/prompts.ts +111 -0
  56. package/src/agent/session.ts +87 -0
  57. package/src/agent/teams.ts +116 -0
  58. package/src/agent/workflow-executor.ts +192 -0
  59. package/src/agent/workflow.ts +175 -0
  60. package/src/channels/adapter.ts +21 -0
  61. package/src/channels/dashboard.html.ts +2969 -0
  62. package/src/channels/discord.ts +137 -0
  63. package/src/channels/optional-deps.d.ts +17 -0
  64. package/src/channels/router.ts +199 -0
  65. package/src/channels/signal.ts +133 -0
  66. package/src/channels/slack.ts +101 -0
  67. package/src/channels/telegram.ts +102 -0
  68. package/src/channels/utils.ts +18 -0
  69. package/src/channels/webchat.ts +1797 -0
  70. package/src/channels/whatsapp.ts +119 -0
  71. package/src/config/loader.ts +22 -0
  72. package/src/config/paths.ts +43 -0
  73. package/src/config/schema.ts +121 -0
  74. package/src/db/connection.ts +20 -0
  75. package/src/db/export.ts +148 -0
  76. package/src/db/migrations.ts +42 -0
  77. package/src/index.ts +261 -0
  78. package/src/llm/claude.ts +193 -0
  79. package/src/llm/factory.ts +115 -0
  80. package/src/llm/failover.ts +101 -0
  81. package/src/llm/openai-compat.ts +409 -0
  82. package/src/llm/provider.ts +83 -0
  83. package/src/llm/smart-router.ts +241 -0
  84. package/src/logs.ts +53 -0
  85. package/src/memory/chunker.ts +58 -0
  86. package/src/memory/document-parser.ts +115 -0
  87. package/src/memory/embedder.ts +235 -0
  88. package/src/memory/engine.ts +170 -0
  89. package/src/memory/fts-index.ts +55 -0
  90. package/src/memory/hybrid-search.ts +72 -0
  91. package/src/memory/store.ts +56 -0
  92. package/src/memory/vector-index.ts +72 -0
  93. package/src/model.ts +118 -0
  94. package/src/registry/cli.ts +43 -0
  95. package/src/registry/client.ts +54 -0
  96. package/src/registry/installer.ts +67 -0
  97. package/src/scheduler/briefing.ts +71 -0
  98. package/src/scheduler/cron.ts +258 -0
  99. package/src/scheduler/heartbeat.ts +58 -0
  100. package/src/scheduler/memory-triggers.ts +100 -0
  101. package/src/scheduler/natural-cron.ts +163 -0
  102. package/src/scheduler/proactive.ts +25 -0
  103. package/src/scheduler/recipes.ts +110 -0
  104. package/src/secrets/store.ts +64 -0
  105. package/src/setup.ts +413 -0
  106. package/src/skills.ts +293 -0
  107. package/src/start.ts +373 -0
  108. package/src/status.ts +165 -0
  109. package/src/tools/builtin/connect-service.ts +205 -0
  110. package/src/tools/builtin/cron.ts +126 -0
  111. package/src/tools/builtin/datetime.ts +36 -0
  112. package/src/tools/builtin/delegate-task.ts +81 -0
  113. package/src/tools/builtin/delegate.ts +42 -0
  114. package/src/tools/builtin/diagnose.ts +41 -0
  115. package/src/tools/builtin/google-oauth.ts +379 -0
  116. package/src/tools/builtin/manage-agents.ts +149 -0
  117. package/src/tools/builtin/manage-skills.ts +294 -0
  118. package/src/tools/builtin/manage-teams.ts +89 -0
  119. package/src/tools/builtin/manage-triggers.ts +94 -0
  120. package/src/tools/builtin/manage-workflows.ts +119 -0
  121. package/src/tools/builtin/memory-search.ts +38 -0
  122. package/src/tools/builtin/memory-write.ts +30 -0
  123. package/src/tools/builtin/run-workflow.ts +36 -0
  124. package/src/tools/builtin/secrets.ts +122 -0
  125. package/src/tools/builtin/skill-registry.ts +75 -0
  126. package/src/tools/builtin-integrations/api-helpers.ts +26 -0
  127. package/src/tools/builtin-integrations/github/github_issues/SKILL.md +56 -0
  128. package/src/tools/builtin-integrations/github/github_issues/handler.ts +108 -0
  129. package/src/tools/builtin-integrations/github/github_prs/SKILL.md +57 -0
  130. package/src/tools/builtin-integrations/github/github_prs/handler.ts +113 -0
  131. package/src/tools/builtin-integrations/github/github_repos/SKILL.md +37 -0
  132. package/src/tools/builtin-integrations/github/github_repos/handler.ts +88 -0
  133. package/src/tools/builtin-integrations/google/gmail/SKILL.md +51 -0
  134. package/src/tools/builtin-integrations/google/gmail/handler.ts +125 -0
  135. package/src/tools/builtin-integrations/google/google_calendar/SKILL.md +35 -0
  136. package/src/tools/builtin-integrations/google/google_calendar/handler.ts +105 -0
  137. package/src/tools/builtin-integrations/google/google_docs/SKILL.md +35 -0
  138. package/src/tools/builtin-integrations/google/google_docs/handler.ts +108 -0
  139. package/src/tools/builtin-integrations/google/google_drive/SKILL.md +39 -0
  140. package/src/tools/builtin-integrations/google/google_drive/handler.ts +106 -0
  141. package/src/tools/builtin-integrations/google/google_sheets/SKILL.md +36 -0
  142. package/src/tools/builtin-integrations/google/google_sheets/handler.ts +116 -0
  143. package/src/tools/builtin-integrations/jira/jira_boards/SKILL.md +21 -0
  144. package/src/tools/builtin-integrations/jira/jira_boards/handler.ts +74 -0
  145. package/src/tools/builtin-integrations/jira/jira_issues/SKILL.md +28 -0
  146. package/src/tools/builtin-integrations/jira/jira_issues/handler.ts +140 -0
  147. package/src/tools/builtin-integrations/linear/linear_issues/SKILL.md +30 -0
  148. package/src/tools/builtin-integrations/linear/linear_issues/handler.ts +75 -0
  149. package/src/tools/builtin-integrations/linear/linear_projects/SKILL.md +21 -0
  150. package/src/tools/builtin-integrations/linear/linear_projects/handler.ts +43 -0
  151. package/src/tools/builtin-integrations/notion/notion_databases/SKILL.md +39 -0
  152. package/src/tools/builtin-integrations/notion/notion_databases/handler.ts +83 -0
  153. package/src/tools/builtin-integrations/notion/notion_pages/SKILL.md +43 -0
  154. package/src/tools/builtin-integrations/notion/notion_pages/handler.ts +130 -0
  155. package/src/tools/builtin-integrations/notion/notion_search/SKILL.md +27 -0
  156. package/src/tools/builtin-integrations/notion/notion_search/handler.ts +69 -0
  157. package/src/tools/builtin-integrations/slack/slack_messages/SKILL.md +42 -0
  158. package/src/tools/builtin-integrations/slack/slack_messages/handler.ts +72 -0
  159. package/src/tools/builtin-integrations/twitter/twitter_posts/SKILL.md +24 -0
  160. package/src/tools/builtin-integrations/twitter/twitter_posts/handler.ts +133 -0
  161. package/src/tools/builtin-skills/file-read/SKILL.md +26 -0
  162. package/src/tools/builtin-skills/file-read/handler.ts +66 -0
  163. package/src/tools/builtin-skills/file-write/SKILL.md +30 -0
  164. package/src/tools/builtin-skills/file-write/handler.ts +64 -0
  165. package/src/tools/builtin-skills/http-request/SKILL.md +34 -0
  166. package/src/tools/builtin-skills/http-request/handler.ts +87 -0
  167. package/src/tools/builtin-skills/shell/SKILL.md +26 -0
  168. package/src/tools/builtin-skills/shell/handler.ts +96 -0
  169. package/src/tools/builtin-skills/url-fetch/SKILL.md +26 -0
  170. package/src/tools/builtin-skills/url-fetch/handler.ts +37 -0
  171. package/src/tools/builtin-skills/web-search/SKILL.md +26 -0
  172. package/src/tools/builtin-skills/web-search/handler.ts +50 -0
  173. package/src/tools/executor.ts +205 -0
  174. package/src/tools/integration-installer.ts +106 -0
  175. package/src/tools/permissions.ts +45 -0
  176. package/src/tools/registry.ts +39 -0
  177. package/src/tools/sandbox-runner.ts +56 -0
  178. package/src/tools/sandbox.ts +82 -0
  179. package/src/tools/skill-installer.ts +52 -0
  180. package/src/tools/skill-loader.ts +259 -0
  181. package/src/types/optional-deps.d.ts +23 -0
  182. package/src/util/auth.ts +121 -0
  183. package/src/util/costs.ts +59 -0
  184. package/src/util/error-buffer.ts +32 -0
  185. package/src/util/google-tokens.ts +180 -0
  186. package/src/util/logger.ts +73 -0
  187. package/src/util/perf-collector.ts +35 -0
  188. package/src/util/rate-limiter.ts +70 -0
  189. package/src/util/tokens.ts +17 -0
  190. package/src/voice/stt.ts +57 -0
  191. package/src/voice/tts.ts +103 -0
  192. package/tests/agent/session.test.ts +109 -0
  193. package/tests/agent-loop.test.ts +54 -0
  194. package/tests/auth.test.ts +89 -0
  195. package/tests/channels.test.ts +67 -0
  196. package/tests/compaction.test.ts +44 -0
  197. package/tests/config.test.ts +51 -0
  198. package/tests/costs.test.ts +19 -0
  199. package/tests/cron.test.ts +55 -0
  200. package/tests/db/export.test.ts +219 -0
  201. package/tests/executor.test.ts +144 -0
  202. package/tests/export.test.ts +137 -0
  203. package/tests/helpers/mock-llm.ts +34 -0
  204. package/tests/helpers/test-db.ts +74 -0
  205. package/tests/integration/chat-flow.test.ts +48 -0
  206. package/tests/integrations.test.ts +97 -0
  207. package/tests/memory/engine.test.ts +114 -0
  208. package/tests/memory-engine.test.ts +57 -0
  209. package/tests/permissions.test.ts +21 -0
  210. package/tests/rate-limiter.test.ts +70 -0
  211. package/tests/registry.test.ts +67 -0
  212. package/tests/router.test.ts +36 -0
  213. package/tests/session.test.ts +58 -0
  214. package/tests/skill-loader.test.ts +44 -0
  215. package/tests/tokens.test.ts +30 -0
  216. package/tests/tools/executor.test.ts +130 -0
  217. package/tests/util/auth.test.ts +75 -0
  218. package/tests/util/rate-limiter.test.ts +73 -0
  219. package/tests/voice.test.ts +60 -0
  220. package/tests/webchat.test.ts +88 -0
  221. package/tests/workflow.test.ts +38 -0
  222. package/tsconfig.json +16 -0
@@ -0,0 +1,1034 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Configuration — Zubo Docs</title>
7
+ <meta name="description" content="Complete configuration reference for Zubo: LLM providers, channels, voice, rate limiting, authentication, sandbox settings, and full annotated example.">
8
+ <meta name="theme-color" content="#060608">
9
+ <link rel="canonical" href="https://zubo.bot/docs/config.html">
10
+ <meta property="og:title" content="Configuration — Zubo Docs">
11
+ <meta property="og:description" content="Complete configuration reference for Zubo: LLM providers, channels, voice, rate limiting, authentication, and sandbox settings.">
12
+ <meta property="og:type" content="article">
13
+ <meta property="og:url" content="https://zubo.bot/docs/config.html">
14
+ <meta property="og:image" content="https://zubo.bot/og-image.png">
15
+ <meta property="og:site_name" content="Zubo">
16
+ <meta name="twitter:card" content="summary_large_image">
17
+ <meta name="twitter:title" content="Configuration — Zubo Docs">
18
+ <meta name="twitter:description" content="Complete configuration reference for Zubo: LLM providers, channels, voice, rate limiting, and authentication.">
19
+ <meta name="twitter:image" content="https://zubo.bot/og-image.png">
20
+ <meta name="twitter:creator" content="@thomaskanze">
21
+ <link rel="preconnect" href="https://fonts.googleapis.com">
22
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
23
+ <link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,600;12..96,700;12..96,800&family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,400&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
24
+ <link rel="stylesheet" href="../style.css">
25
+ <link rel="stylesheet" href="../docs.css">
26
+ <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><rect width='100' height='100' rx='20' fill='%237c3aed'/><path d='M50 15C52 37 63 48 85 50C63 52 52 63 50 85C48 63 37 52 15 50C37 48 48 37 50 15Z' fill='white'/></svg>">
27
+ </head>
28
+ <body>
29
+ <header class="nav scrolled" id="nav">
30
+ <div class="nav-inner">
31
+ <a href="../index.html" class="nav-logo"><span class="logo-wordmark">zubo</span></a>
32
+ <nav class="nav-links" id="nav-links">
33
+ <a href="../index.html#features">Features</a>
34
+ <a href="index.html" style="color:#fff;">Docs</a>
35
+ <a href="../skills.html">Skills</a>
36
+ <a href="../index.html#get-started">Get Started</a>
37
+ </nav>
38
+ <div class="nav-right">
39
+ <a href="https://github.com/apwn/zubo" class="nav-github" aria-label="GitHub">
40
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
41
+ </a>
42
+ <a href="../index.html#get-started" class="btn btn-primary btn-nav">Get Started</a>
43
+ <button class="nav-toggle" id="nav-toggle" aria-label="Toggle menu"><span></span><span></span><span></span></button>
44
+ </div>
45
+ </div>
46
+ </header>
47
+
48
+ <div class="docs-layout">
49
+ <aside class="docs-sidebar" id="docs-sidebar">
50
+ <div class="docs-sidebar-section">
51
+ <div class="docs-sidebar-heading">Getting Started</div>
52
+ <div class="docs-sidebar-links">
53
+ <a href="index.html">Overview</a>
54
+ <a href="config.html" class="active">Configuration</a>
55
+ </div>
56
+ </div>
57
+ <div class="docs-sidebar-section">
58
+ <div class="docs-sidebar-heading">Core Concepts</div>
59
+ <div class="docs-sidebar-links">
60
+ <a href="agents.html">Agents &amp; Workflows</a>
61
+ <a href="memory.html">Memory System</a>
62
+ <a href="skills.html">Skills</a>
63
+ </div>
64
+ </div>
65
+ <div class="docs-sidebar-section">
66
+ <div class="docs-sidebar-heading">Guides</div>
67
+ <div class="docs-sidebar-links">
68
+ <a href="channels.html">Channel Setup</a>
69
+ <a href="integrations.html">Integrations</a>
70
+ <a href="security.html">Security &amp; Auth</a>
71
+ </div>
72
+ </div>
73
+ <div class="docs-sidebar-section">
74
+ <div class="docs-sidebar-heading">Reference</div>
75
+ <div class="docs-sidebar-links">
76
+ <a href="api.html">API Reference</a>
77
+ <a href="cli.html">CLI Commands</a>
78
+ </div>
79
+ </div>
80
+ </aside>
81
+ <main class="docs-content">
82
+
83
+ <div class="docs-breadcrumb">
84
+ <a href="../index.html">Home</a> <span>/</span> <a href="index.html">Docs</a> <span>/</span> <span>Configuration</span>
85
+ </div>
86
+
87
+ <h1>Configuration</h1>
88
+
89
+ <p>
90
+ All Zubo configuration lives in a single file: <code>~/.zubo/config.json</code>. You can edit this file directly with any text editor, or use the <code>zubo config</code> CLI commands for quick changes without opening a file. Changes to the configuration file are picked up on the next restart, while CLI changes via <code>zubo config set</code> take effect immediately if Zubo is running.
91
+ </p>
92
+
93
+ <!-- ================================================================ -->
94
+ <h2 id="quick-config-via-cli">Quick Config via CLI</h2>
95
+
96
+ <p>The <code>zubo config</code> command provides a convenient way to read and write configuration values from the terminal:</p>
97
+
98
+ <pre><code># Set values
99
+ zubo config set activeProvider ollama
100
+ zubo config set model llama3.3
101
+ zubo config set heartbeatMinutes 60
102
+ zubo config set auth.enabled true
103
+ zubo config set rateLimit.chatPerMinute 30
104
+ zubo config set channels.webchat.port 8080
105
+ zubo config set providers.anthropic.model claude-sonnet-4-5-20250929
106
+
107
+ # Get values
108
+ zubo config get # Show entire configuration (pretty-printed)
109
+ zubo config get activeProvider # Show a single value
110
+ zubo config get channels.telegram # Show a nested object
111
+ zubo config get rateLimit # Show all rate limit settings</code></pre>
112
+
113
+ <p><strong>Notes on the CLI:</strong></p>
114
+ <ul>
115
+ <li>Supports <strong>dotted keys</strong> for nested values. <code>zubo config set channels.webchat.port 8080</code> writes to <code>{"channels": {"webchat": {"port": 8080}}}</code>.</li>
116
+ <li>Types are <strong>auto-detected</strong>: <code>true</code> and <code>false</code> become booleans, strings of digits become numbers, everything else stays a string.</li>
117
+ <li>To explicitly set a string that looks like a number, wrap it in quotes: <code>zubo config set someField '"12345"'</code>.</li>
118
+ <li>The <code>set</code> command writes the file atomically, so there is no risk of corruption from concurrent writes.</li>
119
+ </ul>
120
+
121
+ <!-- ================================================================ -->
122
+ <h2 id="llm-providers">LLM Providers</h2>
123
+
124
+ <p>
125
+ Zubo supports a multi-provider architecture. You configure one or more LLM providers under the <code>providers</code> object, set one as <code>activeProvider</code>, and optionally define a <code>failover</code> chain. If the active provider fails (network error, rate limit, authentication error), Zubo automatically tries each failover provider in order until one succeeds.
126
+ </p>
127
+
128
+ <h3>Supported Providers</h3>
129
+
130
+ <table>
131
+ <thead>
132
+ <tr>
133
+ <th>Provider Key</th>
134
+ <th>Default Base URL</th>
135
+ <th>Notes</th>
136
+ </tr>
137
+ </thead>
138
+ <tbody>
139
+ <tr>
140
+ <td><code>anthropic</code></td>
141
+ <td><em>(uses Anthropic SDK directly)</em></td>
142
+ <td>Claude models. Supports up to 200k token context. Native streaming. Recommended primary provider.</td>
143
+ </tr>
144
+ <tr>
145
+ <td><code>openai</code></td>
146
+ <td><code>https://api.openai.com/v1</code></td>
147
+ <td>GPT-4o, GPT-4-turbo, and other OpenAI models. Streaming supported.</td>
148
+ </tr>
149
+ <tr>
150
+ <td><code>ollama</code></td>
151
+ <td><code>http://localhost:11434/v1</code></td>
152
+ <td>Run models locally. No API key required. Great as a failover for offline operation.</td>
153
+ </tr>
154
+ <tr>
155
+ <td><code>groq</code></td>
156
+ <td><code>https://api.groq.com/openai/v1</code></td>
157
+ <td>Extremely fast inference. Supports Llama, Mixtral, and other open models.</td>
158
+ </tr>
159
+ <tr>
160
+ <td><code>together</code></td>
161
+ <td><code>https://api.together.xyz/v1</code></td>
162
+ <td>Wide selection of open-source models. Competitive pricing.</td>
163
+ </tr>
164
+ <tr>
165
+ <td><code>openrouter</code></td>
166
+ <td><code>https://openrouter.ai/api/v1</code></td>
167
+ <td>Multi-model gateway. Access Claude, GPT-4, Llama, and more through a single API key.</td>
168
+ </tr>
169
+ <tr>
170
+ <td><code>lmstudio</code></td>
171
+ <td><code>http://localhost:1234/v1</code></td>
172
+ <td>Local model GUI. Download and run models with a graphical interface. No API key required.</td>
173
+ </tr>
174
+ <tr>
175
+ <td><code>google</code></td>
176
+ <td><code>https://generativelanguage.googleapis.com/v1beta</code></td>
177
+ <td>Google Gemini models. Supports Gemini Pro, Gemini Flash, and other Google AI models.</td>
178
+ </tr>
179
+ <tr>
180
+ <td><code>deepseek</code></td>
181
+ <td><code>https://api.deepseek.com/v1</code></td>
182
+ <td>DeepSeek models. OpenAI-compatible API with strong reasoning capabilities at competitive pricing.</td>
183
+ </tr>
184
+ <tr>
185
+ <td><code>xai</code></td>
186
+ <td><code>https://api.x.ai/v1</code></td>
187
+ <td>xAI Grok models. OpenAI-compatible API with real-time knowledge.</td>
188
+ </tr>
189
+ <tr>
190
+ <td><code>fireworks</code></td>
191
+ <td><code>https://api.fireworks.ai/inference/v1</code></td>
192
+ <td>Fireworks AI. Fast inference for open-source models with optimized serving.</td>
193
+ </tr>
194
+ </tbody>
195
+ </table>
196
+
197
+ <h3>Provider Configuration Fields</h3>
198
+
199
+ <p>Each provider object under <code>providers</code> accepts the following fields:</p>
200
+
201
+ <table>
202
+ <thead>
203
+ <tr>
204
+ <th>Field</th>
205
+ <th>Type</th>
206
+ <th>Required</th>
207
+ <th>Description</th>
208
+ </tr>
209
+ </thead>
210
+ <tbody>
211
+ <tr>
212
+ <td><code>apiKey</code></td>
213
+ <td>string</td>
214
+ <td>Yes*</td>
215
+ <td>API key for the provider. Not required for local providers (Ollama, LM Studio).</td>
216
+ </tr>
217
+ <tr>
218
+ <td><code>baseUrl</code></td>
219
+ <td>string</td>
220
+ <td>No</td>
221
+ <td>Override the default base URL. Useful for proxies or self-hosted endpoints.</td>
222
+ </tr>
223
+ <tr>
224
+ <td><code>model</code></td>
225
+ <td>string</td>
226
+ <td>No</td>
227
+ <td>Model name to use. Defaults vary by provider (e.g., <code>claude-sonnet-4-5-20250929</code> for Anthropic).</td>
228
+ </tr>
229
+ <tr>
230
+ <td><code>streaming</code></td>
231
+ <td>boolean</td>
232
+ <td>No</td>
233
+ <td>Enable or disable streaming responses. Defaults to <code>true</code>.</td>
234
+ </tr>
235
+ <tr>
236
+ <td><code>contextWindow</code></td>
237
+ <td>number</td>
238
+ <td>No</td>
239
+ <td>Maximum context window size in tokens. Zubo uses this for context compaction decisions. Defaults to the provider's known maximum.</td>
240
+ </tr>
241
+ </tbody>
242
+ </table>
243
+
244
+ <h3>Multi-Provider Example with Failover</h3>
245
+
246
+ <pre><code>{
247
+ "providers": {
248
+ "anthropic": {
249
+ "apiKey": "sk-ant-api03-...",
250
+ "model": "claude-sonnet-4-5-20250929",
251
+ "streaming": true,
252
+ "contextWindow": 200000
253
+ },
254
+ "openai": {
255
+ "apiKey": "sk-proj-...",
256
+ "model": "gpt-4o",
257
+ "streaming": true
258
+ },
259
+ "ollama": {
260
+ "baseUrl": "http://localhost:11434/v1",
261
+ "model": "llama3.3",
262
+ "streaming": true
263
+ }
264
+ },
265
+ "activeProvider": "anthropic",
266
+ "failover": ["openai", "ollama"]
267
+ }</code></pre>
268
+
269
+ <p>In this configuration, Zubo uses Claude as the primary model. If Anthropic returns an error (rate limit, network issue, etc.), it automatically tries OpenAI next, and finally Ollama as a local fallback. The failover is transparent to the user &mdash; they receive a response regardless of which provider handled it.</p>
270
+
271
+ <h3>Smart Routing</h3>
272
+
273
+ <p>
274
+ Smart routing automatically selects the best provider for each query based on complexity. Simple questions (greetings, quick lookups, short follow-ups) are routed to fast, inexpensive models, while complex queries (multi-step reasoning, code generation, long-form writing) go to your most capable provider. This can significantly reduce costs without noticeable quality loss.
275
+ </p>
276
+
277
+ <table>
278
+ <thead>
279
+ <tr>
280
+ <th>Field</th>
281
+ <th>Type</th>
282
+ <th>Default</th>
283
+ <th>Description</th>
284
+ </tr>
285
+ </thead>
286
+ <tbody>
287
+ <tr>
288
+ <td><code>smartRouting.enabled</code></td>
289
+ <td>boolean</td>
290
+ <td><code>false</code></td>
291
+ <td>Enable automatic query routing between providers.</td>
292
+ </tr>
293
+ <tr>
294
+ <td><code>smartRouting.fastProvider</code></td>
295
+ <td>string</td>
296
+ <td>&mdash;</td>
297
+ <td>Provider key to use for simple queries (e.g., <code>"groq"</code>, <code>"deepseek"</code>).</td>
298
+ </tr>
299
+ <tr>
300
+ <td><code>smartRouting.complexProvider</code></td>
301
+ <td>string</td>
302
+ <td>&mdash;</td>
303
+ <td>Provider key to use for complex queries. Defaults to <code>activeProvider</code> if not set.</td>
304
+ </tr>
305
+ </tbody>
306
+ </table>
307
+
308
+ <pre><code>"smartRouting": {
309
+ "enabled": true,
310
+ "fastProvider": "groq",
311
+ "complexProvider": "anthropic"
312
+ }</code></pre>
313
+
314
+ <p>When smart routing is enabled, Zubo classifies each incoming message and routes it accordingly. You can always override the routing for a specific message by prefixing it with the provider name (e.g., <code>@anthropic explain quantum computing</code>).</p>
315
+
316
+ <!-- ================================================================ -->
317
+ <h2 id="channel-configuration">Channel Configuration</h2>
318
+
319
+ <p>
320
+ Channels define how users interact with Zubo. Each channel is independently configured under the <code>channels</code> object. All enabled channels share the same memory, personality, tools, and conversation history &mdash; a fact learned via Telegram is immediately available in Discord or the web dashboard.
321
+ </p>
322
+
323
+ <h3>Web Chat</h3>
324
+
325
+ <table>
326
+ <thead>
327
+ <tr>
328
+ <th>Field</th>
329
+ <th>Type</th>
330
+ <th>Default</th>
331
+ <th>Description</th>
332
+ </tr>
333
+ </thead>
334
+ <tbody>
335
+ <tr>
336
+ <td><code>enabled</code></td>
337
+ <td>boolean</td>
338
+ <td><code>true</code></td>
339
+ <td>Enable the built-in web chat dashboard.</td>
340
+ </tr>
341
+ <tr>
342
+ <td><code>port</code></td>
343
+ <td>number</td>
344
+ <td><code>3000</code></td>
345
+ <td>HTTP port for the web dashboard and API.</td>
346
+ </tr>
347
+ </tbody>
348
+ </table>
349
+
350
+ <pre><code>"webchat": {
351
+ "enabled": true,
352
+ "port": 3000
353
+ }</code></pre>
354
+
355
+ <h3>Telegram</h3>
356
+
357
+ <table>
358
+ <thead>
359
+ <tr>
360
+ <th>Field</th>
361
+ <th>Type</th>
362
+ <th>Default</th>
363
+ <th>Description</th>
364
+ </tr>
365
+ </thead>
366
+ <tbody>
367
+ <tr>
368
+ <td><code>enabled</code></td>
369
+ <td>boolean</td>
370
+ <td><code>false</code></td>
371
+ <td>Enable the Telegram channel.</td>
372
+ </tr>
373
+ <tr>
374
+ <td><code>botToken</code></td>
375
+ <td>string</td>
376
+ <td>&mdash;</td>
377
+ <td>Bot token from <a href="https://t.me/BotFather" target="_blank" rel="noopener">@BotFather</a>.</td>
378
+ </tr>
379
+ <tr>
380
+ <td><code>allowedUsers</code></td>
381
+ <td>number[]</td>
382
+ <td><code>[]</code></td>
383
+ <td>Array of numeric Telegram user IDs allowed to interact. Empty array means no restriction.</td>
384
+ </tr>
385
+ </tbody>
386
+ </table>
387
+
388
+ <pre><code>"telegram": {
389
+ "enabled": true,
390
+ "botToken": "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11",
391
+ "allowedUsers": [12345678, 87654321]
392
+ }</code></pre>
393
+
394
+ <h3>Discord</h3>
395
+
396
+ <table>
397
+ <thead>
398
+ <tr>
399
+ <th>Field</th>
400
+ <th>Type</th>
401
+ <th>Default</th>
402
+ <th>Description</th>
403
+ </tr>
404
+ </thead>
405
+ <tbody>
406
+ <tr>
407
+ <td><code>enabled</code></td>
408
+ <td>boolean</td>
409
+ <td><code>false</code></td>
410
+ <td>Enable the Discord channel.</td>
411
+ </tr>
412
+ <tr>
413
+ <td><code>botToken</code></td>
414
+ <td>string</td>
415
+ <td>&mdash;</td>
416
+ <td>Bot token from the <a href="https://discord.com/developers/applications" target="_blank" rel="noopener">Discord Developer Portal</a>.</td>
417
+ </tr>
418
+ <tr>
419
+ <td><code>allowedUsers</code></td>
420
+ <td>string[]</td>
421
+ <td><code>[]</code></td>
422
+ <td>Array of Discord user ID strings allowed to interact. Empty array means no restriction.</td>
423
+ </tr>
424
+ </tbody>
425
+ </table>
426
+
427
+ <pre><code>"discord": {
428
+ "enabled": true,
429
+ "botToken": "MTk4NjIyNDgzNDcxOTI1...",
430
+ "allowedUsers": ["198622483471925248"]
431
+ }</code></pre>
432
+
433
+ <h3>Slack</h3>
434
+
435
+ <table>
436
+ <thead>
437
+ <tr>
438
+ <th>Field</th>
439
+ <th>Type</th>
440
+ <th>Default</th>
441
+ <th>Description</th>
442
+ </tr>
443
+ </thead>
444
+ <tbody>
445
+ <tr>
446
+ <td><code>enabled</code></td>
447
+ <td>boolean</td>
448
+ <td><code>false</code></td>
449
+ <td>Enable the Slack channel.</td>
450
+ </tr>
451
+ <tr>
452
+ <td><code>botToken</code></td>
453
+ <td>string</td>
454
+ <td>&mdash;</td>
455
+ <td>Bot User OAuth Token (starts with <code>xoxb-</code>).</td>
456
+ </tr>
457
+ <tr>
458
+ <td><code>appToken</code></td>
459
+ <td>string</td>
460
+ <td>&mdash;</td>
461
+ <td>App-Level Token (starts with <code>xapp-</code>). Required for Socket Mode.</td>
462
+ </tr>
463
+ <tr>
464
+ <td><code>allowedUsers</code></td>
465
+ <td>string[]</td>
466
+ <td><code>[]</code></td>
467
+ <td>Array of Slack member ID strings allowed to interact. Empty array means no restriction.</td>
468
+ </tr>
469
+ </tbody>
470
+ </table>
471
+
472
+ <pre><code>"slack": {
473
+ "enabled": true,
474
+ "botToken": "xoxb-1234567890-abcdefghij",
475
+ "appToken": "xapp-1-A0123456789-1234567890123-abcdef",
476
+ "allowedUsers": ["U01ABCDEF"]
477
+ }</code></pre>
478
+
479
+ <h3>WhatsApp</h3>
480
+
481
+ <table>
482
+ <thead>
483
+ <tr>
484
+ <th>Field</th>
485
+ <th>Type</th>
486
+ <th>Default</th>
487
+ <th>Description</th>
488
+ </tr>
489
+ </thead>
490
+ <tbody>
491
+ <tr>
492
+ <td><code>enabled</code></td>
493
+ <td>boolean</td>
494
+ <td><code>false</code></td>
495
+ <td>Enable the WhatsApp channel.</td>
496
+ </tr>
497
+ <tr>
498
+ <td><code>authDir</code></td>
499
+ <td>string</td>
500
+ <td><code>~/.zubo/whatsapp-auth</code></td>
501
+ <td>Directory to store WhatsApp Web authentication data. On first run, a QR code is displayed for pairing.</td>
502
+ </tr>
503
+ <tr>
504
+ <td><code>allowedNumbers</code></td>
505
+ <td>string[]</td>
506
+ <td><code>[]</code></td>
507
+ <td>Array of phone numbers (with country code, e.g., <code>"14155551234"</code>) allowed to interact. Empty array means no restriction.</td>
508
+ </tr>
509
+ </tbody>
510
+ </table>
511
+
512
+ <pre><code>"whatsapp": {
513
+ "enabled": true,
514
+ "authDir": "/Users/you/.zubo/whatsapp-auth",
515
+ "allowedNumbers": ["14155551234", "447700900000"]
516
+ }</code></pre>
517
+
518
+ <h3>Signal</h3>
519
+
520
+ <table>
521
+ <thead>
522
+ <tr>
523
+ <th>Field</th>
524
+ <th>Type</th>
525
+ <th>Default</th>
526
+ <th>Description</th>
527
+ </tr>
528
+ </thead>
529
+ <tbody>
530
+ <tr>
531
+ <td><code>enabled</code></td>
532
+ <td>boolean</td>
533
+ <td><code>false</code></td>
534
+ <td>Enable the Signal channel.</td>
535
+ </tr>
536
+ <tr>
537
+ <td><code>phoneNumber</code></td>
538
+ <td>string</td>
539
+ <td>&mdash;</td>
540
+ <td>The phone number registered with Signal for the bot (with country code, e.g., <code>"+14155551234"</code>).</td>
541
+ </tr>
542
+ <tr>
543
+ <td><code>signalCliPath</code></td>
544
+ <td>string</td>
545
+ <td><code>signal-cli</code></td>
546
+ <td>Path to the <code>signal-cli</code> binary. Defaults to looking on the system PATH.</td>
547
+ </tr>
548
+ <tr>
549
+ <td><code>allowedNumbers</code></td>
550
+ <td>string[]</td>
551
+ <td><code>[]</code></td>
552
+ <td>Array of phone numbers allowed to interact. Empty array means no restriction.</td>
553
+ </tr>
554
+ </tbody>
555
+ </table>
556
+
557
+ <pre><code>"signal": {
558
+ "enabled": true,
559
+ "phoneNumber": "+14155551234",
560
+ "signalCliPath": "/usr/local/bin/signal-cli",
561
+ "allowedNumbers": ["+447700900000"]
562
+ }</code></pre>
563
+
564
+ <!-- ================================================================ -->
565
+ <h2 id="voice-configuration">Voice Configuration</h2>
566
+
567
+ <p>
568
+ Zubo supports speech-to-text (STT) for transcribing voice messages received on any channel, and text-to-speech (TTS) for generating spoken audio responses. Voice is configured under the <code>voice</code> object.
569
+ </p>
570
+
571
+ <h3>Speech-to-Text (STT)</h3>
572
+
573
+ <table>
574
+ <thead>
575
+ <tr>
576
+ <th>Field</th>
577
+ <th>Type</th>
578
+ <th>Default</th>
579
+ <th>Description</th>
580
+ </tr>
581
+ </thead>
582
+ <tbody>
583
+ <tr>
584
+ <td><code>provider</code></td>
585
+ <td>string</td>
586
+ <td><code>"whisper"</code></td>
587
+ <td>STT provider. Currently supported: <code>whisper</code> (OpenAI Whisper API).</td>
588
+ </tr>
589
+ <tr>
590
+ <td><code>apiKey</code></td>
591
+ <td>string</td>
592
+ <td>&mdash;</td>
593
+ <td>API key for the STT provider. For Whisper, this is your OpenAI API key.</td>
594
+ </tr>
595
+ <tr>
596
+ <td><code>model</code></td>
597
+ <td>string</td>
598
+ <td><code>"whisper-1"</code></td>
599
+ <td>Model to use for transcription.</td>
600
+ </tr>
601
+ </tbody>
602
+ </table>
603
+
604
+ <h3>Text-to-Speech (TTS)</h3>
605
+
606
+ <table>
607
+ <thead>
608
+ <tr>
609
+ <th>Field</th>
610
+ <th>Type</th>
611
+ <th>Default</th>
612
+ <th>Description</th>
613
+ </tr>
614
+ </thead>
615
+ <tbody>
616
+ <tr>
617
+ <td><code>provider</code></td>
618
+ <td>string</td>
619
+ <td><code>"openai"</code></td>
620
+ <td>TTS provider. Supported: <code>openai</code>, <code>elevenlabs</code>.</td>
621
+ </tr>
622
+ <tr>
623
+ <td><code>apiKey</code></td>
624
+ <td>string</td>
625
+ <td>&mdash;</td>
626
+ <td>API key for the TTS provider.</td>
627
+ </tr>
628
+ <tr>
629
+ <td><code>voice</code></td>
630
+ <td>string</td>
631
+ <td><code>"nova"</code></td>
632
+ <td>Voice to use for speech generation. OpenAI voices: <code>alloy</code>, <code>echo</code>, <code>fable</code>, <code>onyx</code>, <code>nova</code>, <code>shimmer</code>. ElevenLabs voices depend on your account.</td>
633
+ </tr>
634
+ </tbody>
635
+ </table>
636
+
637
+ <pre><code>"voice": {
638
+ "stt": {
639
+ "provider": "whisper",
640
+ "apiKey": "sk-proj-...",
641
+ "model": "whisper-1"
642
+ },
643
+ "tts": {
644
+ "provider": "openai",
645
+ "apiKey": "sk-proj-...",
646
+ "voice": "nova"
647
+ }
648
+ }</code></pre>
649
+
650
+ <!-- ================================================================ -->
651
+ <h2 id="agent-settings">Agent Settings</h2>
652
+
653
+ <p>These top-level settings control the core agent behavior.</p>
654
+
655
+ <table>
656
+ <thead>
657
+ <tr>
658
+ <th>Field</th>
659
+ <th>Type</th>
660
+ <th>Default</th>
661
+ <th>Description</th>
662
+ </tr>
663
+ </thead>
664
+ <tbody>
665
+ <tr>
666
+ <td><code>maxTurns</code></td>
667
+ <td>number</td>
668
+ <td><code>50</code></td>
669
+ <td>Maximum number of tool-call rounds per conversation turn. When the agent reaches this limit, it stops calling tools and produces a text response with whatever information it has gathered. This prevents runaway tool loops. Reasonable values range from 10 (tightly constrained) to 100 (complex multi-step tasks).</td>
670
+ </tr>
671
+ <tr>
672
+ <td><code>heartbeatMinutes</code></td>
673
+ <td>number</td>
674
+ <td><code>30</code></td>
675
+ <td>Interval in minutes (1&ndash;1440) between heartbeat cycles. During each heartbeat, Zubo wakes up, checks for pending cron jobs, processes scheduled tasks, evaluates proactive memory triggers, and optionally sends notifications. Set to a low value (1&ndash;5) for near-real-time scheduling, or a high value (60&ndash;1440) to conserve resources.</td>
676
+ </tr>
677
+ </tbody>
678
+ </table>
679
+
680
+ <pre><code>{
681
+ "maxTurns": 50,
682
+ "heartbeatMinutes": 30
683
+ }</code></pre>
684
+
685
+ <!-- ================================================================ -->
686
+ <h2 id="rate-limiting">Rate Limiting</h2>
687
+
688
+ <p>
689
+ Zubo includes built-in per-IP rate limiting to protect against abuse. Rate limits use a sliding window algorithm &mdash; each IP address gets an independent counter that resets on a rolling 60-second basis.
690
+ </p>
691
+
692
+ <table>
693
+ <thead>
694
+ <tr>
695
+ <th>Field</th>
696
+ <th>Type</th>
697
+ <th>Default</th>
698
+ <th>Description</th>
699
+ </tr>
700
+ </thead>
701
+ <tbody>
702
+ <tr>
703
+ <td><code>rateLimit.chatPerMinute</code></td>
704
+ <td>number</td>
705
+ <td><code>60</code></td>
706
+ <td>Maximum chat messages per minute per IP address. Applies to the <code>/api/chat</code> endpoint and WebSocket messages. When exceeded, the client receives a <code>429 Too Many Requests</code> response.</td>
707
+ </tr>
708
+ <tr>
709
+ <td><code>rateLimit.uploadPerMinute</code></td>
710
+ <td>number</td>
711
+ <td><code>10</code></td>
712
+ <td>Maximum file uploads per minute per IP address. Applies to the <code>/api/upload</code> endpoint. Uploads are more resource-intensive (document parsing, chunking, embedding), so the default is lower.</td>
713
+ </tr>
714
+ </tbody>
715
+ </table>
716
+
717
+ <pre><code>"rateLimit": {
718
+ "chatPerMinute": 60,
719
+ "uploadPerMinute": 10
720
+ }</code></pre>
721
+
722
+ <p>For personal use on localhost, the defaults are generous. If you are exposing Zubo on a public network or sharing it with others, consider lowering these values (e.g., <code>chatPerMinute: 30</code>, <code>uploadPerMinute: 5</code>).</p>
723
+
724
+ <!-- ================================================================ -->
725
+ <h2 id="budget-controls">Budget Controls</h2>
726
+
727
+ <p>
728
+ Zubo tracks token usage and estimated costs for every LLM request. You can set spending limits to prevent surprise bills and view per-model cost breakdowns in the dashboard.
729
+ </p>
730
+
731
+ <table>
732
+ <thead>
733
+ <tr>
734
+ <th>Field</th>
735
+ <th>Type</th>
736
+ <th>Default</th>
737
+ <th>Description</th>
738
+ </tr>
739
+ </thead>
740
+ <tbody>
741
+ <tr>
742
+ <td><code>budget.dailyLimit</code></td>
743
+ <td>number</td>
744
+ <td><code>0</code></td>
745
+ <td>Maximum daily spend in USD. Set to <code>0</code> for no limit. When the limit is reached, Zubo pauses LLM requests and notifies you.</td>
746
+ </tr>
747
+ <tr>
748
+ <td><code>budget.monthlyLimit</code></td>
749
+ <td>number</td>
750
+ <td><code>0</code></td>
751
+ <td>Maximum monthly spend in USD. Set to <code>0</code> for no limit.</td>
752
+ </tr>
753
+ <tr>
754
+ <td><code>budget.warningThreshold</code></td>
755
+ <td>number</td>
756
+ <td><code>0.8</code></td>
757
+ <td>Percentage (0&ndash;1) of the budget at which Zubo sends a warning notification. Default is 80%.</td>
758
+ </tr>
759
+ </tbody>
760
+ </table>
761
+
762
+ <pre><code>"budget": {
763
+ "dailyLimit": 5,
764
+ "monthlyLimit": 50,
765
+ "warningThreshold": 0.8
766
+ }</code></pre>
767
+
768
+ <p>Cost tracking is always active even without spending limits. View your usage breakdown in the dashboard under Analytics &rarr; Costs, or ask Zubo directly: &ldquo;How much have I spent today?&rdquo;</p>
769
+
770
+ <!-- ================================================================ -->
771
+ <h2 id="authentication">Authentication</h2>
772
+
773
+ <p>
774
+ When <code>auth.enabled</code> is <code>true</code>, all HTTP API endpoints and WebSocket connections require a valid API key. This is strongly recommended if you are exposing Zubo's port beyond localhost.
775
+ </p>
776
+
777
+ <table>
778
+ <thead>
779
+ <tr>
780
+ <th>Field</th>
781
+ <th>Type</th>
782
+ <th>Default</th>
783
+ <th>Description</th>
784
+ </tr>
785
+ </thead>
786
+ <tbody>
787
+ <tr>
788
+ <td><code>auth.enabled</code></td>
789
+ <td>boolean</td>
790
+ <td><code>false</code></td>
791
+ <td>Enable API key authentication for all HTTP and WebSocket endpoints.</td>
792
+ </tr>
793
+ </tbody>
794
+ </table>
795
+
796
+ <h3>Managing API Keys</h3>
797
+
798
+ <p>API keys can be created and managed via the CLI or the web dashboard:</p>
799
+
800
+ <pre><code># Create a new API key
801
+ zubo auth create --name "my-app"
802
+ # Output: API key created: zb_k1_a1b2c3d4e5f6...
803
+
804
+ # List all API keys
805
+ zubo auth list
806
+
807
+ # Revoke an API key
808
+ zubo auth revoke zb_k1_a1b2c3d4e5f6...</code></pre>
809
+
810
+ <h3>Using API Keys</h3>
811
+
812
+ <p>Include the API key in the <code>Authorization</code> header as a Bearer token:</p>
813
+
814
+ <pre><code>curl -X POST http://localhost:3000/api/chat \
815
+ -H "Authorization: Bearer zb_k1_a1b2c3d4e5f6..." \
816
+ -H "Content-Type: application/json" \
817
+ -d '{"message": "Hello, Zubo!"}'</code></pre>
818
+
819
+ <p>For WebSocket connections, pass the key as a query parameter:</p>
820
+
821
+ <pre><code>ws://localhost:3000/ws?token=zb_k1_a1b2c3d4e5f6...</code></pre>
822
+
823
+ <p>API keys are stored as hashed values in the SQLite database. The plain-text key is only shown once at creation time and cannot be retrieved later. If you lose a key, revoke it and create a new one.</p>
824
+
825
+ <!-- ================================================================ -->
826
+ <h2 id="sandbox">Sandbox</h2>
827
+
828
+ <p>
829
+ The sandbox controls how user-installed skills (from <code>~/.zubo/workspace/skills/</code>) are executed. Built-in tools always run in the main process, but user skills run in isolated subprocesses for safety.
830
+ </p>
831
+
832
+ <table>
833
+ <thead>
834
+ <tr>
835
+ <th>Field</th>
836
+ <th>Type</th>
837
+ <th>Default</th>
838
+ <th>Description</th>
839
+ </tr>
840
+ </thead>
841
+ <tbody>
842
+ <tr>
843
+ <td><code>sandbox.enabled</code></td>
844
+ <td>boolean</td>
845
+ <td><code>true</code></td>
846
+ <td>Enable subprocess sandboxing for user-installed skills. When enabled, each skill invocation runs in a separate Bun subprocess with restricted access. Disabling this is not recommended but may be necessary for skills that require direct main-process access.</td>
847
+ </tr>
848
+ <tr>
849
+ <td><code>sandbox.timeoutMs</code></td>
850
+ <td>number</td>
851
+ <td><code>30000</code></td>
852
+ <td>Maximum execution time in milliseconds for a single skill invocation. If a skill exceeds this timeout, its subprocess is terminated and an error is returned to the agent. Set higher for skills that perform long-running operations (e.g., large file processing, slow API calls).</td>
853
+ </tr>
854
+ </tbody>
855
+ </table>
856
+
857
+ <pre><code>"sandbox": {
858
+ "enabled": true,
859
+ "timeoutMs": 30000
860
+ }</code></pre>
861
+
862
+ <!-- ================================================================ -->
863
+ <h2 id="full-example">Full Example</h2>
864
+
865
+ <p>Here is a complete <code>~/.zubo/config.json</code> showing all configuration sections together. This represents a fully configured instance with Anthropic as the primary provider, Groq for smart routing, Ollama as a local failover, three channels enabled, voice support, budget controls, and production-ready security settings:</p>
866
+
867
+ <pre><code>{
868
+ "providers": {
869
+ "anthropic": {
870
+ "apiKey": "sk-ant-api03-...",
871
+ "model": "claude-sonnet-4-5-20250929",
872
+ "streaming": true,
873
+ "contextWindow": 200000
874
+ },
875
+ "groq": {
876
+ "apiKey": "gsk_...",
877
+ "model": "llama-3.3-70b-versatile",
878
+ "streaming": true
879
+ },
880
+ "ollama": {
881
+ "baseUrl": "http://localhost:11434/v1",
882
+ "model": "llama3.3",
883
+ "streaming": true
884
+ }
885
+ },
886
+ "activeProvider": "anthropic",
887
+ "failover": ["groq", "ollama"],
888
+
889
+ "smartRouting": {
890
+ "enabled": true,
891
+ "fastProvider": "groq",
892
+ "complexProvider": "anthropic"
893
+ },
894
+
895
+ "channels": {
896
+ "webchat": {
897
+ "enabled": true,
898
+ "port": 3000
899
+ },
900
+ "telegram": {
901
+ "enabled": true,
902
+ "botToken": "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11",
903
+ "allowedUsers": [12345678]
904
+ },
905
+ "discord": {
906
+ "enabled": true,
907
+ "botToken": "MTk4NjIyNDgzNDcxOTI1...",
908
+ "allowedUsers": []
909
+ },
910
+ "slack": {
911
+ "enabled": false,
912
+ "botToken": "",
913
+ "appToken": "",
914
+ "allowedUsers": []
915
+ },
916
+ "whatsapp": {
917
+ "enabled": false,
918
+ "authDir": "",
919
+ "allowedNumbers": []
920
+ },
921
+ "signal": {
922
+ "enabled": false,
923
+ "phoneNumber": "",
924
+ "signalCliPath": "signal-cli",
925
+ "allowedNumbers": []
926
+ }
927
+ },
928
+
929
+ "voice": {
930
+ "stt": {
931
+ "provider": "whisper",
932
+ "apiKey": "sk-proj-...",
933
+ "model": "whisper-1"
934
+ },
935
+ "tts": {
936
+ "provider": "openai",
937
+ "apiKey": "sk-proj-...",
938
+ "voice": "nova"
939
+ }
940
+ },
941
+
942
+ "maxTurns": 50,
943
+ "heartbeatMinutes": 30,
944
+
945
+ "rateLimit": {
946
+ "chatPerMinute": 60,
947
+ "uploadPerMinute": 10
948
+ },
949
+
950
+ "budget": {
951
+ "dailyLimit": 5,
952
+ "monthlyLimit": 50,
953
+ "warningThreshold": 0.8
954
+ },
955
+
956
+ "auth": {
957
+ "enabled": false
958
+ },
959
+
960
+ "sandbox": {
961
+ "enabled": true,
962
+ "timeoutMs": 30000
963
+ }
964
+ }</code></pre>
965
+
966
+ <p><strong>Tip:</strong> You do not need to include every field. Zubo applies sensible defaults for any omitted values. A minimal config only needs <code>activeProvider</code> and the corresponding provider entry with an API key.</p>
967
+
968
+ <!-- ================================================================ -->
969
+ <h2 id="environment">Environment</h2>
970
+
971
+ <p>
972
+ By default, Zubo stores all data and configuration under <code>~/.zubo</code>. You can override this by setting the <code>ZUBO_HOME</code> environment variable to an absolute path:
973
+ </p>
974
+
975
+ <pre><code># Use a custom home directory
976
+ export ZUBO_HOME=/opt/zubo-data
977
+ zubo start
978
+
979
+ # Or inline for a single invocation
980
+ ZUBO_HOME=/opt/zubo-data zubo start --daemon</code></pre>
981
+
982
+ <p>When <code>ZUBO_HOME</code> is set, all paths &mdash; config file, database, logs, sessions, models, and workspace &mdash; are resolved relative to that directory instead of <code>~/.zubo</code>. This is useful for running multiple isolated Zubo instances on the same machine, or for placing the data directory on a specific volume or mount point.</p>
983
+
984
+ <p>Other environment variables recognized by Zubo:</p>
985
+
986
+ <table>
987
+ <thead>
988
+ <tr>
989
+ <th>Variable</th>
990
+ <th>Description</th>
991
+ </tr>
992
+ </thead>
993
+ <tbody>
994
+ <tr>
995
+ <td><code>ZUBO_HOME</code></td>
996
+ <td>Override the default <code>~/.zubo</code> data directory.</td>
997
+ </tr>
998
+ <tr>
999
+ <td><code>ZUBO_LOG_LEVEL</code></td>
1000
+ <td>Set the log level: <code>debug</code>, <code>info</code>, <code>warn</code>, <code>error</code>. Defaults to <code>info</code>.</td>
1001
+ </tr>
1002
+ <tr>
1003
+ <td><code>ZUBO_PORT</code></td>
1004
+ <td>Override the web dashboard port (takes precedence over config file).</td>
1005
+ </tr>
1006
+ <tr>
1007
+ <td><code>NODE_ENV</code></td>
1008
+ <td>When set to <code>production</code>, Zubo disables verbose logging and enables additional security hardening.</td>
1009
+ </tr>
1010
+ </tbody>
1011
+ </table>
1012
+
1013
+ <div class="docs-page-nav">
1014
+ <a href="index.html"><span class="nav-dir">Previous</span><span class="nav-label">&larr; Overview</span></a>
1015
+ <a href="agents.html"><span class="nav-dir">Next</span><span class="nav-label">Agents &amp; Workflows &rarr;</span></a>
1016
+ </div>
1017
+
1018
+ </main>
1019
+ </div>
1020
+ <button class="docs-sidebar-toggle" id="docs-sidebar-toggle" aria-label="Toggle sidebar">&#9776;</button>
1021
+ <script src="../script.js"></script>
1022
+ <script type="application/ld+json">
1023
+ {
1024
+ "@context": "https://schema.org",
1025
+ "@type": "BreadcrumbList",
1026
+ "itemListElement": [
1027
+ { "@type": "ListItem", "position": 1, "name": "Home", "item": "https://zubo.bot/" },
1028
+ { "@type": "ListItem", "position": 2, "name": "Docs", "item": "https://zubo.bot/docs/" },
1029
+ { "@type": "ListItem", "position": 3, "name": "Configuration", "item": "https://zubo.bot/docs/config.html" }
1030
+ ]
1031
+ }
1032
+ </script>
1033
+ </body>
1034
+ </html>