Skip to content

v2.5.0

Choose a tag to compare

@jztan jztan released this 16 May 15:00
· 127 commits to develop since this release

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