boten-gemma 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.
- package/README.md +860 -0
- package/dist/automation/cron/index.d.ts +6 -0
- package/dist/automation/cron/index.d.ts.map +1 -0
- package/dist/automation/cron/index.js +4 -0
- package/dist/automation/cron/index.js.map +1 -0
- package/dist/automation/cron/parse-schedule.d.ts +11 -0
- package/dist/automation/cron/parse-schedule.d.ts.map +1 -0
- package/dist/automation/cron/parse-schedule.js +36 -0
- package/dist/automation/cron/parse-schedule.js.map +1 -0
- package/dist/automation/cron/schedule.d.ts +7 -0
- package/dist/automation/cron/schedule.d.ts.map +1 -0
- package/dist/automation/cron/schedule.js +28 -0
- package/dist/automation/cron/schedule.js.map +1 -0
- package/dist/automation/cron/service.d.ts +70 -0
- package/dist/automation/cron/service.d.ts.map +1 -0
- package/dist/automation/cron/service.js +207 -0
- package/dist/automation/cron/service.js.map +1 -0
- package/dist/automation/cron/store.d.ts +12 -0
- package/dist/automation/cron/store.d.ts.map +1 -0
- package/dist/automation/cron/store.js +27 -0
- package/dist/automation/cron/store.js.map +1 -0
- package/dist/automation/cron/types.d.ts +67 -0
- package/dist/automation/cron/types.d.ts.map +1 -0
- package/dist/automation/cron/types.js +5 -0
- package/dist/automation/cron/types.js.map +1 -0
- package/dist/automation/cron.d.ts +15 -0
- package/dist/automation/cron.d.ts.map +1 -0
- package/dist/automation/cron.js +10 -0
- package/dist/automation/cron.js.map +1 -0
- package/dist/automation/heartbeat.d.ts +14 -0
- package/dist/automation/heartbeat.d.ts.map +1 -0
- package/dist/automation/heartbeat.js +27 -0
- package/dist/automation/heartbeat.js.map +1 -0
- package/dist/channels/cli.d.ts +17 -0
- package/dist/channels/cli.d.ts.map +1 -0
- package/dist/channels/cli.js +125 -0
- package/dist/channels/cli.js.map +1 -0
- package/dist/channels/telegram.d.ts +27 -0
- package/dist/channels/telegram.d.ts.map +1 -0
- package/dist/channels/telegram.js +288 -0
- package/dist/channels/telegram.js.map +1 -0
- package/dist/channels/types.d.ts +50 -0
- package/dist/channels/types.d.ts.map +1 -0
- package/dist/channels/types.js +6 -0
- package/dist/channels/types.js.map +1 -0
- package/dist/channels/web.d.ts +149 -0
- package/dist/channels/web.d.ts.map +1 -0
- package/dist/channels/web.js +1113 -0
- package/dist/channels/web.js.map +1 -0
- package/dist/config/defaults.d.ts +11 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +80 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/loader.d.ts +22 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +158 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +261 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +119 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/confirm/audit.d.ts +34 -0
- package/dist/confirm/audit.d.ts.map +1 -0
- package/dist/confirm/audit.js +49 -0
- package/dist/confirm/audit.js.map +1 -0
- package/dist/confirm/auto-approve.d.ts +20 -0
- package/dist/confirm/auto-approve.d.ts.map +1 -0
- package/dist/confirm/auto-approve.js +62 -0
- package/dist/confirm/auto-approve.js.map +1 -0
- package/dist/confirm/gate.d.ts +50 -0
- package/dist/confirm/gate.d.ts.map +1 -0
- package/dist/confirm/gate.js +138 -0
- package/dist/confirm/gate.js.map +1 -0
- package/dist/confirm/parser.d.ts +23 -0
- package/dist/confirm/parser.d.ts.map +1 -0
- package/dist/confirm/parser.js +76 -0
- package/dist/confirm/parser.js.map +1 -0
- package/dist/confirm/presenter.d.ts +23 -0
- package/dist/confirm/presenter.d.ts.map +1 -0
- package/dist/confirm/presenter.js +92 -0
- package/dist/confirm/presenter.js.map +1 -0
- package/dist/core/agent-loop.d.ts +44 -0
- package/dist/core/agent-loop.d.ts.map +1 -0
- package/dist/core/agent-loop.js +156 -0
- package/dist/core/agent-loop.js.map +1 -0
- package/dist/core/compaction.d.ts +17 -0
- package/dist/core/compaction.d.ts.map +1 -0
- package/dist/core/compaction.js +70 -0
- package/dist/core/compaction.js.map +1 -0
- package/dist/core/context-builder.d.ts +38 -0
- package/dist/core/context-builder.d.ts.map +1 -0
- package/dist/core/context-builder.js +137 -0
- package/dist/core/context-builder.js.map +1 -0
- package/dist/core/logger.d.ts +42 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +95 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/queue.d.ts +25 -0
- package/dist/core/queue.d.ts.map +1 -0
- package/dist/core/queue.js +33 -0
- package/dist/core/queue.js.map +1 -0
- package/dist/core/router.d.ts +21 -0
- package/dist/core/router.d.ts.map +1 -0
- package/dist/core/router.js +27 -0
- package/dist/core/router.js.map +1 -0
- package/dist/core/session-store.d.ts +53 -0
- package/dist/core/session-store.d.ts.map +1 -0
- package/dist/core/session-store.js +367 -0
- package/dist/core/session-store.js.map +1 -0
- package/dist/core/session.d.ts +89 -0
- package/dist/core/session.d.ts.map +1 -0
- package/dist/core/session.js +49 -0
- package/dist/core/session.js.map +1 -0
- package/dist/daemon/launchd.d.ts +8 -0
- package/dist/daemon/launchd.d.ts.map +1 -0
- package/dist/daemon/launchd.js +155 -0
- package/dist/daemon/launchd.js.map +1 -0
- package/dist/daemon/service.d.ts +12 -0
- package/dist/daemon/service.d.ts.map +1 -0
- package/dist/daemon/service.js +42 -0
- package/dist/daemon/service.js.map +1 -0
- package/dist/daemon/systemd.d.ts +11 -0
- package/dist/daemon/systemd.d.ts.map +1 -0
- package/dist/daemon/systemd.js +145 -0
- package/dist/daemon/systemd.js.map +1 -0
- package/dist/daemon/types.d.ts +14 -0
- package/dist/daemon/types.d.ts.map +1 -0
- package/dist/daemon/types.js +2 -0
- package/dist/daemon/types.js.map +1 -0
- package/dist/daemon/update.d.ts +41 -0
- package/dist/daemon/update.d.ts.map +1 -0
- package/dist/daemon/update.js +106 -0
- package/dist/daemon/update.js.map +1 -0
- package/dist/gateway.d.ts +103 -0
- package/dist/gateway.d.ts.map +1 -0
- package/dist/gateway.js +1063 -0
- package/dist/gateway.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +572 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/auth/oauth-callback.d.ts +20 -0
- package/dist/llm/auth/oauth-callback.d.ts.map +1 -0
- package/dist/llm/auth/oauth-callback.js +95 -0
- package/dist/llm/auth/oauth-callback.js.map +1 -0
- package/dist/llm/auth/oauth.d.ts +30 -0
- package/dist/llm/auth/oauth.d.ts.map +1 -0
- package/dist/llm/auth/oauth.js +331 -0
- package/dist/llm/auth/oauth.js.map +1 -0
- package/dist/llm/auth/resolver.d.ts +24 -0
- package/dist/llm/auth/resolver.d.ts.map +1 -0
- package/dist/llm/auth/resolver.js +97 -0
- package/dist/llm/auth/resolver.js.map +1 -0
- package/dist/llm/auth/token-store.d.ts +15 -0
- package/dist/llm/auth/token-store.d.ts.map +1 -0
- package/dist/llm/auth/token-store.js +94 -0
- package/dist/llm/auth/token-store.js.map +1 -0
- package/dist/llm/auth/types.d.ts +20 -0
- package/dist/llm/auth/types.d.ts.map +1 -0
- package/dist/llm/auth/types.js +3 -0
- package/dist/llm/auth/types.js.map +1 -0
- package/dist/llm/gemini.d.ts +28 -0
- package/dist/llm/gemini.d.ts.map +1 -0
- package/dist/llm/gemini.js +524 -0
- package/dist/llm/gemini.js.map +1 -0
- package/dist/llm/openai-compat.d.ts +14 -0
- package/dist/llm/openai-compat.d.ts.map +1 -0
- package/dist/llm/openai-compat.js +200 -0
- package/dist/llm/openai-compat.js.map +1 -0
- package/dist/llm/provider.d.ts +2 -0
- package/dist/llm/provider.d.ts.map +1 -0
- package/dist/llm/provider.js +4 -0
- package/dist/llm/provider.js.map +1 -0
- package/dist/llm/types.d.ts +75 -0
- package/dist/llm/types.d.ts.map +1 -0
- package/dist/llm/types.js +3 -0
- package/dist/llm/types.js.map +1 -0
- package/dist/mcp/adapter.d.ts +14 -0
- package/dist/mcp/adapter.d.ts.map +1 -0
- package/dist/mcp/adapter.js +58 -0
- package/dist/mcp/adapter.js.map +1 -0
- package/dist/mcp/index.d.ts +4 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +3 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/manager.d.ts +48 -0
- package/dist/mcp/manager.d.ts.map +1 -0
- package/dist/mcp/manager.js +109 -0
- package/dist/mcp/manager.js.map +1 -0
- package/dist/memory/daily-log.d.ts +19 -0
- package/dist/memory/daily-log.d.ts.map +1 -0
- package/dist/memory/daily-log.js +47 -0
- package/dist/memory/daily-log.js.map +1 -0
- package/dist/memory/memory-manager.d.ts +41 -0
- package/dist/memory/memory-manager.d.ts.map +1 -0
- package/dist/memory/memory-manager.js +97 -0
- package/dist/memory/memory-manager.js.map +1 -0
- package/dist/memory/workspace.d.ts +21 -0
- package/dist/memory/workspace.d.ts.map +1 -0
- package/dist/memory/workspace.js +63 -0
- package/dist/memory/workspace.js.map +1 -0
- package/dist/panels/bridge.d.ts +19 -0
- package/dist/panels/bridge.d.ts.map +1 -0
- package/dist/panels/bridge.js +74 -0
- package/dist/panels/bridge.js.map +1 -0
- package/dist/panels/registry.d.ts +30 -0
- package/dist/panels/registry.d.ts.map +1 -0
- package/dist/panels/registry.js +102 -0
- package/dist/panels/registry.js.map +1 -0
- package/dist/panels/routes.d.ts +8 -0
- package/dist/panels/routes.d.ts.map +1 -0
- package/dist/panels/routes.js +252 -0
- package/dist/panels/routes.js.map +1 -0
- package/dist/panels/sdk/gemma-panel.js +331 -0
- package/dist/panels/service-context.d.ts +28 -0
- package/dist/panels/service-context.d.ts.map +1 -0
- package/dist/panels/service-context.js +84 -0
- package/dist/panels/service-context.js.map +1 -0
- package/dist/panels/service-loader.d.ts +19 -0
- package/dist/panels/service-loader.d.ts.map +1 -0
- package/dist/panels/service-loader.js +61 -0
- package/dist/panels/service-loader.js.map +1 -0
- package/dist/panels/service-manager.d.ts +40 -0
- package/dist/panels/service-manager.d.ts.map +1 -0
- package/dist/panels/service-manager.js +148 -0
- package/dist/panels/service-manager.js.map +1 -0
- package/dist/panels/storage.d.ts +14 -0
- package/dist/panels/storage.d.ts.map +1 -0
- package/dist/panels/storage.js +47 -0
- package/dist/panels/storage.js.map +1 -0
- package/dist/panels/types.d.ts +39 -0
- package/dist/panels/types.d.ts.map +1 -0
- package/dist/panels/types.js +8 -0
- package/dist/panels/types.js.map +1 -0
- package/dist/shared/ws-types.d.ts +332 -0
- package/dist/shared/ws-types.d.ts.map +1 -0
- package/dist/shared/ws-types.js +7 -0
- package/dist/shared/ws-types.js.map +1 -0
- package/dist/skills/gating.d.ts +15 -0
- package/dist/skills/gating.d.ts.map +1 -0
- package/dist/skills/gating.js +49 -0
- package/dist/skills/gating.js.map +1 -0
- package/dist/skills/loader.d.ts +32 -0
- package/dist/skills/loader.d.ts.map +1 -0
- package/dist/skills/loader.js +66 -0
- package/dist/skills/loader.js.map +1 -0
- package/dist/skills/parser.d.ts +22 -0
- package/dist/skills/parser.d.ts.map +1 -0
- package/dist/skills/parser.js +29 -0
- package/dist/skills/parser.js.map +1 -0
- package/dist/skills/prompt-injector.d.ts +10 -0
- package/dist/skills/prompt-injector.d.ts.map +1 -0
- package/dist/skills/prompt-injector.js +29 -0
- package/dist/skills/prompt-injector.js.map +1 -0
- package/dist/tools/builtin/cron.d.ts +3 -0
- package/dist/tools/builtin/cron.d.ts.map +1 -0
- package/dist/tools/builtin/cron.js +198 -0
- package/dist/tools/builtin/cron.js.map +1 -0
- package/dist/tools/builtin/edit.d.ts +3 -0
- package/dist/tools/builtin/edit.d.ts.map +1 -0
- package/dist/tools/builtin/edit.js +77 -0
- package/dist/tools/builtin/edit.js.map +1 -0
- package/dist/tools/builtin/exec.d.ts +3 -0
- package/dist/tools/builtin/exec.d.ts.map +1 -0
- package/dist/tools/builtin/exec.js +88 -0
- package/dist/tools/builtin/exec.js.map +1 -0
- package/dist/tools/builtin/panel.d.ts +14 -0
- package/dist/tools/builtin/panel.d.ts.map +1 -0
- package/dist/tools/builtin/panel.js +521 -0
- package/dist/tools/builtin/panel.js.map +1 -0
- package/dist/tools/builtin/read.d.ts +3 -0
- package/dist/tools/builtin/read.d.ts.map +1 -0
- package/dist/tools/builtin/read.js +61 -0
- package/dist/tools/builtin/read.js.map +1 -0
- package/dist/tools/builtin/web-fetch.d.ts +3 -0
- package/dist/tools/builtin/web-fetch.d.ts.map +1 -0
- package/dist/tools/builtin/web-fetch.js +68 -0
- package/dist/tools/builtin/web-fetch.js.map +1 -0
- package/dist/tools/builtin/web-search.d.ts +3 -0
- package/dist/tools/builtin/web-search.d.ts.map +1 -0
- package/dist/tools/builtin/web-search.js +67 -0
- package/dist/tools/builtin/web-search.js.map +1 -0
- package/dist/tools/builtin/write.d.ts +3 -0
- package/dist/tools/builtin/write.d.ts.map +1 -0
- package/dist/tools/builtin/write.js +40 -0
- package/dist/tools/builtin/write.js.map +1 -0
- package/dist/tools/executor.d.ts +16 -0
- package/dist/tools/executor.d.ts.map +1 -0
- package/dist/tools/executor.js +142 -0
- package/dist/tools/executor.js.map +1 -0
- package/dist/tools/registry.d.ts +23 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +72 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/types.d.ts +58 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +8 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/ui/assets/code-block-OCS4YCEC-D5mQabi7.js +2 -0
- package/dist/ui/assets/index-0RdIdnZu.js +456 -0
- package/dist/ui/assets/index-CjWH8YjU.css +1 -0
- package/dist/ui/index.html +16 -0
- package/package.json +89 -0
- package/skills/coding/SKILL.md +52 -0
- package/skills/file-ops/SKILL.md +50 -0
- package/skills/panel-dev/SKILL.md +742 -0
- package/skills/system-admin/SKILL.md +56 -0
- package/skills/web-research/SKILL.md +44 -0
- package/templates/BOOTSTRAP.md +19 -0
- package/templates/IDENTITY.md +9 -0
- package/templates/INSTRUCTIONS.md +19 -0
- package/templates/MEMORY.md +5 -0
- package/templates/SOUL.md +21 -0
- package/templates/TOOLS.md +13 -0
- package/templates/USER.md +12 -0
- package/templates/panel/gemma-panel-sdk.d.ts +27 -0
- package/templates/panel/gemma-panel.d.ts +46 -0
- package/templates/panel/index.html +59 -0
- package/templates/panel/package.json +15 -0
- package/templates/panel/panel.json +12 -0
- package/templates/panel/service.ts +69 -0
- package/templates/panel/tsconfig.json +17 -0
- package/templates/panel/vite.config.ts +13 -0
- package/templates/panel-react/index.html +12 -0
- package/templates/panel-react/package.json +22 -0
- package/templates/panel-react/panel.json +10 -0
- package/templates/panel-react/service.ts +69 -0
- package/templates/panel-react/src/App.tsx +108 -0
- package/templates/panel-react/src/gemma.d.ts +13 -0
- package/templates/panel-react/src/main.tsx +9 -0
- package/templates/panel-react/src/vite-env.d.ts +1 -0
- package/templates/panel-react/tsconfig.json +17 -0
- package/templates/panel-react/tsconfig.service.json +16 -0
- package/templates/panel-react/vite.config.ts +14 -0
package/README.md
ADDED
|
@@ -0,0 +1,860 @@
|
|
|
1
|
+
# Gemma
|
|
2
|
+
|
|
3
|
+
A confirmation-first personal AI assistant. Gemma is a single-process Node.js gateway that connects messaging channels (Web, Telegram, CLI) to an LLM with tool access. The core invariant: **no tool executes without user approval**.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Quick Start](#quick-start)
|
|
8
|
+
- [Architecture](#architecture)
|
|
9
|
+
- [Configuration](#configuration)
|
|
10
|
+
- [Channels](#channels)
|
|
11
|
+
- [LLM Providers](#llm-providers)
|
|
12
|
+
- [Authentication](#authentication)
|
|
13
|
+
- [Tools](#tools)
|
|
14
|
+
- [Confirmation Gate](#confirmation-gate)
|
|
15
|
+
- [Skills](#skills)
|
|
16
|
+
- [Panels](#panels)
|
|
17
|
+
- [Automation](#automation)
|
|
18
|
+
- [Web UI](#web-ui)
|
|
19
|
+
- [WebSocket Protocol](#websocket-protocol)
|
|
20
|
+
- [Deployment](#deployment)
|
|
21
|
+
- [Project Structure](#project-structure)
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Install dependencies
|
|
29
|
+
npm install
|
|
30
|
+
|
|
31
|
+
# Interactive first-run setup (auth, channels, directories)
|
|
32
|
+
npx gemma setup
|
|
33
|
+
|
|
34
|
+
# Or configure manually and start
|
|
35
|
+
npx gemma start
|
|
36
|
+
|
|
37
|
+
# Development
|
|
38
|
+
npm run dev # Server with tsx (auto-restart)
|
|
39
|
+
npm run dev:ui # Vite dev server on :5173 with HMR
|
|
40
|
+
npm run build # Full production build (server + UI)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Prerequisites
|
|
44
|
+
|
|
45
|
+
- **Node.js 22+** (uses built-in `.env` loading, ES2023 features)
|
|
46
|
+
- A Gemini API key or Google OAuth credentials
|
|
47
|
+
- Optional: Brave Search API key for web search
|
|
48
|
+
|
|
49
|
+
### First Run
|
|
50
|
+
|
|
51
|
+
On first launch, Gemma runs an interactive setup wizard:
|
|
52
|
+
|
|
53
|
+
1. **Auth** -- Choose OAuth (browser flow), API key, or skip
|
|
54
|
+
2. **Channels** -- Enable Telegram (with bot token), Web UI (with optional password)
|
|
55
|
+
3. **Setup** -- Creates `~/.gemma/` directory structure, writes `gemma.json`, copies workspace templates
|
|
56
|
+
|
|
57
|
+
After setup, Gemma starts on `http://localhost:18789`.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Architecture
|
|
62
|
+
|
|
63
|
+
Gemma is a **single-process gateway** that orchestrates messaging channels, an LLM, and tool execution through a mandatory confirmation gate.
|
|
64
|
+
|
|
65
|
+
### Message Flow
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
Channel (Web / Telegram / CLI)
|
|
69
|
+
-> Gateway.handleMessage()
|
|
70
|
+
-> Session resolution (per channel+sender)
|
|
71
|
+
-> Agent loop (up to 25 iterations):
|
|
72
|
+
1. Auto-compact if context > 200k chars
|
|
73
|
+
2. Hard trim if context > 320k chars
|
|
74
|
+
3. Build system prompt (workspace files + skills + runtime)
|
|
75
|
+
4. LLM.generate() -- streaming async generator
|
|
76
|
+
5. Collect text + tool calls from stream
|
|
77
|
+
6. If text only -> send response, break
|
|
78
|
+
7. If tool calls -> ConfirmationGate.process()
|
|
79
|
+
-> Auto-approve check (internal reads only)
|
|
80
|
+
-> Present to user via channel
|
|
81
|
+
-> Execute approved tools
|
|
82
|
+
8. Feed tool results back to LLM
|
|
83
|
+
9. Continue loop
|
|
84
|
+
-> Send final response to channel
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Key Design Decisions
|
|
88
|
+
|
|
89
|
+
- **Single import boundary**: `ConfirmationGate` is the _only_ module that imports the tool executor. The executor is never re-exported or accessible from any other path.
|
|
90
|
+
- **Streaming-first**: Both LLM providers are async generators. No buffered mode.
|
|
91
|
+
- **Error-as-text**: When all LLM retries are exhausted, errors are yielded as text chunks rather than thrown, keeping the conversation alive.
|
|
92
|
+
- **Session serialization**: Each session allows only one concurrent agent loop run via a `running` flag.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Configuration
|
|
97
|
+
|
|
98
|
+
Gemma loads config from `gemma.json`, searched in order: current directory, then `~/.gemma/`.
|
|
99
|
+
|
|
100
|
+
- **JSON5** comments and trailing commas supported
|
|
101
|
+
- **`${ENV_VAR}`** expansion in string values
|
|
102
|
+
- **`~`** expands to home directory
|
|
103
|
+
- Full **Zod validation** with sensible defaults
|
|
104
|
+
|
|
105
|
+
### Complete Reference
|
|
106
|
+
|
|
107
|
+
#### Model
|
|
108
|
+
|
|
109
|
+
| Key | Type | Default | Description |
|
|
110
|
+
|-----|------|---------|-------------|
|
|
111
|
+
| `model.provider` | `'gemini' \| 'openai-compat'` | `'gemini'` | LLM provider |
|
|
112
|
+
| `model.model` | `string` | `'gemini-2.5-flash'` | Default model name |
|
|
113
|
+
| `model.fallbackModel` | `string?` | -- | Fallback model when primary is at capacity |
|
|
114
|
+
| `model.auth` | `'oauth' \| 'api-key' \| 'adc'` | auto-detected | Force a specific auth mode |
|
|
115
|
+
| `model.apiKey` | `string?` | -- | Gemini API key (or use `GEMINI_API_KEY` env) |
|
|
116
|
+
| `model.oauth.clientId` | `string?` | -- | Custom OAuth client ID |
|
|
117
|
+
| `model.oauth.clientSecret` | `string?` | -- | Custom OAuth client secret |
|
|
118
|
+
| `model.openaiCompat.baseUrl` | `string` | `http://localhost:11434/v1` | OpenAI-compatible server URL |
|
|
119
|
+
| `model.openaiCompat.model` | `string` | `llama3.2` | Model name for OpenAI-compat |
|
|
120
|
+
|
|
121
|
+
#### Gateway
|
|
122
|
+
|
|
123
|
+
| Key | Type | Default | Description |
|
|
124
|
+
|-----|------|---------|-------------|
|
|
125
|
+
| `gateway.port` | `number` | `18789` | HTTP/WS port (env: `GEMMA_PORT`) |
|
|
126
|
+
| `gateway.bind` | `string` | `'127.0.0.1'` | Bind address (env: `GEMMA_BIND`) |
|
|
127
|
+
| `gateway.auth.token` | `string?` | -- | Optional password for WebSocket auth |
|
|
128
|
+
|
|
129
|
+
#### Channels
|
|
130
|
+
|
|
131
|
+
| Key | Type | Default | Description |
|
|
132
|
+
|-----|------|---------|-------------|
|
|
133
|
+
| `channels.web.enabled` | `boolean` | `true` | Enable Web UI + WebSocket |
|
|
134
|
+
| `channels.telegram.enabled` | `boolean` | `false` | Enable Telegram bot |
|
|
135
|
+
| `channels.telegram.token` | `string?` | -- | Bot token (or `TELEGRAM_BOT_TOKEN` env) |
|
|
136
|
+
| `channels.telegram.webhookUrl` | `string?` | -- | Webhook URL (omit for polling mode) |
|
|
137
|
+
| `channels.telegram.allowFrom` | `number[]` | `[]` | Allowed Telegram user IDs (empty = all) |
|
|
138
|
+
| `channels.cli.enabled` | `boolean` | `false` | Enable CLI channel |
|
|
139
|
+
|
|
140
|
+
#### Confirmation
|
|
141
|
+
|
|
142
|
+
| Key | Type | Default | Description |
|
|
143
|
+
|-----|------|---------|-------------|
|
|
144
|
+
| `confirm.timeout` | `number` | `300` | Confirmation timeout in seconds |
|
|
145
|
+
| `confirm.autoApprove.internalReads` | `boolean` | `true` | Auto-approve reads inside `~/.gemma/` |
|
|
146
|
+
| `confirm.autoApprove.memoryWrites` | `boolean` | `false` | Auto-approve writes to MEMORY.md |
|
|
147
|
+
|
|
148
|
+
#### Agent Loop
|
|
149
|
+
|
|
150
|
+
| Key | Type | Default | Description |
|
|
151
|
+
|-----|------|---------|-------------|
|
|
152
|
+
| `agent.maxIterations` | `number` | `25` | Max tool-call rounds per request (1-100) |
|
|
153
|
+
| `agent.compactionThreshold` | `number` | `200000` | Auto-compact above this char count |
|
|
154
|
+
| `agent.maxContextChars` | `number` | `320000` | Hard trim above this char count |
|
|
155
|
+
| `agent.maxToolResultChars` | `number` | `30000` | Truncate individual tool results |
|
|
156
|
+
|
|
157
|
+
#### Tools
|
|
158
|
+
|
|
159
|
+
| Key | Type | Default | Description |
|
|
160
|
+
|-----|------|---------|-------------|
|
|
161
|
+
| `tools.exec.timeout` | `number` | `30` | Shell command timeout (seconds) |
|
|
162
|
+
| `tools.exec.shell` | `string` | `'/bin/bash'` | Shell for exec tool |
|
|
163
|
+
| `tools.webSearch.provider` | `string` | `'brave'` | Web search provider |
|
|
164
|
+
| `tools.webSearch.apiKey` | `string?` | -- | Brave Search API key (or `BRAVE_SEARCH_API_KEY` env) |
|
|
165
|
+
|
|
166
|
+
#### Panels
|
|
167
|
+
|
|
168
|
+
| Key | Type | Default | Description |
|
|
169
|
+
|-----|------|---------|-------------|
|
|
170
|
+
| `panels.enabled` | `boolean` | `true` | Enable panel system |
|
|
171
|
+
| `panels.dir` | `string` | `'~/.gemma/panels'` | Panels directory |
|
|
172
|
+
| `panels.maxDataSize` | `number` | `5242880` | Max data storage per panel (bytes) |
|
|
173
|
+
| `panels.disabled` | `string[]` | `[]` | Panel names to disable |
|
|
174
|
+
| `panels.devMode` | `boolean` | `false` | Proxy to panel dev servers |
|
|
175
|
+
| `panels.serviceTimeout` | `number` | `30000` | Service start/stop/RPC timeout (ms) |
|
|
176
|
+
|
|
177
|
+
#### Automation
|
|
178
|
+
|
|
179
|
+
| Key | Type | Default | Description |
|
|
180
|
+
|-----|------|---------|-------------|
|
|
181
|
+
| `heartbeat.enabled` | `boolean` | `true` | Enable periodic heartbeat |
|
|
182
|
+
| `heartbeat.intervalMinutes` | `number` | `30` | Heartbeat interval |
|
|
183
|
+
| `heartbeat.prompt` | `string` | `'Read HEARTBEAT.md...'` | Prompt sent to agent |
|
|
184
|
+
| `cron.enabled` | `boolean` | `true` | Enable cron system |
|
|
185
|
+
| `cron.store` | `string` | `'~/.gemma/cron/jobs.json'` | Job persistence path |
|
|
186
|
+
|
|
187
|
+
#### Skills
|
|
188
|
+
|
|
189
|
+
| Key | Type | Default | Description |
|
|
190
|
+
|-----|------|---------|-------------|
|
|
191
|
+
| `skills.dirs` | `string[]` | `[]` | Extra skill directories |
|
|
192
|
+
| `skills.entries` | `Record` | `{}` | Per-skill configuration |
|
|
193
|
+
|
|
194
|
+
#### MCP
|
|
195
|
+
|
|
196
|
+
| Key | Type | Default | Description |
|
|
197
|
+
|-----|------|---------|-------------|
|
|
198
|
+
| `mcp.servers` | `Record<string, MCPServer>` | `{}` | Named MCP server configs |
|
|
199
|
+
|
|
200
|
+
Each MCP server: `{ command, args?, env?, enabled? }`
|
|
201
|
+
|
|
202
|
+
### Environment Variables
|
|
203
|
+
|
|
204
|
+
| Variable | Purpose |
|
|
205
|
+
|----------|---------|
|
|
206
|
+
| `GEMMA_HOME` | Override home directory (default: `~/.gemma`) |
|
|
207
|
+
| `GEMMA_PORT` | Override gateway port |
|
|
208
|
+
| `GEMMA_BIND` | Override bind address |
|
|
209
|
+
| `GEMINI_API_KEY` | Gemini API key |
|
|
210
|
+
| `BRAVE_SEARCH_API_KEY` | Brave Search API key |
|
|
211
|
+
| `TELEGRAM_BOT_TOKEN` | Telegram bot token |
|
|
212
|
+
| `GEMMA_OAUTH_CLIENT_ID` | Custom OAuth client ID |
|
|
213
|
+
| `GEMMA_OAUTH_CLIENT_SECRET` | Custom OAuth client secret |
|
|
214
|
+
|
|
215
|
+
### Example `gemma.json`
|
|
216
|
+
|
|
217
|
+
```json5
|
|
218
|
+
{
|
|
219
|
+
// Use Gemini 3 Flash with 2.5 Flash as fallback
|
|
220
|
+
"model": {
|
|
221
|
+
"model": "gemini-3-flash-preview",
|
|
222
|
+
"fallbackModel": "gemini-2.5-flash"
|
|
223
|
+
},
|
|
224
|
+
"gateway": {
|
|
225
|
+
"port": 18789,
|
|
226
|
+
"bind": "0.0.0.0",
|
|
227
|
+
"auth": { "token": "my-secret" }
|
|
228
|
+
},
|
|
229
|
+
"channels": {
|
|
230
|
+
"web": { "enabled": true },
|
|
231
|
+
"telegram": {
|
|
232
|
+
"enabled": true,
|
|
233
|
+
"token": "${TELEGRAM_BOT_TOKEN}",
|
|
234
|
+
"allowFrom": [123456789]
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
"confirm": {
|
|
238
|
+
"autoApprove": {
|
|
239
|
+
"internalReads": true,
|
|
240
|
+
"memoryWrites": true
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
"mcp": {
|
|
244
|
+
"servers": {
|
|
245
|
+
"filesystem": {
|
|
246
|
+
"command": "npx",
|
|
247
|
+
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user"]
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Channels
|
|
257
|
+
|
|
258
|
+
### Web (default)
|
|
259
|
+
|
|
260
|
+
HTTP server + WebSocket on the configured port. Serves:
|
|
261
|
+
- React SPA at `/`
|
|
262
|
+
- Panel files at `/panels/:name/*`
|
|
263
|
+
- Panel SDK at `/panels/_sdk/gemma-panel.js`
|
|
264
|
+
- Panel API at `/api/panels`
|
|
265
|
+
- Health check at `/health`
|
|
266
|
+
- Telegram webhook at `/webhook/telegram`
|
|
267
|
+
|
|
268
|
+
WebSocket at `/ws` handles all real-time communication (chat, streaming, confirmations, config, sessions, cron, logs, panels). Optional token auth via `gateway.auth.token`.
|
|
269
|
+
|
|
270
|
+
### Telegram
|
|
271
|
+
|
|
272
|
+
Uses [grammY](https://grammy.dev/) framework. Supports:
|
|
273
|
+
- **Polling mode** (default): Standalone long-polling
|
|
274
|
+
- **Webhook mode**: Routes through the web channel's HTTP server
|
|
275
|
+
- **Inline keyboard confirmations**: Approve All / Select Individual / Reject All
|
|
276
|
+
- **Streaming**: Edits message in-place every second with accumulated text
|
|
277
|
+
- **Access control**: `allowFrom` whitelist of Telegram user IDs
|
|
278
|
+
|
|
279
|
+
### CLI
|
|
280
|
+
|
|
281
|
+
Readline-based interface for local development. Color-coded output via chalk. Confirmations via text input (`y`/`n`/comma-separated indices).
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## LLM Providers
|
|
286
|
+
|
|
287
|
+
### Gemini (default)
|
|
288
|
+
|
|
289
|
+
Two API endpoints depending on auth mode:
|
|
290
|
+
|
|
291
|
+
| Auth Mode | Endpoint | URL |
|
|
292
|
+
|-----------|----------|-----|
|
|
293
|
+
| API key | Standard Gemini API | `generativelanguage.googleapis.com/v1beta` |
|
|
294
|
+
| OAuth | Code Assist proxy | `cloudcode-pa.googleapis.com/v1internal` |
|
|
295
|
+
| ADC | Standard Gemini API | Same as API key |
|
|
296
|
+
|
|
297
|
+
**Features:**
|
|
298
|
+
- SSE streaming with async generator interface
|
|
299
|
+
- Thinking/reasoning mode (`thinkingBudget: 8192` tokens)
|
|
300
|
+
- `thoughtSignature` propagation on tool calls
|
|
301
|
+
- Retry logic: 5 retries, exponential backoff (1s base, 5s for capacity exhaustion), 60s max delay
|
|
302
|
+
- Fallback model: automatically tries a configured fallback on `MODEL_CAPACITY_EXHAUSTED`
|
|
303
|
+
- Respects `Retry-After` headers
|
|
304
|
+
|
|
305
|
+
**Available models:** `gemini-3-pro-preview`, `gemini-3-flash-preview`, `gemini-2.5-pro`, `gemini-2.5-flash`, `gemini-2.0-flash`, `gemini-2.0-flash-lite`
|
|
306
|
+
|
|
307
|
+
### OpenAI-Compatible
|
|
308
|
+
|
|
309
|
+
For local/self-hosted LLMs: **Ollama**, **LM Studio**, **vLLM**, etc.
|
|
310
|
+
|
|
311
|
+
```json5
|
|
312
|
+
{
|
|
313
|
+
"model": {
|
|
314
|
+
"provider": "openai-compat",
|
|
315
|
+
"openaiCompat": {
|
|
316
|
+
"baseUrl": "http://localhost:11434/v1",
|
|
317
|
+
"model": "llama3.2"
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Uses standard `/chat/completions` with streaming. No retry logic or fallback model support.
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
## Authentication
|
|
328
|
+
|
|
329
|
+
Three modes, auto-detected in priority order:
|
|
330
|
+
|
|
331
|
+
### 1. OAuth (recommended)
|
|
332
|
+
|
|
333
|
+
```bash
|
|
334
|
+
gemma auth --google
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
Opens a browser for Google OAuth consent. Tokens cached at `~/.gemma/auth/tokens.json` (chmod 600) with automatic refresh 5 minutes before expiry.
|
|
338
|
+
|
|
339
|
+
OAuth credentials are borrowed from the installed [Gemini CLI](https://github.com/anthropics/gemini-cli) (`@google/gemini-cli-core`). Falls back to `GEMMA_OAUTH_CLIENT_ID`/`GEMMA_OAUTH_CLIENT_SECRET` env vars or config.
|
|
340
|
+
|
|
341
|
+
Supports headless environments (SSH, CI) -- prints URL for user to open on any device.
|
|
342
|
+
|
|
343
|
+
### 2. API Key
|
|
344
|
+
|
|
345
|
+
```bash
|
|
346
|
+
export GEMINI_API_KEY="your-key-here"
|
|
347
|
+
# or in gemma.json:
|
|
348
|
+
# "model": { "apiKey": "your-key" }
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### 3. Application Default Credentials (ADC)
|
|
352
|
+
|
|
353
|
+
For GCP environments. Uses `google-auth-library` with `cloud-platform` scope. Auto-detected when no OAuth tokens or API key are available.
|
|
354
|
+
|
|
355
|
+
### Auth Commands
|
|
356
|
+
|
|
357
|
+
```bash
|
|
358
|
+
gemma auth --status # Show current auth mode and email
|
|
359
|
+
gemma auth --google # Run OAuth flow
|
|
360
|
+
gemma auth --api-key # Set API key
|
|
361
|
+
gemma auth --logout # Revoke tokens and delete
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## Tools
|
|
367
|
+
|
|
368
|
+
8 built-in tools, all going through the confirmation gate:
|
|
369
|
+
|
|
370
|
+
### `read`
|
|
371
|
+
Read file contents with optional line range.
|
|
372
|
+
- **Params**: `path` (required), `startLine?`, `endLine?` (1-based)
|
|
373
|
+
- Returns numbered lines with metadata
|
|
374
|
+
|
|
375
|
+
### `write`
|
|
376
|
+
Write content to a file, creating parent directories as needed.
|
|
377
|
+
- **Params**: `path` (required), `content` (required)
|
|
378
|
+
|
|
379
|
+
### `edit`
|
|
380
|
+
Find-and-replace a unique string in a file.
|
|
381
|
+
- **Params**: `path` (required), `old_string` (required), `new_string` (required)
|
|
382
|
+
- Rejects if old_string appears 0 or 2+ times
|
|
383
|
+
|
|
384
|
+
### `exec`
|
|
385
|
+
Execute a shell command.
|
|
386
|
+
- **Params**: `command` (required), `timeout?` (default 30s)
|
|
387
|
+
- Returns stdout, stderr, exit code. SIGTERM then SIGKILL on timeout.
|
|
388
|
+
|
|
389
|
+
### `web_search`
|
|
390
|
+
Search the web via Brave Search API.
|
|
391
|
+
- **Params**: `query` (required), `count?` (max 20, default 5)
|
|
392
|
+
- Requires `BRAVE_SEARCH_API_KEY` or config
|
|
393
|
+
|
|
394
|
+
### `web_fetch`
|
|
395
|
+
Fetch a URL and convert HTML to markdown.
|
|
396
|
+
- **Params**: `url` (required), `maxLength?` (default 50000)
|
|
397
|
+
|
|
398
|
+
### `cron`
|
|
399
|
+
Manage scheduled jobs (list, add, update, remove, enable, disable, run).
|
|
400
|
+
- Schedule formats: cron expressions (`0 9 * * 1-5`), intervals (`every:30m`), one-shots (`at:2024-03-15T09:00:00Z`)
|
|
401
|
+
|
|
402
|
+
### `create_panel`
|
|
403
|
+
Scaffold, update, remove, list, or rebuild UI panels.
|
|
404
|
+
- Templates: `html` (custom HTML) or `react` (React 18 + Vite + TypeScript)
|
|
405
|
+
- Optional backend service with RPC and event support
|
|
406
|
+
|
|
407
|
+
### MCP Tools
|
|
408
|
+
|
|
409
|
+
External tools from MCP servers are discovered at startup and registered as `mcp__<server>__<tool>`. They go through the same confirmation gate as built-in tools. MCP servers can be hot-reloaded via the Settings UI.
|
|
410
|
+
|
|
411
|
+
---
|
|
412
|
+
|
|
413
|
+
## Confirmation Gate
|
|
414
|
+
|
|
415
|
+
The security boundary. Every tool call passes through the gate before execution.
|
|
416
|
+
|
|
417
|
+
### Auto-Approve Rules
|
|
418
|
+
|
|
419
|
+
| Condition | Auto-approved? | Default |
|
|
420
|
+
|-----------|---------------|---------|
|
|
421
|
+
| `read` tool targeting paths inside `~/.gemma/` | Yes | `internalReads: true` |
|
|
422
|
+
| `read` tool targeting `HEARTBEAT.md` | Yes | Always |
|
|
423
|
+
| `write`/`edit` to `MEMORY.md` or `memory/*.md` | Configurable | `memoryWrites: false` |
|
|
424
|
+
| Everything else | No | Requires confirmation |
|
|
425
|
+
|
|
426
|
+
### Cowboy Mode
|
|
427
|
+
|
|
428
|
+
Per-session toggle that bypasses ALL confirmations. Enabled via the shield toggle in the Web UI. Use with caution.
|
|
429
|
+
|
|
430
|
+
### Audit Log
|
|
431
|
+
|
|
432
|
+
Every confirmation cycle is logged to `~/.gemma/logs/audit.jsonl`:
|
|
433
|
+
```json
|
|
434
|
+
{
|
|
435
|
+
"timestamp": "2024-03-15T09:00:00.000Z",
|
|
436
|
+
"session": "s-abc123-xyz",
|
|
437
|
+
"proposed": [{"tool": "exec", "args": {"command": "ls"}}],
|
|
438
|
+
"approved": [0],
|
|
439
|
+
"rejected": [],
|
|
440
|
+
"auto_approved": [],
|
|
441
|
+
"user_response_time_ms": 2100
|
|
442
|
+
}
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
## Skills
|
|
448
|
+
|
|
449
|
+
Skills are `SKILL.md` files with YAML frontmatter that provide domain-specific instructions to the agent.
|
|
450
|
+
|
|
451
|
+
### Format
|
|
452
|
+
|
|
453
|
+
```markdown
|
|
454
|
+
---
|
|
455
|
+
name: my-skill
|
|
456
|
+
description: What this skill does
|
|
457
|
+
metadata:
|
|
458
|
+
requires:
|
|
459
|
+
bins: [docker] # Required binaries on PATH
|
|
460
|
+
env: [DOCKER_HOST] # Required environment variables
|
|
461
|
+
---
|
|
462
|
+
# Instructions for the agent
|
|
463
|
+
Detailed instructions here...
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
### Loading Order (later overrides earlier)
|
|
467
|
+
|
|
468
|
+
1. `./skills/` -- Bundled with Gemma
|
|
469
|
+
2. `~/.gemma/workspace/skills/` -- User workspace
|
|
470
|
+
3. Config `skills.dirs` entries -- Custom directories
|
|
471
|
+
|
|
472
|
+
### Bundled Skills (5)
|
|
473
|
+
|
|
474
|
+
| Skill | Description |
|
|
475
|
+
|-------|-------------|
|
|
476
|
+
| `web-research` | Search the web and extract content from URLs |
|
|
477
|
+
| `file-ops` | Read, write, and edit files on the local filesystem |
|
|
478
|
+
| `coding` | Writing, debugging, reviewing, and explaining code |
|
|
479
|
+
| `system-admin` | Execute system commands and manage servers |
|
|
480
|
+
| `panel-development` | Guide for creating Gemma panels with backend services |
|
|
481
|
+
|
|
482
|
+
Skills are gated by their `requires` field -- unavailable skills (missing binaries/env vars) are excluded from the system prompt.
|
|
483
|
+
|
|
484
|
+
---
|
|
485
|
+
|
|
486
|
+
## Panels
|
|
487
|
+
|
|
488
|
+
Panels are mini web apps that extend Gemma's UI. They run in sandboxed iframes and communicate via a client SDK and optional backend services.
|
|
489
|
+
|
|
490
|
+
### Display Modes
|
|
491
|
+
|
|
492
|
+
- **Tab** -- Full-width content area, shown as a nav item in the sidebar
|
|
493
|
+
- **Sidebar** -- Compact widget at the bottom of the sidebar (max 300px height)
|
|
494
|
+
|
|
495
|
+
### Creating a Panel
|
|
496
|
+
|
|
497
|
+
The LLM can scaffold panels via the `create_panel` tool, or you can create one manually:
|
|
498
|
+
|
|
499
|
+
```
|
|
500
|
+
~/.gemma/panels/my-panel/
|
|
501
|
+
panel.json # Manifest (required)
|
|
502
|
+
index.html # Entry point
|
|
503
|
+
dist/ # Build output (for React panels)
|
|
504
|
+
data/ # Scoped data directory (runtime)
|
|
505
|
+
service.ts # Backend service (optional)
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
### Manifest (`panel.json`)
|
|
509
|
+
|
|
510
|
+
```json
|
|
511
|
+
{
|
|
512
|
+
"name": "my-panel",
|
|
513
|
+
"title": "My Panel",
|
|
514
|
+
"version": "1.0.0",
|
|
515
|
+
"entry": "index.html",
|
|
516
|
+
"display": "tab",
|
|
517
|
+
"icon": "puzzle",
|
|
518
|
+
"permissions": ["send:chat", "read:data", "write:data"],
|
|
519
|
+
"service": "service.js"
|
|
520
|
+
}
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
**Permissions**: `send:chat`, `read:data`, `write:data`, `read:memory`, `listen:chat`
|
|
524
|
+
|
|
525
|
+
### Client SDK
|
|
526
|
+
|
|
527
|
+
Auto-injected into panel HTML. Provides:
|
|
528
|
+
|
|
529
|
+
```javascript
|
|
530
|
+
const panel = new GemmaPanel();
|
|
531
|
+
|
|
532
|
+
// Data storage (scoped per panel)
|
|
533
|
+
await panel.readData('key');
|
|
534
|
+
await panel.writeData('key', value);
|
|
535
|
+
|
|
536
|
+
// Chat integration
|
|
537
|
+
panel.sendChat('Hello from my panel');
|
|
538
|
+
panel.onMessage(msg => console.log(msg));
|
|
539
|
+
|
|
540
|
+
// Backend RPC
|
|
541
|
+
const result = await panel.callBackend('myMethod', { param: 'value' });
|
|
542
|
+
panel.onEvent('update', data => console.log(data));
|
|
543
|
+
|
|
544
|
+
// Theme
|
|
545
|
+
const theme = await panel.getTheme(); // { isDark, variables }
|
|
546
|
+
|
|
547
|
+
// Notifications
|
|
548
|
+
panel.notify('Something happened', 'info');
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
### Backend Services
|
|
552
|
+
|
|
553
|
+
Optional server-side logic for panels. Export `start`, `onRpc`, and `stop`:
|
|
554
|
+
|
|
555
|
+
```typescript
|
|
556
|
+
import type { PanelServiceContext } from './gemma-panel.js';
|
|
557
|
+
|
|
558
|
+
export async function start(ctx: PanelServiceContext) {
|
|
559
|
+
ctx.emit('ready', { status: 'initialized' });
|
|
560
|
+
ctx.schedule('refresh', 60000, () => { /* periodic work */ });
|
|
561
|
+
ctx.registerTool({ name: 'my_tool', description: '...', parameters: {...},
|
|
562
|
+
execute: async (args) => ({ content: 'result' }) });
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
export async function onRpc(method: string, params: unknown, ctx: PanelServiceContext) {
|
|
566
|
+
if (method === 'getData') return { items: [] };
|
|
567
|
+
throw new Error(`Unknown method: ${method}`);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
export async function stop() { /* cleanup */ }
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
---
|
|
574
|
+
|
|
575
|
+
## Automation
|
|
576
|
+
|
|
577
|
+
### Heartbeat
|
|
578
|
+
|
|
579
|
+
Periodic wake-up that prompts the agent on a timer (default: every 30 minutes).
|
|
580
|
+
|
|
581
|
+
The agent reads `HEARTBEAT.md` from the workspace and acts on standing instructions. If nothing needs attention, it replies `HEARTBEAT_OK`. Runs in the most recently active web session.
|
|
582
|
+
|
|
583
|
+
### Cron
|
|
584
|
+
|
|
585
|
+
Full-featured scheduled job system.
|
|
586
|
+
|
|
587
|
+
**Schedule formats:**
|
|
588
|
+
- Cron expression: `0 9 * * 1-5` (9 AM weekdays)
|
|
589
|
+
- Interval: `every:30m`, `every:2h`, `every:1d`
|
|
590
|
+
- One-shot: `at:2024-03-15T09:00:00Z`
|
|
591
|
+
|
|
592
|
+
**Key behaviors:**
|
|
593
|
+
- Jobs persist to `~/.gemma/cron/jobs.json`
|
|
594
|
+
- Each job runs in an isolated session (or shared `main` session)
|
|
595
|
+
- Cron jobs **bypass the confirmation gate** -- they are pre-authorized
|
|
596
|
+
- Consecutive errors are tracked per job
|
|
597
|
+
- Jobs can be managed via the `cron` tool, Web UI, or WebSocket API
|
|
598
|
+
|
|
599
|
+
---
|
|
600
|
+
|
|
601
|
+
## Web UI
|
|
602
|
+
|
|
603
|
+
React 18 single-page application with Tailwind CSS 3 and shadcn/ui.
|
|
604
|
+
|
|
605
|
+
### Views
|
|
606
|
+
|
|
607
|
+
| View | Description |
|
|
608
|
+
|------|-------------|
|
|
609
|
+
| **Chat** | Conversation interface with streaming markdown, thinking display, inline tool confirmations, cowboy mode toggle |
|
|
610
|
+
| **Settings** | MCP server management, model/fallback selection, agent loop tuning, API keys, auth status |
|
|
611
|
+
| **Cron** | Create/edit/delete scheduled jobs with friendly schedule picker |
|
|
612
|
+
| **Logs** | Real-time log viewer with level/source filtering and auto-scroll |
|
|
613
|
+
| **Panel Manager** | List installed panels, enable/disable, view errors |
|
|
614
|
+
| **Panel tabs** | Full-width iframe hosting for tab-display panels |
|
|
615
|
+
|
|
616
|
+
### Chat Features
|
|
617
|
+
|
|
618
|
+
- **Streaming markdown** with syntax-highlighted code blocks (Shiki)
|
|
619
|
+
- **Thinking/reasoning display** -- collapsible with duration counter
|
|
620
|
+
- **Inline confirmations** -- approve/reject individual or all tool calls with risk indicators
|
|
621
|
+
- **Tool result cards** -- collapsible with status and preview
|
|
622
|
+
- **Per-session model override** and thinking toggle
|
|
623
|
+
- **Cowboy mode** -- shield toggle with confirmation dialog
|
|
624
|
+
- **Session management** -- sidebar with create, switch, rename, delete
|
|
625
|
+
|
|
626
|
+
### Development
|
|
627
|
+
|
|
628
|
+
```bash
|
|
629
|
+
npm run dev:ui # Vite on :5173, proxies /ws, /api, /panels to gateway on :18789
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
---
|
|
633
|
+
|
|
634
|
+
## WebSocket Protocol
|
|
635
|
+
|
|
636
|
+
38 message types over a single WebSocket connection at `/ws`.
|
|
637
|
+
|
|
638
|
+
### Core Chat
|
|
639
|
+
|
|
640
|
+
| Type | Direction | Description |
|
|
641
|
+
|------|-----------|-------------|
|
|
642
|
+
| `chat` | Both | User message or assistant reply |
|
|
643
|
+
| `stream` | S->C | Streaming response chunk (`done: true` signals end) |
|
|
644
|
+
| `thinking` | S->C | LLM reasoning chunk |
|
|
645
|
+
| `confirmation` | S->C | Present tool calls with risk assessment |
|
|
646
|
+
| `confirmation_response` | C->S | User approval/rejection by call IDs |
|
|
647
|
+
| `tool_results` | S->C | Tool execution results |
|
|
648
|
+
|
|
649
|
+
### Session Management
|
|
650
|
+
|
|
651
|
+
| Type | Direction | Description |
|
|
652
|
+
|------|-----------|-------------|
|
|
653
|
+
| `session:resume` | C->S | Resume session on connect |
|
|
654
|
+
| `session:list` / `session:list:response` | Both | List all sessions |
|
|
655
|
+
| `session:new` / `session:switch` / `session:delete` / `session:rename` | C->S | CRUD operations |
|
|
656
|
+
| `session:restored` | S->C | Full session data with history |
|
|
657
|
+
| `session:event` | S->C | Session CRUD notifications |
|
|
658
|
+
|
|
659
|
+
### Config, Cron, Logs, Panels
|
|
660
|
+
|
|
661
|
+
Full CRUD over WebSocket for config management, MCP servers, cron jobs, log streaming, and panel bridge (data read/write, RPC, events).
|
|
662
|
+
|
|
663
|
+
See `src/shared/ws-types.ts` for the complete type definitions.
|
|
664
|
+
|
|
665
|
+
---
|
|
666
|
+
|
|
667
|
+
## Deployment
|
|
668
|
+
|
|
669
|
+
### Docker
|
|
670
|
+
|
|
671
|
+
```bash
|
|
672
|
+
# Build
|
|
673
|
+
docker build -f docker/Dockerfile -t gemma .
|
|
674
|
+
|
|
675
|
+
# Run with persistent state
|
|
676
|
+
docker run -d \
|
|
677
|
+
-p 18789:18789 \
|
|
678
|
+
-v gemma-data:/home/node/.gemma \
|
|
679
|
+
-e GEMINI_API_KEY=your-key \
|
|
680
|
+
-e GEMMA_BIND=0.0.0.0 \
|
|
681
|
+
gemma
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
The Docker image:
|
|
685
|
+
- Two-stage build (Node 22 -> Node 22 Alpine)
|
|
686
|
+
- Installs Gemini CLI globally for OAuth credential extraction
|
|
687
|
+
- Runs as non-root `node` user
|
|
688
|
+
- Exposes port 18789
|
|
689
|
+
- Persists all state in `/home/node/.gemma` volume
|
|
690
|
+
|
|
691
|
+
### Docker Compose
|
|
692
|
+
|
|
693
|
+
A `docker-compose.yml` with Caddy reverse proxy is included:
|
|
694
|
+
|
|
695
|
+
```bash
|
|
696
|
+
cd docker
|
|
697
|
+
cp .env.example .env # Edit with your API keys
|
|
698
|
+
docker compose up -d
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
This sets up Gemma behind Caddy for automatic HTTPS. Edit the `Caddyfile` for your domain.
|
|
702
|
+
|
|
703
|
+
### VPS / Bare Metal
|
|
704
|
+
|
|
705
|
+
```bash
|
|
706
|
+
npm install
|
|
707
|
+
npm run build
|
|
708
|
+
npx gemma start
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
Use a process manager (systemd, PM2) for production. Set `GEMMA_BIND=0.0.0.0` to listen on all interfaces. Use a reverse proxy (nginx, Caddy) for TLS.
|
|
712
|
+
|
|
713
|
+
---
|
|
714
|
+
|
|
715
|
+
## Project Structure
|
|
716
|
+
|
|
717
|
+
```
|
|
718
|
+
gemma/
|
|
719
|
+
src/
|
|
720
|
+
index.ts # CLI entry point, auth commands, setup wizard
|
|
721
|
+
gateway.ts # Main Gateway class, agent loop, lifecycle
|
|
722
|
+
config/
|
|
723
|
+
schema.ts # Zod config schema (all options)
|
|
724
|
+
loader.ts # JSON5 loading, env expansion, tilde expansion
|
|
725
|
+
defaults.ts # Default values
|
|
726
|
+
core/
|
|
727
|
+
session.ts # Session interface and creation
|
|
728
|
+
session-store.ts # File-based session persistence (JSONL)
|
|
729
|
+
compaction.ts # LLM-powered context summarization
|
|
730
|
+
logger.ts # Structured logger with ring buffer
|
|
731
|
+
llm/
|
|
732
|
+
types.ts # LLMProvider interface, Message, ToolCall types
|
|
733
|
+
gemini.ts # Gemini provider (dual endpoint, retry, fallback)
|
|
734
|
+
openai-compat.ts # OpenAI-compatible provider
|
|
735
|
+
auth/
|
|
736
|
+
resolver.ts # Auth mode detection and initialization
|
|
737
|
+
oauth.ts # OAuth flow (desktop + headless)
|
|
738
|
+
oauth-callback.ts # Local callback server for OAuth
|
|
739
|
+
token-store.ts # Token persistence and auto-refresh
|
|
740
|
+
types.ts # Auth types
|
|
741
|
+
channels/
|
|
742
|
+
types.ts # Channel interface
|
|
743
|
+
web.ts # HTTP server + WebSocket (700+ lines)
|
|
744
|
+
telegram.ts # grammY bot with inline keyboards
|
|
745
|
+
cli.ts # Readline interface
|
|
746
|
+
confirm/
|
|
747
|
+
gate.ts # Confirmation gate (security boundary)
|
|
748
|
+
auto-approve.ts # Auto-approve rule engine
|
|
749
|
+
audit.ts # JSONL audit logging
|
|
750
|
+
tools/
|
|
751
|
+
types.ts # Tool/ToolHandler interfaces, ToolContext
|
|
752
|
+
registry.ts # Tool registry with registerBuiltins()
|
|
753
|
+
executor.ts # Tool executor (only imported by gate.ts)
|
|
754
|
+
builtin/
|
|
755
|
+
read.ts, write.ts, edit.ts, exec.ts
|
|
756
|
+
web-search.ts, web-fetch.ts
|
|
757
|
+
cron.ts, panel.ts
|
|
758
|
+
mcp/
|
|
759
|
+
manager.ts # MCP server lifecycle management
|
|
760
|
+
adapter.ts # MCP tool -> Gemma tool adapter
|
|
761
|
+
skills/
|
|
762
|
+
loader.ts # SKILL.md discovery and parsing
|
|
763
|
+
gating.ts # Binary/env requirement checking
|
|
764
|
+
prompt-injector.ts # Skill list -> system prompt XML
|
|
765
|
+
panels/
|
|
766
|
+
registry.ts # Panel discovery and validation
|
|
767
|
+
routes.ts # HTTP routes for panel serving
|
|
768
|
+
types.ts # Panel manifest and service types
|
|
769
|
+
service-manager.ts # Panel service lifecycle
|
|
770
|
+
service-loader.ts # Dynamic ESM import with hot-reload
|
|
771
|
+
service-context.ts # Scoped context builder for services
|
|
772
|
+
sdk/
|
|
773
|
+
gemma-panel.js # Client-side panel SDK
|
|
774
|
+
automation/
|
|
775
|
+
heartbeat.ts # Periodic agent prompt timer
|
|
776
|
+
cron/
|
|
777
|
+
service.ts # CronService orchestrator
|
|
778
|
+
types.ts # Job, schedule, event types
|
|
779
|
+
schedule.ts # Next-run computation
|
|
780
|
+
parse-schedule.ts # Human-friendly schedule parsing
|
|
781
|
+
store.ts # JSON persistence
|
|
782
|
+
memory/
|
|
783
|
+
memory-manager.ts # Workspace file loading by scope
|
|
784
|
+
daily-log.ts # Daily log file management
|
|
785
|
+
shared/
|
|
786
|
+
ws-types.ts # WebSocket protocol types (38 message types)
|
|
787
|
+
ui/ # React SPA (separate build via Vite)
|
|
788
|
+
main.tsx # React entry
|
|
789
|
+
App.tsx # Root component
|
|
790
|
+
components/
|
|
791
|
+
AppShell.tsx # Layout shell (sidebar + content + statusbar)
|
|
792
|
+
Sidebar.tsx # Navigation + session list + panel widgets
|
|
793
|
+
StatusBar.tsx # Connection, model, cowboy mode indicators
|
|
794
|
+
views/ # ChatView, SettingsView, CronView, LogsView, PanelManagerView
|
|
795
|
+
ai/ # Conversation, MessageResponse, Reasoning, Shimmer, CodeBlock
|
|
796
|
+
chat/ # ConfirmationCard, ToolCallCard, ToolResultBadge
|
|
797
|
+
panels/ # PanelHost (tab), PanelSidebarSlot (sidebar)
|
|
798
|
+
settings/ # MCPServerCard, MCPServerForm
|
|
799
|
+
cron/ # CronJobCard, CronJobForm
|
|
800
|
+
ui/ # 19 shadcn/ui primitives
|
|
801
|
+
hooks/
|
|
802
|
+
useGateway.ts # Central WS hub (chat, streaming, sessions, model)
|
|
803
|
+
useConfig.ts # Config CRUD over WS
|
|
804
|
+
useSessions.ts # Session list management
|
|
805
|
+
usePanels.ts # Panel manifest fetching
|
|
806
|
+
useCron.ts # Cron job management
|
|
807
|
+
useLogs.ts # Log streaming
|
|
808
|
+
usePanelBridge.ts # iframe <-> WS bridge for panels
|
|
809
|
+
usePanelThemeBridge.ts # Theme sync to panel iframes
|
|
810
|
+
skills/ # Bundled skill definitions (SKILL.md files)
|
|
811
|
+
templates/
|
|
812
|
+
panel/ # HTML panel template
|
|
813
|
+
panel-react/ # React panel template (React 18 + Vite + TS)
|
|
814
|
+
*.md # Workspace templates (SOUL, INSTRUCTIONS, IDENTITY, etc.)
|
|
815
|
+
docker/
|
|
816
|
+
Dockerfile # Two-stage production build
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
### NPM Scripts
|
|
820
|
+
|
|
821
|
+
| Script | Description |
|
|
822
|
+
|--------|-------------|
|
|
823
|
+
| `npm run build` | Full build: TypeScript server + Vite React UI |
|
|
824
|
+
| `npm run build:server` | Server only: `tsc` -> `dist/` |
|
|
825
|
+
| `npm run build:ui` | UI only: `vite build` -> `dist/ui/` |
|
|
826
|
+
| `npm run dev` | Dev server: `tsx src/index.ts` |
|
|
827
|
+
| `npm run dev:ui` | UI dev server: Vite on :5173 with HMR |
|
|
828
|
+
|
|
829
|
+
### TypeScript Conventions
|
|
830
|
+
|
|
831
|
+
- **ESM only** (`"type": "module"`)
|
|
832
|
+
- All imports use `.js` extensions: `import { X } from './file.js'`
|
|
833
|
+
- Node imports use `node:` prefix: `import { readFile } from 'node:fs/promises'`
|
|
834
|
+
- Type-only imports: `import type { X } from './types.js'`
|
|
835
|
+
- Target: ES2023, Module: Node16, Strict mode
|
|
836
|
+
- Path alias: `@gemma/*` -> `./src/*` (server), `@/*` -> `./src/ui/*` (UI)
|
|
837
|
+
|
|
838
|
+
---
|
|
839
|
+
|
|
840
|
+
## Workspace Files
|
|
841
|
+
|
|
842
|
+
On first run, these template files are copied to `~/.gemma/workspace/`:
|
|
843
|
+
|
|
844
|
+
| File | Purpose |
|
|
845
|
+
|------|---------|
|
|
846
|
+
| `SOUL.md` | Personality and behavioral guidelines |
|
|
847
|
+
| `INSTRUCTIONS.md` | Operating rules and constraints |
|
|
848
|
+
| `IDENTITY.md` | Name, role, tone configuration |
|
|
849
|
+
| `USER.md` | User profile and preferences |
|
|
850
|
+
| `TOOLS.md` | Tool usage notes |
|
|
851
|
+
| `MEMORY.md` | Curated long-term memory |
|
|
852
|
+
| `BOOTSTRAP.md` | First-run welcome (deleted after first session) |
|
|
853
|
+
|
|
854
|
+
These files are loaded into the system prompt on every LLM call. Edit them to customize Gemma's behavior.
|
|
855
|
+
|
|
856
|
+
---
|
|
857
|
+
|
|
858
|
+
## License
|
|
859
|
+
|
|
860
|
+
[Add license here]
|