a868b14221 Fix/lightweight action tool (#785)
* feat: add tool execution support to lightweight routines

Lightweight routines now execute tools instead of outputting raw tool-call XML.

**Problem:** Lightweight routines had no tool execution loop, causing the LLM to generate
tool-call XML as text output (visible to users as garbage on Telegram). All 4 scheduled
routines were disabled and Emil saw the same issue in health-ping routine.

**Solution:** Implement a simplified agentic loop for lightweight routines that:
- Supports up to 3-5 tool iterations (configurable, capped at 5)
- Executes tools sequentially (not parallel, keeps overhead low)
- Auto-approves non-Always tools (lightweight routines are autonomous)
- Sanitizes and wraps tool outputs via SafetyLayer (same as dispatcher)
- Forces text-only response at iteration limit (guarantees termination)
- Maintains backward compatibility (disabled by default, toggled by config)

**Changes:**
1. **src/config/routines.rs:**
   - Added lightweight_tools_enabled (default: true)
   - Added lightweight_max_iterations (default: 3, capped at 5)
   - Added env var support: ROUTINES_LIGHTWEIGHT_TOOLS, ROUTINES_LIGHTWEIGHT_MAX_ITERATIONS

2. **src/agent/routine_engine.rs:**
   - Extended EngineContext with tools and safety fields
   - Split execute_lightweight into three functions:
     - execute_lightweight: router that dispatches to tool or no-tool version
     - execute_lightweight_no_tools: original single-call behavior
     - execute_lightweight_with_tools: new agentic loop with tool support
   - Added execute_routine_tool: isolated tool execution with validation and timeout
   - Uses ToolCompletionRequest/ToolCompletionResponse for tool-aware LLM calls
   - Integrates SafetyLayer for tool output sanitization

3. **src/agent/agent_loop.rs:**
   - Updated RoutineEngine::new call to pass tools and safety

**Tool Execution Loop:**
1. Build initial messages (system + user prompt)
2. Get tool definitions (empty at iteration limit)
3. Call LLM with ToolCompletionRequest
4. If text response: check for ROUTINE_OK sentinel, return result
5. If tool calls: execute sequentially, sanitize, wrap, add to context, loop
6. Safety ceiling at 5 iterations prevents runaway execution

**Approval Handling:** Auto-approves UnlessAutoApproved and Never tools;
blocks Always tools with error message (routines are autonomous by design).

**Testing:** All 2756 tests pass. Zero clippy warnings.

Co-Authored-By: Claude Haiku 4.5 <[email protected]>

* test: add comprehensive unit tests for lightweight routine tool execution

Added 9 new unit tests covering:
- Configuration defaults (lightweight_tools_enabled, lightweight_max_iterations)
- Max iterations capped at 5 (safety ceiling)
- Routine name sanitization (special chars, alphanumeric preservation)
- Sentinel detection for ROUTINE_OK (exact match, contains, whitespace handling)
- Iteration limit safety ceiling enforcement
- Approval requirement pattern matching (Never, UnlessAutoApproved, Always)
- Empty response handling (finish_reason detection)

All 2765 tests pass (11 routine_engine tests, +9 new).

The tests cover the core logic paths of:
- Configuration validation
- Response parsing and sentinel detection
- Name sanitization for workspace paths
- Approval requirement logic
- Iteration limits and safety ceilings

Note: These are unit tests for core logic. Full integration tests with mock LLM
and tool registry would require more complex test infrastructure and are a future enhancement.

Co-Authored-By: Claude Haiku 4.5 <[email protected]>

* style: format routine_engine.rs per cargo fmt

Apply consistent formatting to match Rust style guidelines:
- Break long import lines
- Reformat method chains for readability
- Format multi-line return tuples

No functional changes.

Co-Authored-By: Claude Haiku 4.5 <[email protected]>

* fix: address security and code quality issues in lightweight routine tool execution

**Security Fixes:**

1. Sanitize tool error messages (medium severity)
   - Tool error messages were sent directly to LLM without sanitization
   - Now wrapped through SafetyLayer like successful outputs
   - Prevents leakage of API keys, internal paths, or PII from errors

2. Use unique job_id for each routine run (medium severity)
   - Previously reused routine.id across all executions
   - Caused state collisions and race conditions
   - Now generates unique run_id (Uuid::new_v4()) for each execution
   - Matches behavior of full_job routines

**Code Quality Fixes:**

3. Remove unreachable code
   - Deleted dead if iteration > 5 check
   - max_iterations is capped at 5 via .min(5), so check was impossible
   - Improves code clarity

4. Extract duplicated response handling logic
   - Created handle_text_response() helper function
   - Eliminated 20+ lines of duplicated ROUTINE_OK sentinel detection
   - Reduces maintenance burden and risk of inconsistencies

5. Fix test duplication
   - Tests now call actual super::sanitize_routine_name()
   - Removes duplicate implementation in tests
   - Ensures tests detect changes to original function

**Testing:**
- All 2765 tests pass (no regressions)
- Zero clippy warnings
- Test coverage maintained

Co-Authored-By: Claude Haiku 4.5 <[email protected]>

* fix: address security issue and improve code quality in lightweight routine tool execution

**SECURITY FIX (High Severity):**

1. Block UnlessAutoApproved tools in lightweight routines
   - Previously auto-approved UnlessAutoApproved tools, creating prompt injection vulnerability
   - Lightweight routines can be triggered by external events (channel messages, webhooks)
   - If susceptible to prompt injection, attacker could trick LLM into calling sensitive tools
   - Now blocks both UnlessAutoApproved and Always tools (only Never tools allowed)
   - Only safe approach without requiring tool_permissions allowlist in routine data model
   - Prevents unauthorized file access, network requests, and other sensitive operations

**Code Quality Improvements:**

2. Use ToolError::Timeout for consistent error handling (medium)
   - Changed from std::io::Error to proper ToolError::Timeout variant
   - More idiomatic and consistent with tool execution error handling
   - Makes errors easier to debug and handle uniformly

3. Fix misleading test names and remove tautological tests (medium)
   - Renamed test_routine_config_lightweight_max_iterations_capped_at_five to
     test_routine_config_can_hold_uncapped_max_iterations
   - Clarified comments to explain where capping actually occurs
   - Removed test_iteration_limit_safety_ceiling (tautological: asserts x.min(5) <= 5)
   - Improves test clarity and prevents false sense of coverage

**Testing:**
- 2764 tests passing (1 test removed, no regressions)
- Zero clippy warnings
- Security vulnerability eliminated

Co-Authored-By: Claude Haiku 4.5 <[email protected]>

* style: format routine_engine.rs per cargo fmt

Apply consistent formatting:
- Fix method chain indentation for LLM completion calls
- Reformat error handling closures for readability
- Break long method calls (wrap_for_llm) across multiple lines

No functional changes.

Co-Authored-By: Claude Haiku 4.5 <[email protected]>

* style: apply cargo fmt formatting fixes to routine_engine.rs

Align formatting with project standards:
- Break long method chains across multiple lines for readability
- Reformat error return statements for consistency
- Split long assert/assert_eq statements across multiple lines

No logic changes; purely cosmetic formatting.

Co-Authored-By: Claude Haiku 4.5 <[email protected]>

* test: update routine engine tests for tool/safety layer parameters

Update test code to pass newly required ToolRegistry and SafetyLayer
parameters to RoutineEngine::new(). Also add missing lightweight_tools_enabled
and lightweight_max_iterations fields to RoutineConfig initializers in tests.

Tests affected:
- tests/support/test_rig.rs: Added tools and safety layer to RoutineEngine::new()
- tests/e2e_routine_heartbeat.rs: Added three instances of tools and safety layer construction

All tests pass (2764 tests).

Co-Authored-By: Claude Haiku 4.5 <[email protected]>

---------

Co-authored-by: Claude Haiku 4.5 <[email protected]>
Co-authored-by: Henry Park <[email protected]>
2026-03-09 20:22:10 -07:00
2026-03-05 17:12:49 -08:00
2026-02-04 22:09:52 -08:00
2026-03-09 20:22:10 -07:00
2026-03-09 20:22:10 -07:00
2026-02-11 08:31:25 +00:00
2026-02-09 03:00:35 +00:00
2026-02-22 19:08:43 +00:00
2026-02-22 19:08:43 +00:00
2026-02-21 15:14:57 -07:00

IronClaw

IronClaw

Your secure personal AI assistant, always on your side

License: MIT OR Apache-2.0 Telegram: @ironclawAI Reddit: r/ironclawAI

English | 简体中文

PhilosophyFeaturesInstallationConfigurationSecurityArchitecture


Philosophy

IronClaw is built on a simple principle: your AI assistant should work for you, not against you.

In a world where AI systems are increasingly opaque about data handling and aligned with corporate interests, IronClaw takes a different approach:

  • Your data stays yours - All information is stored locally, encrypted, and never leaves your control
  • Transparency by design - Open source, auditable, no hidden telemetry or data harvesting
  • Self-expanding capabilities - Build new tools on the fly without waiting for vendor updates
  • Defense in depth - Multiple security layers protect against prompt injection and data exfiltration

IronClaw is the AI assistant you can actually trust with your personal and professional life.

Features

Security First

  • WASM Sandbox - Untrusted tools run in isolated WebAssembly containers with capability-based permissions
  • Credential Protection - Secrets are never exposed to tools; injected at the host boundary with leak detection
  • Prompt Injection Defense - Pattern detection, content sanitization, and policy enforcement
  • Endpoint Allowlisting - HTTP requests only to explicitly approved hosts and paths

Always Available

  • Multi-channel - REPL, HTTP webhooks, WASM channels (Telegram, Slack), and web gateway
  • Docker Sandbox - Isolated container execution with per-job tokens and orchestrator/worker pattern
  • Web Gateway - Browser UI with real-time SSE/WebSocket streaming
  • Routines - Cron schedules, event triggers, webhook handlers for background automation
  • Heartbeat System - Proactive background execution for monitoring and maintenance tasks
  • Parallel Jobs - Handle multiple requests concurrently with isolated contexts
  • Self-repair - Automatic detection and recovery of stuck operations

Self-Expanding

  • Dynamic Tool Building - Describe what you need, and IronClaw builds it as a WASM tool
  • MCP Protocol - Connect to Model Context Protocol servers for additional capabilities
  • Plugin Architecture - Drop in new WASM tools and channels without restarting

Persistent Memory

  • Hybrid Search - Full-text + vector search using Reciprocal Rank Fusion
  • Workspace Filesystem - Flexible path-based storage for notes, logs, and context
  • Identity Files - Maintain consistent personality and preferences across sessions

Installation

Prerequisites

  • Rust 1.85+
  • PostgreSQL 15+ with pgvector extension
  • NEAR AI account (authentication handled via setup wizard)

Download or Build

Visit Releases page to see the latest updates.

Install via Windows Installer (Windows)

Download the Windows Installer and run it.

Install via powershell script (Windows)
irm https://github.com/nearai/ironclaw/releases/latest/download/ironclaw-installer.ps1 | iex
Install via shell script (macOS, Linux, Windows/WSL)
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/nearai/ironclaw/releases/latest/download/ironclaw-installer.sh | sh
Install via Homebrew (macOS/Linux)
brew install ironclaw
Compile the source code (Cargo on Windows, Linux, macOS)

Install it with cargo, just make sure you have Rust installed on your computer.

# Clone the repository
git clone https://github.com/nearai/ironclaw.git
cd ironclaw

# Build
cargo build --release

# Run tests
cargo test

For full release (after modifying channel sources), run ./scripts/build-all.sh to rebuild channels first.

Database Setup

# Create database
createdb ironclaw

# Enable pgvector
psql ironclaw -c "CREATE EXTENSION IF NOT EXISTS vector;"

Configuration

Run the setup wizard to configure IronClaw:

ironclaw onboard

The wizard handles database connection, NEAR AI authentication (via browser OAuth), and secrets encryption (using your system keychain). Settings are persisted in the connected database; bootstrap variables (e.g. DATABASE_URL, LLM_BACKEND) are written to ~/.ironclaw/.env so they are available before the database connects.

Alternative LLM Providers

IronClaw defaults to NEAR AI but works with any OpenAI-compatible endpoint. Popular options include OpenRouter (300+ models), Together AI, Fireworks AI, Ollama (local), and self-hosted servers like vLLM or LiteLLM.

Select "OpenAI-compatible" in the wizard, or set environment variables directly:

LLM_BACKEND=openai_compatible
LLM_BASE_URL=https://openrouter.ai/api/v1
LLM_API_KEY=sk-or-...
LLM_MODEL=anthropic/claude-sonnet-4

See docs/LLM_PROVIDERS.md for a full provider guide.

Security

IronClaw implements defense in depth to protect your data and prevent misuse.

WASM Sandbox

All untrusted tools run in isolated WebAssembly containers:

  • Capability-based permissions - Explicit opt-in for HTTP, secrets, tool invocation
  • Endpoint allowlisting - HTTP requests only to approved hosts/paths
  • Credential injection - Secrets injected at host boundary, never exposed to WASM code
  • Leak detection - Scans requests and responses for secret exfiltration attempts
  • Rate limiting - Per-tool request limits to prevent abuse
  • Resource limits - Memory, CPU, and execution time constraints
WASM ──► Allowlist ──► Leak Scan ──► Credential ──► Execute ──► Leak Scan ──► WASM
         Validator     (request)     Injector       Request     (response)

Prompt Injection Defense

External content passes through multiple security layers:

  • Pattern-based detection of injection attempts
  • Content sanitization and escaping
  • Policy rules with severity levels (Block/Warn/Review/Sanitize)
  • Tool output wrapping for safe LLM context injection

Data Protection

  • All data stored locally in your PostgreSQL database
  • Secrets encrypted with AES-256-GCM
  • No telemetry, analytics, or data sharing
  • Full audit log of all tool executions

Architecture

┌────────────────────────────────────────────────────────────────┐
│                          Channels                              │
│  ┌──────┐  ┌──────┐   ┌─────────────┐  ┌─────────────┐         │
│  │ REPL │  │ HTTP │   │WASM Channels│  │ Web Gateway │         │
│  └──┬───┘  └──┬───┘   └──────┬──────┘  │ (SSE + WS)  │         │
│     │         │              │         └──────┬──────┘         │
│     └─────────┴──────────────┴────────────────┘                │
│                              │                                 │
│                    ┌─────────▼─────────┐                       │
│                    │    Agent Loop     │  Intent routing       │
│                    └────┬──────────┬───┘                       │
│                         │          │                           │
│              ┌──────────▼────┐  ┌──▼───────────────┐           │
│              │  Scheduler    │  │ Routines Engine  │           │
│              │(parallel jobs)│  │(cron, event, wh) │           │
│              └──────┬────────┘  └────────┬─────────┘           │
│                     │                    │                     │
│       ┌─────────────┼────────────────────┘                     │
│       │             │                                          │
│   ┌───▼─────┐  ┌────▼────────────────┐                         │
│   │ Local   │  │    Orchestrator     │                         │
│   │Workers  │  │  ┌───────────────┐  │                         │
│   │(in-proc)│  │  │ Docker Sandbox│  │                         │
│   └───┬─────┘  │  │   Containers  │  │                         │
│       │        │  │ ┌───────────┐ │  │                         │
│       │        │  │ │Worker / CC│ │  │                         │
│       │        │  │ └───────────┘ │  │                         │
│       │        │  └───────────────┘  │                         │
│       │        └─────────┬───────────┘                         │
│       └──────────────────┤                                     │
│                          │                                     │
│              ┌───────────▼──────────┐                          │
│              │    Tool Registry     │                          │
│              │  Built-in, MCP, WASM │                          │
│              └──────────────────────┘                          │
└────────────────────────────────────────────────────────────────┘

Core Components

Component Purpose
Agent Loop Main message handling and job coordination
Router Classifies user intent (command, query, task)
Scheduler Manages parallel job execution with priorities
Worker Executes jobs with LLM reasoning and tool calls
Orchestrator Container lifecycle, LLM proxying, per-job auth
Web Gateway Browser UI with chat, memory, jobs, logs, extensions, routines
Routines Engine Scheduled (cron) and reactive (event, webhook) background tasks
Workspace Persistent memory with hybrid search
Safety Layer Prompt injection defense and content sanitization

Usage

# First-time setup (configures database, auth, etc.)
ironclaw onboard

# Start interactive REPL
cargo run

# With debug logging
RUST_LOG=ironclaw=debug cargo run

Development

# Format code
cargo fmt

# Lint
cargo clippy --all --benches --tests --examples --all-features

# Run tests
createdb ironclaw_test
cargo test

# Run specific test
cargo test test_name
  • Telegram channel: See docs/TELEGRAM_SETUP.md for setup and DM pairing.
  • Changing channel sources: Run ./channels-src/telegram/build.sh before cargo build so the updated WASM is bundled.

OpenClaw Heritage

IronClaw is a Rust reimplementation inspired by OpenClaw. See FEATURE_PARITY.md for the complete tracking matrix.

Key differences:

  • Rust vs TypeScript - Native performance, memory safety, single binary
  • WASM sandbox vs Docker - Lightweight, capability-based security
  • PostgreSQL vs SQLite - Production-ready persistence
  • Security-first design - Multiple defense layers, credential protection

License

Licensed under either of:

at your option.

S
Description
IronClaw is OpenClaw inspired implementation in Rust focused on privacy and security
Readme
14 MiB
Languages
Rust 90.5%
Shell 3%
JavaScript 2.6%
Python 2.6%
CSS 1%
Other 0.3%