Merge remote-tracking branch 'origin/main' into feature/agent-avatar-support

This commit is contained in:
Peter Steinberger
2026-01-22 06:03:56 +00:00
84 changed files with 1323 additions and 381 deletions

View File

@@ -69,11 +69,13 @@ High-level:
1. Requires a clean worktree (no uncommitted changes).
2. Switches to the selected channel (tag or branch).
3. Fetches and rebases against `@{upstream}` (dev only).
4. Installs deps (pnpm preferred; npm fallback).
5. Builds + builds the Control UI.
6. Runs `clawdbot doctor` as the final “safe update” check.
7. Syncs plugins to the active channel (dev uses bundled extensions; stable/beta uses npm) and updates npm-installed plugins.
3. Fetches upstream (dev only).
4. Dev only: preflight lint + TypeScript build in a temp worktree; if the tip fails, walks back up to 10 commits to find the newest clean build.
5. Rebases onto the selected commit (dev only).
6. Installs deps (pnpm preferred; npm fallback).
7. Builds + builds the Control UI.
8. Runs `clawdbot doctor` as the final “safe update” check.
9. Syncs plugins to the active channel (dev uses bundled extensions; stable/beta uses npm) and updates npm-installed plugins.
## `--update` shorthand

View File

@@ -24,7 +24,7 @@ The prompt is intentionally compact and uses fixed sections:
- **Current Date & Time**: user-local time, timezone, and time format.
- **Reply Tags**: optional reply tag syntax for supported providers.
- **Heartbeats**: heartbeat prompt and ack behavior.
- **Runtime**: host, OS, node, model, thinking level (one line).
- **Runtime**: host, OS, node, model, repo root (when detected), thinking level (one line).
- **Reasoning**: current visibility level + /reasoning toggle hint.
## Prompt modes

View File

@@ -9,15 +9,15 @@ read_when:
Clawdbot standardizes timestamps so the model sees a **single reference time**.
## Message envelopes (UTC by default)
## Message envelopes (local by default)
Inbound messages are wrapped in an envelope like:
```
[Provider ... 2026-01-05T21:26Z] message text
[Provider ... 2026-01-05 16:26 PST] message text
```
The timestamp in the envelope is **UTC by default**, with minutes precision.
The timestamp in the envelope is **host-local by default**, with minutes precision.
You can override this with:
@@ -25,7 +25,7 @@ You can override this with:
{
agents: {
defaults: {
envelopeTimezone: "user", // "utc" | "local" | "user" | IANA timezone
envelopeTimezone: "local", // "utc" | "local" | "user" | IANA timezone
envelopeTimestamp: "on", // "on" | "off"
envelopeElapsed: "on" // "on" | "off"
}
@@ -33,6 +33,7 @@ You can override this with:
}
```
- `envelopeTimezone: "utc"` uses UTC.
- `envelopeTimezone: "user"` uses `agents.defaults.userTimezone` (falls back to host timezone).
- Use an explicit IANA timezone (e.g., `"Europe/Vienna"`) for a fixed offset.
- `envelopeTimestamp: "off"` removes absolute timestamps from envelope headers.
@@ -40,10 +41,10 @@ You can override this with:
### Examples
**UTC (default):**
**Local (default):**
```
[Signal Alice +1555 2026-01-18T05:19Z] hello
[Signal Alice +1555 2026-01-18 00:19 PST] hello
```
**Fixed timezone:**

View File

@@ -7,18 +7,18 @@ read_when:
# Date & Time
Clawdbot defaults to **UTC for transport timestamps** and **user-local time only in the system prompt**.
Clawdbot defaults to **host-local time for transport timestamps** and **user-local time only in the system prompt**.
Provider timestamps are preserved so tools keep their native semantics.
## Message envelopes (UTC by default)
## Message envelopes (local by default)
Inbound messages are wrapped with a UTC timestamp (minute precision):
Inbound messages are wrapped with a timestamp (minute precision):
```
[Provider ... 2026-01-05T21:26Z] message text
[Provider ... 2026-01-05 16:26 PST] message text
```
This envelope timestamp is **UTC by default**, regardless of the host timezone.
This envelope timestamp is **host-local by default**, regardless of the provider timezone.
You can override this behavior:
@@ -26,7 +26,7 @@ You can override this behavior:
{
agents: {
defaults: {
envelopeTimezone: "utc", // "utc" | "local" | "user" | IANA timezone
envelopeTimezone: "local", // "utc" | "local" | "user" | IANA timezone
envelopeTimestamp: "on", // "on" | "off"
envelopeElapsed: "on" // "on" | "off"
}
@@ -34,6 +34,7 @@ You can override this behavior:
}
```
- `envelopeTimezone: "utc"` uses UTC.
- `envelopeTimezone: "local"` uses the host timezone.
- `envelopeTimezone: "user"` uses `agents.defaults.userTimezone` (falls back to host timezone).
- Use an explicit IANA timezone (e.g., `"America/Chicago"`) for a fixed zone.
@@ -42,10 +43,10 @@ You can override this behavior:
### Examples
**UTC (default):**
**Local (default):**
```
[WhatsApp +1555 2026-01-18T05:19Z] hello
[WhatsApp +1555 2026-01-18 00:19 PST] hello
```
**User timezone:**
@@ -73,12 +74,13 @@ Time format: 12-hour
If only the timezone is known, we still include the section and instruct the model
to assume UTC for unknown time references.
## System event lines (UTC)
## System event lines (local by default)
Queued system events inserted into agent context are prefixed with a UTC timestamp:
Queued system events inserted into agent context are prefixed with a timestamp using the
same timezone selection as message envelopes (default: host-local).
```
System: [2026-01-12T20:19:17Z] Model switched.
System: [2026-01-12 12:19:17 PST] Model switched.
```
### Configure user timezone + format

View File

@@ -1280,6 +1280,18 @@ Default: `~/clawd`.
If `agents.defaults.sandbox` is enabled, non-main sessions can override this with their
own per-scope workspaces under `agents.defaults.sandbox.workspaceRoot`.
### `agents.defaults.repoRoot`
Optional repository root to show in the system prompts Runtime line. If unset, Clawdbot
tries to detect a `.git` directory by walking upward from the workspace (and current
working directory). The path must exist to be used.
```json5
{
agents: { defaults: { repoRoot: "~/Projects/clawdbot" } }
}
```
### `agents.defaults.skipBootstrap`
Disables automatic creation of the workspace bootstrap files (`AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, and `BOOTSTRAP.md`).
@@ -1983,7 +1995,7 @@ Per-agent override (further restrict):
Notes:
- `tools.elevated` is the global baseline. `agents.list[].tools.elevated` can only further restrict (both must allow).
- `/elevated on|off` stores state per session key; inline directives apply to a single message.
- `/elevated on|off|ask|full` stores state per session key; inline directives apply to a single message.
- Elevated `exec` runs on the host and bypasses sandboxing.
- Tool policy still applies; if `exec` is denied, elevated cannot be used.

View File

@@ -91,7 +91,8 @@ Available groups:
## Elevated: exec-only “run on host”
Elevated does **not** grant extra tools; it only affects `exec`.
- If youre sandboxed, `/elevated on` (or `exec` with `elevated: true`) runs on the host.
- If youre sandboxed, `/elevated on` (or `exec` with `elevated: true`) runs on the host (approvals may still apply).
- Use `/elevated full` to skip exec approvals for the session.
- If youre already running direct, elevated is effectively a no-op (still gated).
- Elevated is **not** skill-scoped and does **not** override tool allow/deny.

View File

@@ -178,6 +178,20 @@ Even with strong system prompts, **prompt injection is not solved**. What helps
- Run sensitive tool execution in a sandbox; keep secrets out of the agents reachable filesystem.
- **Model choice matters:** older/legacy models can be less robust against prompt injection and tool misuse. Prefer modern, instruction-hardened models for any bot with tools. We recommend Anthropic Opus 4.5 because its quite good at recognizing prompt injections (see [“A step forward on safety”](https://www.anthropic.com/news/claude-opus-4-5)).
### Prompt injection does not require public DMs
Even if **only you** can message the bot, prompt injection can still happen via
any **untrusted content** the bot reads (web search/fetch results, browser pages,
emails, docs, attachments, pasted logs/code). In other words: the sender is not
the only threat surface; the **content itself** can carry adversarial instructions.
When tools are enabled, the typical risk is exfiltrating context or triggering
tool calls. Reduce the blast radius by:
- Using a read-only or tool-disabled **reader agent** to summarize untrusted content,
then pass the summary to your main agent.
- Keeping `web_search` / `web_fetch` / `browser` off for tool-enabled agents unless needed.
- Enabling sandboxing and strict tool allowlists for any agent that touches untrusted input.
### Model strength (security note)
Prompt injection resistance is **not** uniform across model tiers. Smaller/cheaper models are generally more susceptible to tool misuse and instruction hijacking, especially under adversarial prompts.
@@ -187,6 +201,7 @@ Recommendations:
- **Avoid weaker tiers** (for example, Sonnet or Haiku) for tool-enabled agents or untrusted inboxes.
- If you must use a smaller model, **reduce blast radius** (read-only tools, strong sandboxing, minimal filesystem access, strict allowlists).
- When running small models, **enable sandboxing for all sessions** and **disable web_search/web_fetch/browser** unless inputs are tightly controlled.
- For chat-only personal assistants with trusted input and no tools, smaller models are usually fine.
## Reasoning & verbose output in groups

View File

@@ -53,6 +53,15 @@ Almost always a Node/npm PATH issue. Start here:
- [Models](/cli/models)
- [OAuth / auth concepts](/concepts/oauth)
### `/model` says `model not allowed`
This usually means `agents.defaults.models` is configured as an allowlist. When its non-empty,
only those provider/model keys can be selected.
- Check the allowlist: `clawdbot config get agents.defaults.models`
- Add the model you want (or clear the allowlist) and retry `/model`
- Use `/models` to browse the allowed providers/models
### When filing an issue
Paste a safe report:

View File

@@ -155,18 +155,21 @@ Quick diagnosis:
```bash
node -v
npm -v
npm bin -g
npm prefix -g
echo "$PATH"
```
If the output of `npm bin -g` is **not** present inside `echo "$PATH"`, your shell cant find global npm binaries (including `clawdbot`).
If `$(npm prefix -g)/bin` (macOS/Linux) or `$(npm prefix -g)` (Windows) is **not** present inside `echo "$PATH"`, your shell cant find global npm binaries (including `clawdbot`).
Fix: add it to your shell startup file (zsh: `~/.zshrc`, bash: `~/.bashrc`):
```bash
export PATH="/path/from/npm/bin/-g:$PATH"
# macOS / Linux
export PATH="$(npm prefix -g)/bin:$PATH"
```
On Windows, add the output of `npm prefix -g` to your PATH.
Then open a new terminal (or `rehash` in zsh / `hash -r` in bash).
## Update / uninstall

View File

@@ -19,33 +19,36 @@ Run:
```bash
node -v
npm -v
npm bin -g
npm prefix -g
echo "$PATH"
```
If the output of `npm bin -g` is **not** present inside `echo "$PATH"`, your shell cant find global npm binaries (including `clawdbot`).
If `$(npm prefix -g)/bin` (macOS/Linux) or `$(npm prefix -g)` (Windows) is **not** present inside `echo "$PATH"`, your shell cant find global npm binaries (including `clawdbot`).
## Fix: put npms global bin dir on PATH
1) Find your global bin directory:
1) Find your global npm prefix:
```bash
npm bin -g
npm prefix -g
```
2) Add it to your shell startup file:
2) Add the global npm bin directory to your shell startup file:
- zsh: `~/.zshrc`
- bash: `~/.bashrc`
Example (replace the path with your `npm bin -g` output):
Example (replace the path with your `npm prefix -g` output):
```bash
export PATH="/path/from/npm/bin/-g:$PATH"
# macOS / Linux
export PATH="/path/from/npm/prefix/bin:$PATH"
```
Then open a **new terminal** (or run `rehash` in zsh / `hash -r` in bash).
On Windows, add the output of `npm prefix -g` to your PATH.
## Fix: avoid `sudo npm install -g` / permission errors (Linux)
If `npm install -g ...` fails with `EACCES`, switch npms global prefix to a user-writable directory:
@@ -63,7 +66,7 @@ Persist the `export PATH=...` line in your shell startup file.
Youll have the fewest surprises if Node/npm are installed in a way that:
- keeps Node updated (22+)
- makes `npm bin -g` stable and on PATH in new shells
- makes the global npm bin dir stable and on PATH in new shells
Common choices:

View File

@@ -216,7 +216,7 @@ Option B:
## Slash commands
- `/exec host=<sandbox|gateway|node> security=<deny|allowlist|full> ask=<off|on-miss|always> node=<id>`
- Per-agent, per-session overrides; non-persistent unless saved via config.
- `/elevated on|off` remains a shortcut for `host=gateway security=full`.
- `/elevated on|off|ask|full` remains a shortcut for `host=gateway security=full` (with `full` skipping approvals).
## Cross-platform story
- The runner service is the portable execution target.

View File

@@ -117,6 +117,8 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS,
- [My skill generated an image/PDF, but nothing was sent](#my-skill-generated-an-imagepdf-but-nothing-was-sent)
- [Security and access control](#security-and-access-control)
- [Is it safe to expose Clawdbot to inbound DMs?](#is-it-safe-to-expose-clawdbot-to-inbound-dms)
- [Is prompt injection only a concern for public bots?](#is-prompt-injection-only-a-concern-for-public-bots)
- [Can I use cheaper models for personal assistant tasks?](#can-i-use-cheaper-models-for-personal-assistant-tasks)
- [I ran `/start` in Telegram but didnt get a pairing code](#i-ran-start-in-telegram-but-didnt-get-a-pairing-code)
- [WhatsApp: will it message my contacts? How does pairing work?](#whatsapp-will-it-message-my-contacts-how-does-pairing-work)
- [Chat commands, aborting tasks, and “it wont stop”](#chat-commands-aborting-tasks-and-it-wont-stop)
@@ -1539,6 +1541,28 @@ Treat inbound DMs as untrusted input. Defaults are designed to reduce risk:
Run `clawdbot doctor` to surface risky DM policies.
### Is prompt injection only a concern for public bots?
No. Prompt injection is about **untrusted content**, not just who can DM the bot.
If your assistant reads external content (web search/fetch, browser pages, emails,
docs, attachments, pasted logs), that content can include instructions that try
to hijack the model. This can happen even if **you are the only sender**.
The biggest risk is when tools are enabled: the model can be tricked into
exfiltrating context or calling tools on your behalf. Reduce the blast radius by:
- using a read-only or tool-disabled "reader" agent to summarize untrusted content
- keeping `web_search` / `web_fetch` / `browser` off for tool-enabled agents
- sandboxing and strict tool allowlists
Details: [Security](/gateway/security).
### Can I use cheaper models for personal assistant tasks?
Yes, **if** the agent is chat-only and the input is trusted. Smaller tiers are
more susceptible to instruction hijacking, so avoid them for tool-enabled agents
or when reading untrusted content. If you must use a smaller model, lock down
tools and run inside a sandbox. See [Security](/gateway/security).
### I ran `/start` in Telegram but didnt get a pairing code
Pairing codes are sent **only** when an unknown sender messages the bot and

View File

@@ -6,17 +6,20 @@ read_when:
# Elevated Mode (/elevated directives)
## What it does
- `/elevated on` is a **shortcut** for `exec.host=gateway` + `exec.security=full`.
- `/elevated on` is a **shortcut** for `exec.host=gateway` + `exec.security=full` (approvals still apply).
- `/elevated full` runs on the gateway host **and** auto-approves exec (skips exec approvals).
- `/elevated ask` runs on the gateway host but keeps exec approvals (same as `/elevated on`).
- Only changes behavior when the agent is **sandboxed** (otherwise exec already runs on the host).
- Directive forms: `/elevated on`, `/elevated off`, `/elev on`, `/elev off`.
- Only `on|off` are accepted; anything else returns a hint and does not change state.
- Directive forms: `/elevated on|off|ask|full`, `/elev on|off|ask|full`.
- Only `on|off|ask|full` are accepted; anything else returns a hint and does not change state.
## What it controls (and what it doesnt)
- **Availability gates**: `tools.elevated` is the global baseline. `agents.list[].tools.elevated` can further restrict elevated per agent (both must allow).
- **Per-session state**: `/elevated on|off` sets the elevated level for the current session key.
- **Inline directive**: `/elevated on` inside a message applies to that message only.
- **Per-session state**: `/elevated on|off|ask|full` sets the elevated level for the current session key.
- **Inline directive**: `/elevated on|ask|full` inside a message applies to that message only.
- **Groups**: In group chats, elevated directives are only honored when the agent is mentioned. Command-only messages that bypass mention requirements are treated as mentioned.
- **Host execution**: elevated forces `exec` onto the gateway host with full security.
- **Approvals**: `full` skips exec approvals; `on`/`ask` still honor them.
- **Unsandboxed agents**: no-op for location; only affects gating, logging, and status.
- **Tool policy still applies**: if `exec` is denied by tool policy, elevated cannot be used.
@@ -26,8 +29,8 @@ read_when:
3. Global default (`agents.defaults.elevatedDefault` in config).
## Setting a session default
- Send a message that is **only** the directive (whitespace allowed), e.g. `/elevated on`.
- Confirmation reply is sent (`Elevated mode enabled.` / `Elevated mode disabled.`).
- Send a message that is **only** the directive (whitespace allowed), e.g. `/elevated full`.
- Confirmation reply is sent (`Elevated mode set to full...` / `Elevated mode disabled.`).
- If elevated access is disabled or the sender is not on the approved allowlist, the directive replies with an actionable error and does not change session state.
- Send `/elevated` (or `/elevated:`) with no argument to see the current elevated level.
@@ -41,4 +44,4 @@ read_when:
## Logging + status
- Elevated exec calls are logged at info level.
- Session status includes elevated mode (e.g. `elevated=on`).
- Session status includes elevated mode (e.g. `elevated=ask`, `elevated=full`).

View File

@@ -11,7 +11,7 @@ read_when:
Exec approvals are the **companion app / node host guardrail** for letting a sandboxed agent run
commands on a real host (`gateway` or `node`). Think of it like a safety interlock:
commands are allowed only when policy + allowlist + (optional) user approval all agree.
Exec approvals are **in addition** to tool policy and elevated gating.
Exec approvals are **in addition** to tool policy and elevated gating (unless elevated is set to `full`, which skips approvals).
If the companion app UI is **not available**, any request that requires a prompt is
resolved by the **ask fallback** (default: deny).
@@ -88,6 +88,7 @@ If a prompt is required but no UI is reachable, fallback decides:
Allowlists are **per agent**. If multiple agents exist, switch which agent youre
editing in the macOS app. Patterns are **case-insensitive glob matches**.
Patterns should resolve to **binary paths** (basename-only entries are ignored).
Legacy `agents.default` entries are migrated to `agents.main` on load.
Examples:
- `~/Projects/**/bin/bird`

View File

@@ -78,7 +78,7 @@ Text + native (when enabled):
- `/think <off|minimal|low|medium|high|xhigh>` (dynamic choices by model/provider; aliases: `/thinking`, `/t`)
- `/verbose on|full|off` (alias: `/v`)
- `/reasoning on|off|stream` (alias: `/reason`; when on, sends a separate message prefixed `Reasoning:`; `stream` = Telegram draft only)
- `/elevated on|off` (alias: `/elev`)
- `/elevated on|off|ask|full` (alias: `/elev`; `full` skips exec approvals)
- `/exec host=<sandbox|gateway|node> security=<deny|allowlist|full> ask=<off|on-miss|always> node=<id>` (send `/exec` to show current)
- `/model <name>` (alias: `/models`; or `/<alias>` from `agents.defaults.models.*.alias`)
- `/queue <mode>` (plus options like `debounce:2s cap:25 drop:summarize`; send `/queue` to see current settings)

View File

@@ -78,7 +78,7 @@ Session controls:
- `/verbose <on|full|off>`
- `/reasoning <on|off|stream>`
- `/usage <off|tokens|full>`
- `/elevated <on|off>` (alias: `/elev`)
- `/elevated <on|off|ask|full>` (alias: `/elev`)
- `/activation <mention|always>`
- `/deliver <on|off>`

View File

@@ -134,3 +134,29 @@ pnpm ui:dev # auto-installs UI deps on first run
```
Then point the UI at your Gateway WS URL (e.g. `ws://127.0.0.1:18789`).
## Debugging/testing: dev server + remote Gateway
The Control UI is static files; the WebSocket target is configurable and can be
different from the HTTP origin. This is handy when you want the Vite dev server
locally but the Gateway runs elsewhere.
1) Start the UI dev server: `pnpm ui:dev`
2) Open a URL like:
```text
http://localhost:5173/?gatewayUrl=ws://<gateway-host>:18789
```
Optional one-time auth (if needed):
```text
http://localhost:5173/?gatewayUrl=wss://<gateway-host>:18789&token=<gateway-token>
```
Notes:
- `gatewayUrl` is stored in localStorage after load and removed from the URL.
- `token` is stored in localStorage; `password` is kept in memory only.
- Use `wss://` when the Gateway is behind TLS (Tailscale Serve, HTTPS proxy, etc.).
Remote access setup details: [Remote access](/gateway/remote).