Skip to content

Commit d999423

Browse files
authored
docs: sync with goclaw source changes b1f6eadf..b9670555 (EN+VI+ZH) (#57)
P0 Breaking Changes: - tools-overview: web_search now tenant-only, removed config.json5 format - upgrading: add migrations 000048-055, tools.web.* removal callout P1 New Features: - security-hardening: exec grant enforcement section - skills: github:owner/repo[@tag] installer type - pancake: auto_react_options fields (allow/deny post/user IDs) - tts-voice: Voices API (GET/POST /v1/voices) + STT section P2 Accuracy Fixes: - context-pruning: fix pipeline diagram (remove pruneContextMessages) - docker-compose: chromedp/headless-shell:latest image - knowledge-vault: scope/ownership invariant section - rest-api: cancel-summon, system-prompt-preview, Voices endpoints
1 parent 71e4097 commit d999423

30 files changed

Lines changed: 692 additions & 66 deletions

advanced/context-pruning.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@ Context pruning is distinct from [session compaction](../core-concepts/sessions-
2020
Pruning is **opt-in** — it only runs when `mode: "cache-ttl"` is set on the agent. The flow:
2121

2222
```
23-
history → limitHistoryTurns → pruneContextMessages → sanitizeHistory → LLM
23+
history → limitHistoryTurns → sanitizeHistory → LLM
2424
```
2525

26+
> **Note:** `pruneContextMessages` (PruneStage) is **not** part of the main pipeline above. It runs opt-in and separately — only when `mode: "cache-ttl"` is set. The diagram above reflects the standard history preparation path.
27+
2628
Before each LLM call, GoClaw:
2729

2830
1. Counts tokens in all messages using the tiktoken BPE tokenizer (falls back to `chars / 4` heuristic when tiktoken is unavailable).
@@ -274,4 +276,4 @@ Tool output is now capped at the source before being added to context. Rather th
274276
- [Memory System](../core-concepts/memory-system.md) — 3-tier memory architecture and consolidation pipeline
275277
- [Configuration Reference](/config-reference) — full agent config reference
276278

277-
<!-- goclaw-source: 050aafc9 | updated: 2026-04-09 -->
279+
<!-- goclaw-source: b9670555 | updated: 2026-04-19 -->

advanced/knowledge-vault.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,28 @@ Documents are scoped by **tenant** (isolation boundary), **agent** (namespace),
5050
| `team` | Team workspace documents shared across team members |
5151
| `shared` | Cross-tenant shared knowledge (future) |
5252

53+
### Document Scope & Ownership Invariant
54+
55+
The `scope` field has a strict ownership invariant enforced at the database level by migration `000055` (`vault_documents_scope_consistency` CHECK constraint):
56+
57+
| `scope` | `agent_id` | `team_id` | Visibility |
58+
|---------|------------|-----------|------------|
59+
| `personal` | set | NULL | Owning agent only (within tenant) |
60+
| `team` | NULL | set | Members of the team (within tenant) |
61+
| `shared` | NULL | NULL | All agents within the tenant |
62+
| `custom` | any | any | User-defined via `custom_scope` |
63+
64+
The CHECK constraint rejects any INSERT or UPDATE that violates the `scope × agent_id × team_id` relationship above. `scope='custom'` is the exception — it is intentionally unconstrained, allowing user-defined ownership semantics.
65+
66+
#### Agent Read Semantics
67+
68+
`vault_search`, `ListDocuments`, and `CountDocuments` always return:
69+
70+
- Documents owned by the querying agent (`agent_id = <agent>`)
71+
- PLUS shared documents (`agent_id IS NULL`)
72+
73+
Within a team context (a `RunContext` with `TeamID` set), results also include team-scoped documents for that team (`scope = 'team'` with `team_id = <team>`). Tenant isolation (`tenant_id = <tenant>`) is always enforced regardless of scope.
74+
5375
---
5476

5577
## Data Model
@@ -391,4 +413,4 @@ No feature flag. Vault is active if the migration ran and VaultStore initialized
391413
- [Memory System](../core-concepts/memory-system.md) — Vector-based long-term memory
392414
- [Context Files](../agents/context-files.md) — Static documents injected into agent context
393415

394-
<!-- goclaw-source: 1296cdbf | updated: 2026-04-15 -->
416+
<!-- goclaw-source: b9670555 | updated: 2026-04-19 -->

advanced/skills.md

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,29 @@ GoClaw auto-detects and installs missing skill dependencies:
219219

220220
1. **Scanner** — statically analyzes `scripts/` subdirectory for Python (`import X`, `from X import`) and Node.js (`require('X')`, `import from 'X'`) imports
221221
2. **Checker** — verifies each import resolves at runtime via subprocess (`python3 -c "import X"` / `node -e "require.resolve('X')"`)
222-
3. **Installer** — installs by prefix: `pip:name``pip3 install`, `npm:name``npm install -g`, `apk:name``doas apk add`
222+
3. **Installer** — installs by prefix:
223+
224+
| Prefix | Effect |
225+
|--------|--------|
226+
| `pip:name` | `pip3 install` (Python package) |
227+
| `npm:name` | `npm install -g` (Node.js package) |
228+
| `system:name` | `apk add` via pkg-helper (system package) |
229+
| `github:owner/repo[@tag]` | GitHub Releases installer — admin-only, SHA256-verified, ELF-validated. Binary lands in `/app/data/.runtime/bin/` (on `$PATH`). |
230+
231+
Example SKILL.md frontmatter using `github:`:
232+
233+
```yaml
234+
---
235+
name: my-skill
236+
description: Does things using ripgrep and gh CLI.
237+
deps:
238+
- github:BurntSushi/ripgrep@14.1.0
239+
- github:cli/cli@v2.40.0
240+
- pip:requests
241+
---
242+
```
243+
244+
The `github:` installer fetches the release from GitHub Releases, auto-selects the `linux` + arch-matching asset (amd64 / arm64), verifies SHA256 if the publisher ships `checksums.txt`, validates ELF magic bytes, and extracts to `/app/data/.runtime/bin/`. If no `@tag` is specified, the latest release is used.
223245

224246
Dep checks run in a background goroutine at startup (non-blocking). Skills with missing deps are archived automatically; they are re-activated after deps are installed. You can also trigger a rescan via **Skills → Rescan Deps** in the Dashboard or `POST /v1/skills/rescan-deps`.
225247

@@ -399,4 +421,4 @@ See [Agent Evolution](agent-evolution.md) for full details on the `skill_manage`
399421
- [Custom Tools](/custom-tools) — add shell-backed tools to your agents
400422
- [Scheduling & Cron](/scheduling-cron) — run agents on a schedule
401423

402-
<!-- goclaw-source: 050aafc9 | updated: 2026-04-15 -->
424+
<!-- goclaw-source: b9670555 | updated: 2026-04-19 -->

advanced/tts-voice.md

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,91 @@ Each agent can override the global TTS voice and model via its `other_config` JS
255255

256256
---
257257

258+
## Voices API
259+
260+
GoClaw exposes HTTP endpoints for discovering available TTS voices. These are tenant-scoped and require tenant admin or operator role.
261+
262+
| Method | Path | Description |
263+
|--------|------|-------------|
264+
| `GET` | `/v1/voices` | List available voices (in-memory cached, TTL 1h) |
265+
| `POST` | `/v1/voices/refresh` | Force-invalidate the voice cache (admin only) |
266+
267+
### `GET /v1/voices`
268+
269+
Returns the voice list for the current tenant's configured ElevenLabs provider. Results are cached in-memory per tenant with a 1-hour TTL — shared across all HTTP and WebSocket handlers.
270+
271+
```json
272+
[
273+
{
274+
"voice_id": "pMsXgVXv3BLzUgSXRplE",
275+
"name": "Alice",
276+
"preview_url": "https://...",
277+
"category": "premade",
278+
"labels": {
279+
"use_case": "conversational",
280+
"accent": "american"
281+
}
282+
}
283+
]
284+
```
285+
286+
A cache miss triggers an immediate fetch from ElevenLabs. Returns `500` if the provider is unreachable.
287+
288+
### `POST /v1/voices/refresh`
289+
290+
Invalidates the voice cache for the current tenant so the next `GET /v1/voices` request fetches a fresh list from the provider. Useful after adding voices to your ElevenLabs account or after CDN expiry.
291+
292+
```json
293+
{ "message": "voice cache invalidated" }
294+
```
295+
296+
Response is `202 Accepted`.
297+
298+
---
299+
300+
## Speech-to-Text (STT)
301+
302+
GoClaw routes all voice/audio transcription through a unified `audio.Manager` with a provider chain. Channels (Telegram, Discord, Feishu, WhatsApp) share the same STT infrastructure.
303+
304+
### Unified Transcription Flow
305+
306+
```mermaid
307+
flowchart TD
308+
VOICE["Voice/audio message"] --> ROUTE{Channel type?}
309+
310+
ROUTE -->|Telegram / Discord / Feishu| DOWNLOAD["Download audio file"]
311+
ROUTE -->|WhatsApp| WA_CHECK{"whatsapp_enabled\nin settings?"}
312+
313+
WA_CHECK -->|No| WA_FALLBACK["[Voice message]\n(default opt-out)"]
314+
WA_CHECK -->|Yes| DOWNLOAD
315+
316+
DOWNLOAD --> STT_CHECK{"STT providers\nconfigured?"}
317+
STT_CHECK -->|Yes| STT_CHAIN["Try providers in order:\nelevenlabs_scribe, proxy"]
318+
STT_CHECK -->|No| FALLBACK["[Voice message]"]
319+
320+
STT_CHAIN -->|Success| TEXT["Transcribed text\n→ agent context"]
321+
STT_CHAIN -->|Fail / 10s timeout| FALLBACK
322+
```
323+
324+
### WhatsApp Opt-In
325+
326+
WhatsApp STT is **off by default** (`whatsapp_enabled: false`). Rationale: WhatsApp voice messages are end-to-end encrypted. Sending audio bytes to an external STT provider breaks E2E encryption. Admins must explicitly enable it in **Config → Audio → STT** and acknowledge the E2E breaking change.
327+
328+
When disabled (default): voice messages appear in agent context as `[Voice message]` — no audio leaves the device.
329+
When enabled: audio is transcribed via the configured STT chain; falls back to `[Voice message]` on failure or timeout (10 s wall clock).
330+
331+
### STT Provider Chain
332+
333+
| Setting | Behavior |
334+
|---------|----------|
335+
| `providers: ["elevenlabs_scribe", "proxy_stt"]` | Try ElevenLabs Scribe first; fall back to legacy proxy |
336+
| `providers: []` (empty) | Skip all STT; voice → `[Voice message]` |
337+
| `providers` missing (nil) | Check for legacy `STTProxyURL` bridge at startup |
338+
339+
Configure via **Config → Audio → STT** in the web UI (stored in `builtin_tools[stt].settings.providers`). When this list is present it overrides all legacy channel-specific STT configs.
340+
341+
---
342+
258343
## STT Builtin Tool
259344

260345
The `stt` builtin tool (seeded by migration 050) enables agents to transcribe voice/audio input using ElevenLabs Scribe or a compatible proxy — see [Tools Overview](/tools-overview) for how to enable and configure it.
@@ -280,4 +365,4 @@ The `stt` builtin tool (seeded by migration 050) enables agents to transcribe vo
280365
- [Scheduling & Cron](/scheduling-cron) — trigger agents on a schedule
281366
- [Extended Thinking](/extended-thinking) — deeper reasoning for complex replies
282367

283-
<!-- goclaw-source: 050aafc9 | updated: 2026-04-17 -->
368+
<!-- goclaw-source: b9670555 | updated: 2026-04-19 -->

channels/pancake.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ For config-file-based channels (instead of DB instances):
8989
| `features.comment_reply` | bool | -- | Enable comment replies |
9090
| `features.first_inbox` | bool | -- | Send a one-time DM to a commenter after their first comment reply |
9191
| `features.auto_react` | bool | -- | Auto-like user comments on Facebook (Facebook only) |
92+
| `auto_react_options.allow_post_ids` | list | -- | Only react to comments on these post IDs (nil = all posts) |
93+
| `auto_react_options.deny_post_ids` | list | -- | Never react to comments on these post IDs (overrides allow) |
94+
| `auto_react_options.allow_user_ids` | list | -- | Only react to comments from these user IDs (nil = all users) |
95+
| `auto_react_options.deny_user_ids` | list | -- | Never react to comments from these user IDs (overrides allow) |
9296
| `comment_reply_options.include_post_context` | bool | false | Prepend post text to comment content sent to the agent |
9397
| `comment_reply_options.filter` | string | `"all"` | Comment filter mode: `"all"` or `"keyword"` |
9498
| `comment_reply_options.keywords` | list | -- | Required when `filter="keyword"` — only process comments containing these keywords |
@@ -232,6 +236,17 @@ When `features.comment_reply: true`, additional options control comment handling
232236

233237
**Auto-react** (`features.auto_react: true`): automatically likes every valid incoming comment on Facebook (Facebook platform only). Fires independently of `comment_reply` — you can react without replying.
234238

239+
Scope the reactions further with `auto_react_options`:
240+
241+
| Field | Type | Behavior |
242+
|-------|------|----------|
243+
| `allow_post_ids` | list | React only on comments for these post IDs (nil = all posts) |
244+
| `deny_post_ids` | list | Never react on these post IDs (overrides allow) |
245+
| `allow_user_ids` | list | React only to comments from these user IDs (nil = all users) |
246+
| `deny_user_ids` | list | Never react to comments from these user IDs (overrides allow) |
247+
248+
Deny lists always take precedence over allow lists. Omitting `auto_react_options` entirely means no scope filter (react to all valid comments).
249+
235250
**First inbox** (`features.first_inbox: true`): after replying to a comment, sends a one-time private DM to the commenter inviting them to continue via inbox. Only sent once per sender per session restart. Customize the DM text with `first_inbox_message`.
236251

237252
### Channel Health
@@ -268,4 +283,4 @@ Application-level failures (HTTP 200 with `success: false` in JSON body) are als
268283
- [Telegram](/channel-telegram) — Telegram bot setup
269284
- [Multi-Channel Setup](/recipe-multi-channel) — Configure multiple channels
270285

271-
<!-- goclaw-source: 050aafc9 | updated: 2026-04-17 -->
286+
<!-- goclaw-source: b9670555 | updated: 2026-04-19 -->

core-concepts/tools-overview.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,21 @@ Tools are how agents interact with the world beyond generating text. An agent ca
3838
| **Brave** | Requires `BRAVE_API_KEY` |
3939
| **DuckDuckGo** | Free fallback — used last if no API keys for the others |
4040

41-
Configure provider order via `provider_order` in tool settings:
41+
> **Breaking change (v3.2+):** `config.json5 tools.web.*` has been removed. Configuration is now tenant-only. Existing keys are auto-migrated on first startup (data hook 055).
4242
43-
```json
43+
Configure `web_search` via the dashboard (**Config → Tools → Web Search**) or the API:
44+
45+
```bash
46+
# Set provider order via tenant-config API
47+
PUT /v1/tools/builtin/web_search/tenant-config
4448
{
45-
"tools": {
46-
"web_search": {
47-
"provider_order": ["exa", "tavily", "brave", "duckduckgo"]
48-
}
49-
}
49+
"provider_order": ["exa", "tavily", "brave", "duckduckgo"],
50+
"brave": { "enabled": true, "max_results": 5 },
51+
"exa": { "enabled": false }
5052
}
5153
```
5254
53-
DuckDuckGo requires no API key and is always available as the final fallback.
55+
DuckDuckGo requires no API key and is always available as the final fallback — it cannot be disabled.
5456
5557
### v3 Memory & Vault Tools
5658
@@ -310,4 +312,4 @@ All parameters are optional — defaults apply when not configured.
310312
- [Multi-Tenancy](/multi-tenancy) — Per-user tool access and isolation
311313
- [Custom Tools](/custom-tools) — Build your own tools
312314
313-
<!-- goclaw-source: 050aafc9 | updated: 2026-04-09 -->
315+
<!-- goclaw-source: b9670555 | updated: 2026-04-19 -->

deployment/docker-compose.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ Mounts `/var/run/docker.sock` so GoClaw can spin up isolated containers for agen
185185

186186
### `docker-compose.browser.yml`
187187

188-
Starts `zenika/alpine-chrome:124` with CDP enabled on port 9222. GoClaw connects via `GOCLAW_BROWSER_REMOTE_URL=ws://chrome:9222`.
188+
Starts `chromedp/headless-shell:latest` with CDP enabled on port 9222. GoClaw connects via `GOCLAW_BROWSER_REMOTE_URL=ws://chrome:9222`.
189189

190190
### `docker-compose.otel.yml`
191191

@@ -464,4 +464,4 @@ docker pull ghcr.io/nextlevelbuilder/goclaw:otel
464464
- [Observability](/deploy-observability) — OpenTelemetry and Jaeger configuration
465465
- [Tailscale](/deploy-tailscale) — secure remote access via Tailscale
466466

467-
<!-- goclaw-source: 050aafc9 | updated: 2026-04-09 -->
467+
<!-- goclaw-source: b9670555 | updated: 2026-04-19 -->

deployment/security-hardening.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,28 @@ For tools that need credentials (e.g., `gh`, `aws`), GoClaw uses direct process
152152

153153
Shell metacharacters (`;`, `|`, `&`, `$()`, backticks) are detected and rejected before execution.
154154

155+
### Exec grant enforcement
156+
157+
Agent-level grant enforcement runs **before** any process spawn, blocking ungranted agents from executing registered binaries:
158+
159+
| Control | Detail |
160+
|---------|--------|
161+
| **Grant lookup** | `store.SecureCLIStore.IsRegisteredBinary()` checks the `secure_cli_agent_grants` table. Non-global binaries require a row for the calling agent. |
162+
| **Fail-closed** | If the grant lookup errors (DB down, timeout), exec is denied with a retry message. Per-lookup timeout: 2 seconds. |
163+
| **Env scrubbing** | When a command bypasses the credentialed path (e.g., via adversarial use of the `exec` tool), the child process environment is scrubbed of all credential keys before spawn — static deny list plus dynamic keys from every registered binary in the tenant. |
164+
| **Wrapper unwrap** | Shell wrappers (`sh -c`, `bash -c`, etc.) that attempt to evade binary path matching are blocked. GoClaw checks up to 3 levels of nesting; deeper chains are rejected as adversarial. |
165+
| **Subagent wiring** | Subagent `ExecTool`s use the same `SecureCLIStore` via `buildSubagentToolsRegistry`. Parent agents cannot bypass the gate by delegating exec to spawned subagents. |
166+
167+
Security log events emitted by the grant gate:
168+
169+
| Event | Meaning |
170+
|-------|---------|
171+
| `security.credentialed_binary_denied` | Agent attempted to run a binary it has no grant for |
172+
| `security.credentialed_binary_gate_error` | Grant lookup failed (DB error); exec denied |
173+
| `security.credentialed_binary_wrapper_too_deep` | Shell wrapper nesting exceeded 3 levels; rejected as adversarial |
174+
175+
All three events include: `binary`, `wrapper`, `agent_id`, `tenant_id`, and `command` prefix fields.
176+
155177
### Shell output limit
156178

157179
Host-executed commands have stdout and stderr capped at **1 MB** each. If a command exceeds this limit, output is truncated with a flag to prevent further writes. Sandboxed execution uses Docker container limits instead.
@@ -478,6 +500,9 @@ All security events log at `slog.Warn` with a `security.*` prefix:
478500
| `security.rate_limited` | Request rejected by rate limiter |
479501
| `security.cors_rejected` | WebSocket connection rejected by CORS policy |
480502
| `security.message_truncated` | Message truncated at `max_message_chars` |
503+
| `security.credentialed_binary_denied` | Agent attempted exec without a grant |
504+
| `security.credentialed_binary_gate_error` | Grant lookup failed; exec denied fail-closed |
505+
| `security.credentialed_binary_wrapper_too_deep` | Shell wrapper nesting > 3 levels rejected |
481506

482507
Filter all security events:
483508

@@ -509,4 +534,4 @@ journalctl -u goclaw | grep 'security\.'
509534
- [Docker Compose](./docker-compose.md) — deploying with security settings via compose overlays
510535
- [Database Setup](./database-setup.md) — PostgreSQL TLS and encrypted secret storage
511536

512-
<!-- goclaw-source: 050aafc9 | updated: 2026-04-09 -->
537+
<!-- goclaw-source: b9670555 | updated: 2026-04-19 -->

deployment/upgrading.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,10 +208,12 @@ Only do this if you understand what the failed migration was doing. When in doub
208208
209209
## Recent Migrations
210210

211-
### v3 Migrations (037–044) — v2→v3 Upgrade Guide
211+
### v3 Migrations (037–055) — v2→v3 Upgrade Guide
212212

213213
These migrations are applied automatically via `./goclaw upgrade`. They constitute the **v3 major release**. Read the breaking changes below before upgrading from v2.
214214

215+
Migrations 048–055 introduce the vault media linking, vault scope consistency enforcement, agent hooks system (phases 1–4), and the `web_search` tenant-config migration. No manual steps are required — data hook 055 auto-migrates any API keys from legacy `config.json5 tools.web.*` and `builtin_tool_tenant_configs.settings` blobs to `config_secrets` on first startup.
216+
215217
| Version | What changed |
216218
|---------|-------------|
217219
| 037 | **V3 memory evolution** — creates `episodic_summaries`, `agent_evolution_metrics`, `agent_evolution_suggestions`; adds `valid_from`/`valid_until` to KG tables; promotes 12 agent fields from `other_config` JSONB to dedicated columns |
@@ -247,6 +249,7 @@ These migrations are applied automatically via `./goclaw upgrade`. They constitu
247249
| Team workspace files: file tools auto-resolve | `read_file`/`write_file` targeting team workspace paths work directly | None — transparent |
248250
| Store unification (`internal/store/base/`) | Internal refactor only | None — no schema or config changes |
249251
| Gateway decomposed into modules | Internal refactor only | None |
252+
| `config.json5 tools.web.*` removed | `web_search` is now tenant-only; global path no longer parsed | Remove `tools.web.*` from `config.json5`; configure via **Config → Tools → Web Search** UI or `/v1/tools/builtin/web_search/tenant-config` API. API keys auto-migrated on startup (hook 055) |
250253

251254
### v2.x Migrations (024–032)
252255

@@ -321,4 +324,4 @@ Before each upgrade, check the release notes for:
321324
- [Database Setup](/deploy-database) — PostgreSQL and pgvector setup
322325
- [Observability](/deploy-observability) — monitor your gateway post-upgrade
323326

324-
<!-- goclaw-source: 050aafc9 | updated: 2026-04-17 -->
327+
<!-- goclaw-source: b9670555 | updated: 2026-04-19 -->

0 commit comments

Comments
 (0)