`supports_vision` is currently hardcoded per-provider. The same Ollama instance can run `llava` (vision) or
`codellama` (no vision), but the code fixes vision support at the provider level with no user override.
This adds a top-level `model_support_vision: Option<bool>` config key — tri-state:
- **Unset (default):** provider's built-in value, zero behavior change
- **`true`:** force vision on (e.g. Ollama + llava)
- **`false`:** force vision off
Follows the exact same pattern as `reasoning_enabled`. Override is applied at the wrapper layer (`ReliableProvider` /
`RouterProvider`) — no concrete provider code is touched.
## Changes
**Config surface:**
- Top-level `model_support_vision` field in `Config` struct with `#[serde(default)]`
- Env override: `ZEROCLAW_MODEL_SUPPORT_VISION` / `MODEL_SUPPORT_VISION`
**Provider wrappers (core logic):**
- `ReliableProvider`: `vision_override` field + `with_vision_override()` builder + `supports_vision()` override
- `RouterProvider`: same pattern
**Wiring (1-line each):**
- `ProviderRuntimeOptions` struct + factory functions
- 5 construction sites: `loop_.rs`, `channels/mod.rs`, `gateway/mod.rs`, `tools/mod.rs`, `onboard/wizard.rs`
**Docs (i18n parity):**
- `config-reference.md` — Core Keys table
- `providers-reference.md` — new "Ollama Vision Override" section
- Vietnamese sync: `docs/i18n/vi/` + `docs/vi/` (4 files)
## Non-goals
- Does not change any concrete provider implementation
- Does not auto-detect model vision capability
## Test plan
- [x] `cargo fmt --all -- --check`
- [x] `cargo clippy --all-targets -- -D warnings` (no new errors)
- [x] 5 new tests passing:
- `model_support_vision_deserializes` — TOML parse + default None
- `env_override_model_support_vision` — env var override + invalid value ignored
- `vision_override_forces_true` — ReliableProvider override
- `vision_override_forces_false` — ReliableProvider override
- `vision_override_none_defers_to_provider` — passthrough behavior
## Risk and Rollback
- **Risk:** Low. `None` default = zero behavior change for existing users.
- **Rollback:** Revert commit. Field is `#[serde(default)]` so old configs without it will deserialize fine.
(cherry picked from commit a1b8dee785)
Add 5 LLM-callable IPC tools (agents_list, agents_send, agents_inbox,
state_get, state_set) backed by a shared SQLite database, enabling
independent ZeroClaw processes on the same host to discover and
communicate with each other. Gated behind [agents_ipc] enabled = true.
Related #88 (item 3: Sessions / Sub-Agent Orchestration)
Related #1518 (design spec)
- Base branch target: dev
- Problem: ZeroClaw agents have no structured way to decompose complex tasks into trackable steps, falling behind
every comparable agent runtime
- Why it matters: Without task tracking, multi-step work is fragile (lost on context compression), invisible to users
(no progress signal), and error-prone (agent loses track of what's done vs. pending)
- What changed: Added a session-scoped task_plan tool with create/add/update/list/delete actions, integrated with
SecurityPolicy, registered in the tool factory
- What did not change: No config schema changes, no persistence layer, no CLI subcommand, no changes to agent loop or
any other subsystem
Label Snapshot
- Risk label: risk: low
- Size label: size: S
- Scope labels: tool
- Module labels: tool: task_plan
- Contributor tier label: (auto-managed)
- If any auto-label is incorrect: N/A
Change Metadata
- Change type: feature
- Primary scope: tool
Linked Issue
- Closes #(issue number)
- Related: N/A
- Depends on: N/A
- Supersedes: N/A
Supersede Attribution
N/A — no superseded PRs.
Validation Evidence
cargo fmt --all -- --check # pass (no output)
cargo clippy --all-targets -- -D warnings # task_plan.rs: 0 warnings (pre-existing warnings in other files
unrelated)
cargo test --lib tools::task_plan # 15/15 passed
- Evidence provided: test output (15 passed, 0 failed)
- If any command is intentionally skipped: cargo clippy reports pre-existing warnings in unrelated files
(onboard/wizard.rs etc.); task_plan.rs itself has zero clippy warnings
Security Impact
- New permissions/capabilities? No — uses existing ToolOperation::Act enforcement
- New external network calls? No
- Secrets/tokens handling changed? No
- File system access scope changed? No
Privacy and Data Hygiene
- Data-hygiene status: pass
- Redaction/anonymization notes: No identity data in code or tests. Test fixtures use neutral strings ("step one",
"do thing", "first")
- Neutral wording confirmation: All naming follows ZeroClaw/project-native conventions
Compatibility / Migration
- Backward compatible? Yes
- Config/env changes? No
- Migration needed? No
i18n Follow-Through
- i18n follow-through triggered? No — no docs or user-facing wording changes
Human Verification
- Verified scenarios: Ran ./target/debug/zeroclaw agent -m "调用 task_plan 工具,action=list" — agent correctly
identified and called task_plan, returned "No tasks."
- Edge cases checked: read-only mode blocks mutations, empty task list, invalid action names, missing required
parameters, create replaces existing list, ID auto-increment after add
- What was not verified: Behavior with non-CLI channels (Telegram, Discord); behavior with XML-fallback dispatcher
(non-native-tool providers)
Side Effects / Blast Radius
- Affected subsystems/workflows: src/tools/ only — tool factory gains one additional entry
- Potential unintended effects: Marginally increases tool spec payload size sent to LLM (one more tool definition).
Could theoretically cause tool name confusion with schedule if LLM descriptions are ambiguous — mitigated by distinct
naming (task_plan vs schedule) and different description wording.
- Guardrails/monitoring for early detection: Standard tool dispatch logging. Tool is session-scoped so no persistent
side effects on failure.
Agent Collaboration Notes
- Agent tools used: Claude Code for implementation assistance and review
- Workflow/plan summary: Implement Tool trait → register in factory → validate with tests → manual agent session test
- Verification focus: Security policy enforcement, parameter validation edge cases, all 5 action paths
- Confirmation: naming + architecture boundaries followed (CLAUDE.md §6.3, §6.4, §7.3): Yes
Rollback Plan
- Fast rollback command/path: git revert <commit> — removes 3 lines from mod.rs and deletes task_plan.rs
- Feature flags or config toggles: None needed — tool is stateless and session-scoped
- Observable failure symptoms: Tool not appearing in agent tool list, or tool returning errors on valid input
Risks and Mitigations
- Risk: LLM may occasionally confuse task_plan (action: list) with schedule (action: list) due to similar parameter
structure
- Mitigation: Distinct tool names and descriptions; task_plan description emphasizes "session checklist" while
schedule emphasizes "cron/recurring tasks"
- Problem: The existing http_request tool returns raw HTML/JSON, which is nearly unusable for LLMs to extract
meaningful content from web pages.
- Why it matters: All mainstream AI agents (Claude Code, Gemini CLI, Aider) have dedicated web content extraction
tools. ZeroClaw lacks this capability, limiting its ability to research and gather information from the web.
- What changed: Added a new web_fetch tool that fetches web pages and converts HTML to clean plain text using
nanohtml2text. Includes domain allowlist/blocklist, SSRF protection, redirect following, and content-type aware
processing.
- What did not change (scope boundary): http_request tool is untouched. No shared code extracted between http_request
and web_fetch (DRY rule-of-three: only 2 callers). No changes to existing tool behavior or defaults.
Label Snapshot (required)
- Risk label: risk: medium
- Size label: size: M
- Scope labels: tool, config
- Module labels: tool: web_fetch
- If any auto-label is incorrect, note requested correction: N/A
Change Metadata
- Change type: feature
- Primary scope: tool
Linked Issue
- Closes #
- Related #
- Depends on #
- Supersedes #
Supersede Attribution (required when Supersedes # is used)
N/A
Validation Evidence (required)
cargo fmt --all -- --check # pass
cargo clippy --all-targets -- -D warnings # no new warnings (pre-existing warnings only)
cargo test --lib -- web_fetch # 26/26 passed
cargo test --lib -- tools::tests # 12/12 passed
cargo test --lib -- config::schema::tests # 134/134 passed
- Evidence provided: unit test results (26 new tests), manual end-to-end test with Ollama + qwen2.5:72b
- If any command is intentionally skipped, explain why: Full cargo clippy --all-targets has 43 pre-existing errors
unrelated to this PR (e.g. await_holding_lock, format! appended to String). Zero errors from web_fetch code.
Security Impact (required)
- New permissions/capabilities? Yes — new web_fetch tool can make outbound HTTP GET requests
- New external network calls? Yes — fetches web pages from allowed domains
- Secrets/tokens handling changed? No
- File system access scope changed? No
- If any Yes, describe risk and mitigation:
- Deny-by-default: enabled = false by default; tool is not registered unless explicitly enabled
- Domain filtering: allowed_domains (default ["*"] = all public hosts) + blocked_domains (takes priority).
Blocklist always wins over allowlist.
- SSRF protection: Blocks localhost, private IPs (RFC 1918), link-local, multicast, reserved ranges, IPv4-mapped
IPv6, .local TLD — identical coverage to http_request
- Rate limiting: can_act() + record_action() enforce autonomy level and rate limits
- Read-only mode: Blocked when autonomy is ReadOnly
- Response size cap: 500KB default truncation prevents context window exhaustion
- Proxy support: Honors [proxy] config via tool.web_fetch service key
Privacy and Data Hygiene (required)
- Data-hygiene status: pass
- Redaction/anonymization notes: No personal data in code, tests, or fixtures
- Neutral wording confirmation: All test identifiers use neutral project-scoped labels
Compatibility / Migration
- Backward compatible? Yes — new tool, no existing behavior changed
- Config/env changes? Yes — new [web_fetch] section in config.toml (all fields have defaults)
- Migration needed? No — #[serde(default)] on all fields; existing configs without [web_fetch] section work unchanged
i18n Follow-Through (required when docs or user-facing wording changes)
- i18n follow-through triggered? No — no docs or user-facing wording changes
Human Verification (required)
- Verified scenarios:
- End-to-end test: zeroclaw agent with Ollama qwen2.5:72b successfully called web_fetch to fetch
https://github.com/zeroclaw-labs/zeroclaw, returned clean plain text with project description, features, star count
- Tool registration: tool_count increased from 22 to 23 when enabled = true
- Config: enabled = false (default) → tool not registered; enabled = true → tool available
- Edge cases checked:
- Missing [web_fetch] section in existing config.toml → works (serde defaults)
- Blocklist priority over allowlist
- SSRF with localhost, private IPs, IPv6
- What was not verified:
- Proxy routing (no proxy configured in test environment)
- Very large page truncation with real-world content
Side Effects / Blast Radius (required)
- Affected subsystems/workflows: all_tools_with_runtime() signature gained one parameter (web_fetch_config); all 5
call sites updated
- Potential unintended effects: None — new tool only, existing tools unchanged
- Guardrails/monitoring for early detection: enabled = false default; tool_count in debug logs
Agent Collaboration Notes (recommended)
- Agent tools used: Claude Code (Opus 4.6)
- Workflow/plan summary: Plan mode → approval → implementation → validation
- Verification focus: Security (SSRF, domain filtering, rate limiting), config compatibility, tool registration
- Confirmation: naming + architecture boundaries followed (CLAUDE.md + CONTRIBUTING.md): Yes — trait implementation +
factory registration pattern, independent security helpers (DRY rule-of-three), deny-by-default config
Rollback Plan (required)
- Fast rollback command/path: git revert <commit>
- Feature flags or config toggles: [web_fetch] enabled = false (default) disables completely
- Observable failure symptoms: tool_count in debug logs drops by 1; LLM cannot call web_fetch
Risks and Mitigations
- Risk: SSRF bypass via DNS rebinding (attacker-controlled domain resolving to private IP)
- Mitigation: Pre-request host validation blocks known private/local patterns. Same defense level as existing
http_request tool. Full DNS-level protection would require async DNS resolution before connect, which is out of scope
for this PR.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
(cherry picked from commit 04597352cc)
- Problem: Agent relies on `shell` + `find` for file search — fragile syntax, raw output, broad permissions
- Why it matters: Structured tool reduces failed tool calls and tightens security boundary
- What changed: New `glob_search` tool in `default_tools` and `all_tools`; searches workspace by glob pattern with
full security checks
- What did **not** change (scope boundary): No changes to security policy, config schema, providers, or agent loop
Each major subsystem mod.rs now includes a //! doc block explaining the
subsystem purpose, trait-driven architecture, factory registration pattern,
and extension guidance. This improves the generated rustdoc experience for
developers navigating ZeroClaw's modular architecture.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- add scope-aware proxy schema and runtime wiring for providers/channels/tools
- add agent callable proxy_config tool for fast proxy setup
- standardize docs system with index, template, and playbooks
Add native web search capability that works regardless of LLM tool-calling
support. This is particularly useful for GLM models via Z.AI that don't
reliably support standard tool calling formats.
Features:
- DuckDuckGo provider (free, no API key required)
- Brave Search provider (optional, requires API key)
- Configurable max results and timeout
- Enabled by default
Configuration (config.toml):
[web_search]
enabled = true
provider = "duckduckgo"
max_results = 5
The tool allows agents to search the web for current information without
requiring proper tool calling support from the LLM.
Also includes CI workflow fix for first-interaction action inputs.
- Added `JobType`, `SessionTarget`, `Schedule`, `DeliveryConfig`, `CronJob`, `CronRun`, and `CronJobPatch` types in `src/cron/types.rs` for cron job configuration and management.
- Introduced `CronAddTool`, `CronListTool`, `CronRemoveTool`, `CronRunTool`, `CronRunsTool`, and `CronUpdateTool` in `src/tools` for adding, listing, removing, running, and updating cron jobs.
- Updated the `run` function in `src/daemon/mod.rs` to conditionally start the scheduler based on the cron configuration.
- Modified command-line argument parsing in `src/lib.rs` and `src/main.rs` to support new cron job commands.
- Enhanced the onboarding wizard in `src/onboard/wizard.rs` to include cron configuration.
- Added tests for cron job tools to ensure functionality and error handling.
* feat: add ZeroClaw firmware for ESP32 and Nucleo
* Introduced new firmware for ZeroClaw on ESP32 and Nucleo-F401RE, enabling JSON-over-serial communication for GPIO control.
* Added `zeroclaw-esp32` with support for commands like `gpio_read` and `gpio_write`, along with capabilities reporting.
* Implemented `zeroclaw-nucleo` firmware with similar functionality for STM32, ensuring compatibility with existing ZeroClaw protocols.
* Updated `.gitignore` to include new firmware targets and added necessary dependencies in `Cargo.toml` for both platforms.
* Created README files for both firmware projects detailing setup, build, and usage instructions.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: enhance hardware peripheral support and documentation
- Added `Peripheral` trait implementation in `src/peripherals/` to manage hardware boards (STM32, RPi GPIO).
- Updated `AGENTS.md` to include new extension points for peripherals and their configuration.
- Introduced comprehensive documentation for adding boards and tools, including a quick start guide and supported boards.
- Enhanced `Cargo.toml` to include optional dependencies for PDF extraction and peripheral support.
- Created new datasheets for Arduino Uno, ESP32, and Nucleo-F401RE, detailing pin aliases and GPIO usage.
- Implemented new tools for hardware memory reading and board information retrieval in the agent loop.
This update significantly improves the integration and usability of hardware peripherals within the ZeroClaw framework.
* feat: add ZeroClaw firmware for ESP32 and Nucleo
* Introduced new firmware for ZeroClaw on ESP32 and Nucleo-F401RE, enabling JSON-over-serial communication for GPIO control.
* Added `zeroclaw-esp32` with support for commands like `gpio_read` and `gpio_write`, along with capabilities reporting.
* Implemented `zeroclaw-nucleo` firmware with similar functionality for STM32, ensuring compatibility with existing ZeroClaw protocols.
* Updated `.gitignore` to include new firmware targets and added necessary dependencies in `Cargo.toml` for both platforms.
* Created README files for both firmware projects detailing setup, build, and usage instructions.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: enhance hardware peripheral support and documentation
- Added `Peripheral` trait implementation in `src/peripherals/` to manage hardware boards (STM32, RPi GPIO).
- Updated `AGENTS.md` to include new extension points for peripherals and their configuration.
- Introduced comprehensive documentation for adding boards and tools, including a quick start guide and supported boards.
- Enhanced `Cargo.toml` to include optional dependencies for PDF extraction and peripheral support.
- Created new datasheets for Arduino Uno, ESP32, and Nucleo-F401RE, detailing pin aliases and GPIO usage.
- Implemented new tools for hardware memory reading and board information retrieval in the agent loop.
This update significantly improves the integration and usability of hardware peripherals within the ZeroClaw framework.
* feat: Introduce hardware auto-discovery and expanded configuration options for agents, hardware, and security.
* chore: update dependencies and improve probe-rs integration
- Updated `Cargo.lock` to remove specific version constraints for several dependencies, including `zerocopy`, `syn`, and `strsim`, allowing for more flexibility in version resolution.
- Upgraded `bincode` and `bitfield` to their latest versions, enhancing serialization and memory management capabilities.
- Updated `Cargo.toml` to reflect the new version of `probe-rs` from `0.24` to `0.30`, improving hardware probing functionality.
- Refactored code in `src/hardware` and `src/tools` to utilize the new `SessionConfig` for session management in `probe-rs`, ensuring better compatibility and performance.
- Cleaned up documentation in `docs/datasheets/nucleo-f401re.md` by removing unnecessary lines.
* fix: apply cargo fmt
* docs: add hardware architecture diagram.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Unifies scheduled task capabilities and consolidates overlapping implementations from #337 and #338 into a single security-first integration path.\n\nCo-authored-by: Edvard <ecschoye@stud.ntnu.no>\nCo-authored-by: stawky <stakeswky@gmail.com>
* feat: add agent-to-agent delegation tool
Add `delegate` tool enabling multi-agent workflows where a primary agent
can hand off subtasks to specialized sub-agents with different
provider/model configurations.
- New `DelegateAgentConfig` in config schema with provider, model,
system_prompt, api_key, temperature, and max_depth fields
- `delegate` tool with recursion depth limits to prevent infinite loops
- Agents configured via `[agents.<name>]` TOML sections
- Sub-agents use `ReliableProvider` with fallback API key support
- Backward-compatible: empty agents map when section is absent
Closes#218
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: encrypt agent API keys and tighten delegation input validation
Address CodeRabbit review comments on PR #224:
1. Agent API key encryption (schema.rs):
- Config::load_or_init() now decrypts agents.*.api_key via SecretStore
- Config::save() encrypts plaintext agent API keys before writing
- Updated doc comment to document encryption behavior
- Added tests for encrypt-on-save and plaintext-when-disabled
2. Delegation input validation (delegate.rs):
- Added "additionalProperties": false to schema
- Added "minLength": 1 for agent and prompt fields
- Trim agent/prompt/context inputs, reject empty after trim
- Added tests for blank agent, blank prompt, whitespace trimming
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(delegate): replace mutable depth counter with immutable field
- Replace `current_depth: Arc<AtomicU32>` with `depth: u32` set at
construction time, eliminating TOCTOU race and cancel/panic safety
issues from fetch_add/fetch_sub pattern
- When sub-agents get their own tool registry, construct via
`with_depth(agents, key, parent.depth + 1)` for proper propagation
- Add tokio::time::timeout (120s) around provider calls to prevent
indefinite blocking from misbehaving sub-agent providers
- Rename misleading test whitespace_agent_name_not_found →
whitespace_agent_name_trimmed_and_found
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* style: fix rustfmt formatting issues
Fixed all formatting issues reported by cargo fmt to pass CI lint checks.
- Line length adjustments
- Chain formatting consistency
- Trailing whitespace cleanup
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Edvard <ecschoye@stud.ntnu.no>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add screenshot and image_info vision tools
Add two new tools for visual capabilities:
- `screenshot`: captures screen using platform-native commands
(screencapture on macOS, gnome-screenshot/scrot/import on Linux),
returns file path + base64-encoded PNG data
- `image_info`: reads image metadata (format, dimensions, size) from
header bytes without external deps, optionally returns base64 data
for future multimodal provider support
Both tools are registered in the tool registry and agent system prompt.
Includes 24 inline tests covering format detection, dimension extraction,
schema validation, and execution edge cases.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: resolve unused variable warning after rebase
Prefix unused `resolved_key` with underscore to suppress compiler
warning introduced by upstream changes. Update Cargo.lock.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address review comments on vision tools
Security fixes:
- Fix JPEG parser infinite loop on malformed zero-length segments
- Add workspace path restriction to ImageInfoTool (prevents arbitrary
file exfiltration via include_base64)
- Quote paths in Linux screenshot shell commands to prevent injection
- Add autonomy-level check in ScreenshotTool::execute
Robustness:
- Add file size guard in read_and_encode before loading into memory
- Wire resolve_api_key through all provider match arms (was dead code)
- Gate screenshot_command_exists test on macOS/Linux only
- Infer MIME type from file extension instead of hardcoding image/png
Tests:
- Add JPEG dimension extraction test
- Add JPEG malformed zero-length segment test
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: argenis de la rosa <theonlyhennygod@gmail.com>