What's New in v2.5.0
Added
- Telegram bridge. New
blueclaw telegram subcommand exposes blueclaw to
Telegram with per-chat workspaces under ~/blueclaw/chats/<chat_id>/,
Strands FileSessionManager-backed conversation continuity, allowlist-enforced
authorization (empty allowlist refuses everyone), /whoami /reset /forget
commands, long-polling by default and webhook mode opt-in, and a --echo
smoke-test mode. Each turn is persisted via build_trace_and_record →
write_trace + append_history with source="telegram". Install via
pip install -e ".[telegram]". See docs/bridges/telegram.md.
blueclaw history --chat <id> / --all-chats. Inspect per-chat
Telegram history without changing directory; --all-chats aggregates the
default workspace with every ~/blueclaw/chats/<id>/, labeling each row.
- Telegram bridge: empty-reply fallback. Small Ollama models occasionally
emit only a tool-use block with no synthesized text. Previously this crashed
the handler with Telegram's BadRequest: Message text is empty. The bridge
now substitutes a friendly fallback ((no reply — the model produced empty output. Try rephrasing, /reset, or a stronger model.)) and skips empty chunks.
- Sandbox: chats-root mount widened.
~/blueclaw/chats/ is now bind-mounted
into the container whenever it exists on the host, not just for the
telegram subcommand. This lets blueclaw trace ui --all-chats and
blueclaw history --all-chats see per-chat data when running under
sandbox.mode=docker.
- Dashboard: strict-mode regression fixed. The multi-workspace patch had
reassigned function fetchJSON(...), which is a SyntaxError under the
dashboard's 'use strict' directive and broke the entire SPA. Replaced
with an apiFetch() wrapper used at every /api/* call site.
- Multi-workspace trace coverage. Every
blueclaw trace * reader now
accepts --chat <id> (single Telegram chat) and, where the union makes
sense (list, stats, purge, ui), --all-chats. Single-target
trace show / explain / graph / replay / timeline / diff auto-scan
workspaces and print a disambiguation hint on collision. The web
dashboard (blueclaw trace ui) gains a workspace dropdown (with All workspaces when more than one exists), a Source column in the trace
list, and a per-source breakdown table in the stats view. New
GET /api/workspaces endpoint; existing /api/traces, /api/traces/{id},
/api/stats accept ?workspace=<key> (all unions). Writers
unchanged.
- SOUL.md identity file. Optional
<workspace>/SOUL.md holds the agent's
persona/voice (personality, values, communication style) separately from
CONTEXT.md (which holds factual memory). When present, it is loaded as the
## Identity section of the system prompt before ## Persistent Context.
blueclaw init writes a default template; the file is human-managed
(no auto-writes) and re-read every turn so edits are picked up live.
- Docker sandbox. Opt-in via
sandbox.mode: docker in blueclaw.yaml. Runs the
entire agent process inside a short-lived container with the workspace bind-mounted,
read-only root FS, no-new-privileges, all capabilities dropped, and configurable
resource caps. Launcher transparently execvps into docker run while keeping
the user's TTY and signal forwarding intact. See docs/sandbox.md.
- Layered env composition for the sandbox: built-in allowlist →
~/blueclaw/.env → <project>/.env (same file python-dotenv already loads on
the host) → <project>/.env.docker → YAML extra_env. blueclaw init adds
dotenv files to .gitignore.
blueclaw sandbox build / blueclaw sandbox doctor CLI commands.
- Visible launch indicator: the launcher prints
→ blueclaw sandbox: docker (<image-tag>) to stderr when it re-execs into the
container, so users can confirm the sandbox fired.
- Editable-install detection (PEP 610): editable installs build
dev-<sha>
images and overlay the source tree at /opt/blueclaw-src via PYTHONPATH.
- Trace metadata records
sandbox.mode/image/image_digest/fallback_reason on
every TraceStep.
- Recursion guard for the in-container blueclaw: when
BLUECLAW_SANDBOX_MODE=docker is set, the launcher hook short-circuits so the
container never tries to launch another container.
Fixed
- Launcher hook misfired under bare
pytest. _maybe_execvp_into_docker
inspected sys.argv directly to route subcommands. Under bare pytest from a
project with sandbox.mode: docker in blueclaw.yaml, sys.argv=['pytest']
→ normalize_subcommand returned "" (the interactive-mode marker, which is
in _CONTAINER_COMMANDS) → the hook tried to re-exec the test process into
docker, causing every runner.invoke(app, []) in tests/test_cli.py to fail
with exit_code=2. Added a host-program guard: the hook returns early when
os.path.basename(sys.argv[0]) != "blueclaw". CI didn't catch it because
.github/workflows/ci.yml invoked pytest tests/ (where sys.argv[1]="tests"
isn't sandbox-routed) and ran in a clean checkout without blueclaw.yaml.
- Test invocation parity with CI. Added
testpaths = ["tests"] to
[tool.pytest.ini_options] and dropped the tests/ arg from the CI test
step so bare pytest and CI collect identically.
blueclaw sandbox build accumulated dev images. Editable installs tag
images as blueclaw/runtime:dev-<short-sha>, so every commit produced a new
tag and the previous one lingered on disk. sandbox build now sweeps stale
dev-* tags after a successful build so it behaves like an overwrite.
- Spurious "unable to find previously injected skills XML" warning on every
resumed turn under blueclaw serve. FileSessionManager rehydrated the
Strands skills plugin's last_injected_xml state from disk, but the system
prompt was rebuilt fresh each turn, so the plugin couldn't match its prior
injection and warned (harmlessly) before re-appending. create_agent now
clears the agent_skills state key after construction when a session manager
is attached, so the plugin treats the next invocation as a first injection.
- Launcher hook fall-through.
_maybe_execvp_into_docker now raises
SystemExit(0) after os.execvp so the function cannot continue into the
in-process subcommand if execvp ever returns. Fixes a CI hang where the
test_docker_mode_trace_ui_calls_execvp test mocked os.execvp, fell
through to typer's subcommand dispatch, and blocked forever inside a real
uvicorn.run.
Changed
- Sandbox auto-host for Ollama. When
provider: ollama and
sandbox.mode: docker, the launcher now defaults OLLAMA_HOST to
http://host.docker.internal:11434 (unless the user set it explicitly) and
adds --add-host=host.docker.internal:host-gateway to the docker run argv.
Containers previously hit localhost:11434 — which is the container itself
— and surfaced an opaque "All connection attempts failed" mid-stream.
Requires the host Ollama daemon to bind a reachable interface
(OLLAMA_HOST=0.0.0.0:11434 ollama serve).
blueclaw serve updates CONTEXT.md per turn. Matches CLI behavior: each
successful /message or /message/stream turn calls
BackgroundContextUpdater.trigger(agent), which spawns one background
summarization thread. Concurrent triggers are coalesced (the updater is a
no-op while a previous one is in flight), so multiple conversations writing
the same global file can't race. The Starlette lifespan handler now waits
on the last in-flight thread (up to 15s) so Ctrl+C never truncates a write.
- Runtime image installs all four model-provider extras (
anthropic,
ollama, openai, gemini) so the image works for any configured provider
without a rebuild.
- HOME tmpfs: the sandbox now mounts ephemeral tmpfs at
/home/blueclaw/.cache (256 MB), /home/blueclaw/.config (32 MB),
/home/blueclaw/.local (64 MB) so XDG-respecting tools (pdf-mcp cache, pip
cache, HuggingFace cache, etc.) work under --read-only root.
- In-container bind defaults to 0.0.0.0 for
blueclaw serve and
blueclaw trace ui when running under the sandbox, so --publish <port>:<port>
actually reaches the in-container server. Outside the sandbox, the bind stays
on 127.0.0.1 (unchanged).
- Config path resolution honors
BLUECLAW_CONFIG env var, set by the launcher
to the bind-mounted config path inside the container. The config is mounted
outside the workspace mount (/home/blueclaw/blueclaw.yaml) because macOS
Docker Desktop with VirtioFS refuses to bind-mount a file inside another
bind-mount.
Installation
pip install blueclaw==2.5.0
Links