Rebrand to IronClaw with security-first mission

Renamed project from "near-agent" to "ironclaw" throughout the codebase.
Updated documentation to emphasize the core philosophy:
- Your data stays yours (local, encrypted, no telemetry)
- Self-expanding capabilities (build tools on the fly)
- Defense in depth (WASM sandbox, prompt injection defense)
- Always on user's side

Key changes:
- Package name: near-agent -> ironclaw
- Config paths: ~/.near-agent/ -> ~/.ironclaw/
- Database name in docs: near_agent -> ironclaw
- CLI binary: near-agent -> ironclaw
- Log filters: RUST_LOG=near_agent -> RUST_LOG=ironclaw
- All user-facing strings (welcome messages, help text, etc.)

Preserved for compatibility:
- HKDF salt "near-agent-secrets-v1" (changing would break existing secrets)
- WIT interface names (near::agent::*)
- NEAR AI provider config (NEARAI_* env vars)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
This commit is contained in:
Illia Polosukhin
2026-02-05 01:10:40 -08:00
co-authored by Claude Opus 4.5
parent 2486065fa7
commit 598dd43b1c
36 changed files with 266 additions and 231 deletions
+17 -9
View File
@@ -1,9 +1,17 @@
# NEAR Agent Development Guide
# IronClaw Development Guide
## Project Overview
LLM-powered autonomous agent for the NEAR AI marketplace. Features:
- **Multi-channel input**: Full TUI (Ratatui), HTTP webhook with secret auth (Slack/Telegram stubs)
**IronClaw** is a secure personal AI assistant that protects your data and expands its capabilities on the fly.
### Core Philosophy
- **User-first security** - Your data stays yours, encrypted and local
- **Self-expanding** - Build new tools dynamically without vendor dependency
- **Defense in depth** - Multiple security layers against prompt injection and data exfiltration
- **Always available** - Multi-channel access with proactive background execution
### Features
- **Multi-channel input**: TUI (Ratatui), HTTP webhooks, Telegram, WhatsApp, Slack (WASM channels)
- **Parallel job execution** with state machine and self-repair for stuck jobs
- **Extensible tools**: Built-in tools, WASM sandbox, MCP client, dynamic builder
- **Persistent memory**: Workspace with hybrid search (FTS + vector via RRF)
@@ -26,7 +34,7 @@ cargo test
cargo test test_name
# Run with logging
RUST_LOG=near_agent=debug cargo run
RUST_LOG=ironclaw=debug cargo run
```
## Project Structure
@@ -201,7 +209,7 @@ Pending -> InProgress -> Completed -> Submitted -> Accepted
Environment variables (see `.env.example`):
```bash
DATABASE_URL=postgres://user:pass@localhost/near_agent
DATABASE_URL=postgres://user:pass@localhost/ironclaw
# NEAR AI (required)
NEARAI_SESSION_TOKEN=sess_...
@@ -209,7 +217,7 @@ NEARAI_MODEL=claude-3-5-sonnet-20241022
NEARAI_BASE_URL=https://private.near.ai
# Agent settings
AGENT_NAME=near-agent
AGENT_NAME=ironclaw
MAX_PARALLEL_JOBS=5
# Embeddings (for semantic memory search)
@@ -328,13 +336,13 @@ Key test patterns:
```bash
# Verbose logging
RUST_LOG=near_agent=trace cargo run
RUST_LOG=ironclaw=trace cargo run
# Just the agent module
RUST_LOG=near_agent::agent=debug cargo run
RUST_LOG=ironclaw::agent=debug cargo run
# With HTTP request logging
RUST_LOG=near_agent=debug,tower_http=debug cargo run
RUST_LOG=ironclaw=debug,tower_http=debug cargo run
```
## Code Style
Generated
+56 -56
View File
@@ -1876,6 +1876,62 @@ dependencies = [
"serde",
]
[[package]]
name = "ironclaw"
version = "0.1.0"
dependencies = [
"aes-gcm",
"aho-corasick",
"anyhow",
"async-trait",
"axum",
"blake3",
"bollard",
"bytes",
"chrono",
"clap",
"crossterm",
"deadpool-postgres",
"dirs 6.0.0",
"dotenvy",
"futures",
"hkdf",
"http-body-util",
"hyper",
"hyper-util",
"open",
"pgvector",
"postgres-types",
"pretty_assertions",
"rand 0.8.5",
"ratatui",
"refinery",
"regex",
"reqwest",
"rust_decimal",
"rust_decimal_macros",
"secrecy",
"serde",
"serde_json",
"sha2",
"tempfile",
"testcontainers-modules",
"thiserror 2.0.18",
"tokio",
"tokio-postgres",
"tokio-stream",
"tokio-test",
"tower",
"tower-http",
"tracing",
"tracing-subscriber",
"urlencoding",
"uuid",
"wasmparser 0.220.1",
"wasmtime",
"wasmtime-wasi",
]
[[package]]
name = "is-docker"
version = "0.2.0"
@@ -2127,62 +2183,6 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "near-agent"
version = "0.1.0"
dependencies = [
"aes-gcm",
"aho-corasick",
"anyhow",
"async-trait",
"axum",
"blake3",
"bollard",
"bytes",
"chrono",
"clap",
"crossterm",
"deadpool-postgres",
"dirs 6.0.0",
"dotenvy",
"futures",
"hkdf",
"http-body-util",
"hyper",
"hyper-util",
"open",
"pgvector",
"postgres-types",
"pretty_assertions",
"rand 0.8.5",
"ratatui",
"refinery",
"regex",
"reqwest",
"rust_decimal",
"rust_decimal_macros",
"secrecy",
"serde",
"serde_json",
"sha2",
"tempfile",
"testcontainers-modules",
"thiserror 2.0.18",
"tokio",
"tokio-postgres",
"tokio-stream",
"tokio-test",
"tower",
"tower-http",
"tracing",
"tracing-subscriber",
"urlencoding",
"uuid",
"wasmparser 0.220.1",
"wasmtime",
"wasmtime-wasi",
]
[[package]]
name = "nu-ansi-term"
version = "0.50.3"
+2 -2
View File
@@ -1,9 +1,9 @@
[package]
name = "near-agent"
name = "ironclaw"
version = "0.1.0"
edition = "2024"
rust-version = "1.85"
description = "LLM-powered autonomous agent for the NEAR AI marketplace"
description = "Secure personal AI assistant that protects your data and expands its capabilities on the fly"
license = "MIT OR Apache-2.0"
[dependencies]
+2 -2
View File
@@ -208,7 +208,7 @@ This document tracks feature parity between IronClaw (Rust implementation) and O
| Dynamic loading | ✅ | ✅ | WASM modules |
| Manifest validation | ✅ | ✅ | WASM metadata |
| HTTP path registration | ✅ | ❌ | Plugin routes |
| Workspace-relative install | ✅ | ✅ | ~/.near-agent/tools/ |
| Workspace-relative install | ✅ | ✅ | ~/.ironclaw/tools/ |
| Channel plugins | ✅ | ✅ | WASM channels |
| Auth plugins | ✅ | ❌ | |
| Memory plugins | ✅ | ❌ | Custom backends |
@@ -233,7 +233,7 @@ This document tracks feature parity between IronClaw (Rust implementation) and O
| Config validation/schema | ✅ | ✅ | Type-safe Config struct |
| Hot-reload | ✅ | ❌ | |
| Legacy migration | ✅ | | |
| State directory | ✅ `~/.openclaw-state/` | ✅ `~/.near-agent/` | |
| State directory | ✅ `~/.openclaw-state/` | ✅ `~/.ironclaw/` | |
| Credentials directory | ✅ | ✅ | Session files |
### Owner: _Unassigned_
+96 -71
View File
@@ -5,58 +5,60 @@
<h1 align="center">IronClaw</h1>
<p align="center">
<strong>LLM-powered autonomous agent for the NEAR AI marketplace</strong>
<strong>Your secure personal AI assistant, always on your side</strong>
</p>
<p align="center">
<a href="#philosophy">Philosophy</a> •
<a href="#features">Features</a> •
<a href="#openclaw-feature-parity">Parity</a> •
<a href="#installation">Installation</a> •
<a href="#configuration">Configuration</a> •
<a href="#architecture">Architecture</a> •
<a href="#security">Security</a>
<a href="#security">Security</a> •
<a href="#architecture">Architecture</a>
</p>
---
## 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
- **Multi-channel input** - CLI, HTTP webhooks, Slack, Telegram
- **Parallel job execution** - Concurrent task processing with isolated contexts
- **Extensible tools** - Built-in tools + MCP protocol + WASM sandbox
- **Persistent memory** - Hybrid search (FTS + vector) with chunked documents
- **Prompt injection defense** - Pattern detection, content sanitization, policy enforcement
- **Self-repair** - Automatic detection and recovery of stuck jobs
- **Heartbeat system** - Proactive periodic execution for background tasks
### Security First
## OpenClaw Feature Parity
- **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
IronClaw is a Rust reimplementation inspired by [OpenClaw](https://github.com/openclaw/openclaw). See [FEATURE_PARITY.md](FEATURE_PARITY.md) for the complete tracking matrix.
### Always Available
### Status Summary
- **Multi-channel** - Reach your assistant via CLI, Telegram, WhatsApp, Slack, or HTTP webhooks
- **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
| Category | Status | Notes |
|----------|--------|-------|
| **Core Agent** | ✅ Complete | Sessions, workers, routing, context compaction |
| **Channels** | 🚧 Partial | TUI, HTTP, REPL, WASM channels done; messaging platforms pending |
| **Tools** | ✅ Complete | Built-in, MCP, WASM sandbox, dynamic builder |
| **Memory** | ✅ Complete | Hybrid search, embeddings, workspace filesystem |
| **Security** | ✅ Complete | WASM sandbox, prompt injection, leak detection |
| **Automation** | 🚧 Partial | Heartbeat done; cron, hooks pending |
| **Gateway** | ❌ Pending | WebSocket control plane, service management |
| **Web UI** | ❌ Pending | Control dashboard, WebChat |
| **Mobile/Desktop** | 🚫 Out of scope | Focus on server-side initially |
### Self-Expanding
### Key Differences from OpenClaw
- **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
- **Rust vs TypeScript** - Native performance, single binary
- **WASM sandbox vs Docker** - Lightweight, capability-based security
- **PostgreSQL vs SQLite** - Production-ready persistence
- **NEAR AI primary** - Session-based auth with model proxy
### Persistent Memory
### Contributing
Pick an unassigned feature area in [FEATURE_PARITY.md](FEATURE_PARITY.md) and claim it.
- **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
@@ -64,14 +66,14 @@ Pick an unassigned feature area in [FEATURE_PARITY.md](FEATURE_PARITY.md) and cl
- Rust 1.85+
- PostgreSQL 15+ with pgvector extension
- NEAR AI session token
- NEAR AI session token (or other LLM provider)
### Build
```bash
# Clone the repository
git clone https://github.com/nearai/near-agent.git
cd near-agent
git clone https://github.com/nearai/ironclaw.git
cd ironclaw
# Build
cargo build --release
@@ -84,10 +86,10 @@ cargo test
```bash
# Create database
createdb near_agent
createdb ironclaw
# Enable pgvector
psql near_agent -c "CREATE EXTENSION IF NOT EXISTS vector;"
psql ironclaw -c "CREATE EXTENSION IF NOT EXISTS vector;"
# Run migrations
refinery migrate -c refinery.toml
@@ -99,12 +101,13 @@ Copy `.env.example` to `.env` and configure:
```bash
# Required
DATABASE_URL=postgres://user:pass@localhost/near_agent
DATABASE_URL=postgres://user:pass@localhost/ironclaw
NEARAI_SESSION_TOKEN=sess_...
# Optional: Enable channels
SLACK_BOT_TOKEN=xoxb-...
TELEGRAM_BOT_TOKEN=...
WHATSAPP_ACCESS_TOKEN=...
SLACK_BOT_TOKEN=xoxb-...
HTTP_PORT=8080
```
@@ -118,15 +121,51 @@ HTTP_PORT=8080
| `AGENT_MAX_PARALLEL_JOBS` | Max concurrent jobs (default: 5) | No |
| `SECRETS_MASTER_KEY` | 32+ byte key for secret encryption | For secrets |
## 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 │
│ ┌─────┐ ┌──────┐ ┌───────┐ ┌──────────┐
│ │ CLI │ │ HTTP │ │ Slack │ │ Telegram │
│ └──┬──┘ └─────┘ └───┬───┘ └────┬─────┘
│ └──────────────────┴───────────┘
│ ┌─────┐ ┌──────────┐ ┌──────────┐ ┌───────┐
│ │ CLI │ │ Telegram │ │ WhatsApp │ │ Slack │
│ └──┬──┘ └────┬─────┘ └────┬─────┘ └───┬───┘
│ └──────────┴─────────────┴───────────┘ │
│ │ │
│ ┌────▼────┐ │
│ │ Router │ Intent classification │
@@ -165,31 +204,6 @@ HTTP_PORT=8080
| **Workspace** | Persistent memory with hybrid search |
| **Safety Layer** | Prompt injection defense and content sanitization |
## Security
### WASM Sandbox
Untrusted tools run in a sandboxed WASM environment with:
- **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
- **Leak detection** - Scans requests and responses for secret exfiltration
- **Rate limiting** - Per-tool request limits (per-minute and per-hour)
- **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
- Pattern-based detection of injection attempts
- Content sanitization and escaping
- Policy rules with severity levels (Block/Warn/Review/Sanitize)
- Tool output wrapping for LLM context
## Usage
### CLI Mode
@@ -199,7 +213,7 @@ WASM ──► Allowlist ──► Leak Scan ──► Credential ──► Exec
cargo run
# With debug logging
RUST_LOG=near_agent=debug cargo run
RUST_LOG=ironclaw=debug cargo run
```
### HTTP Server
@@ -211,7 +225,7 @@ HTTP_PORT=8080 cargo run
# Send a request
curl -X POST http://localhost:8080/webhook \
-H "Content-Type: application/json" \
-d '{"message": "Hello, agent!"}'
-d '{"message": "Hello, IronClaw!"}'
```
## Development
@@ -230,6 +244,17 @@ cargo test
cargo test test_name
```
## OpenClaw Heritage
IronClaw is a Rust reimplementation inspired by [OpenClaw](https://github.com/openclaw/openclaw). See [FEATURE_PARITY.md](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:
+1 -1
View File
@@ -2,7 +2,7 @@
name = "slack-channel"
version = "0.1.0"
edition = "2021"
description = "Slack Events API channel for NEAR Agent"
description = "Slack Events API channel for IronClaw"
license = "MIT OR Apache-2.0"
[lib]
+1 -1
View File
@@ -1,4 +1,4 @@
//! Slack Events API channel for NEAR Agent.
//! Slack Events API channel for IronClaw.
//!
//! This WASM component implements the channel interface for handling Slack
//! webhooks and sending messages back to Slack.
+1 -1
View File
@@ -2,7 +2,7 @@
name = "telegram-channel"
version = "0.1.0"
edition = "2021"
description = "Telegram Bot API channel for NEAR Agent"
description = "Telegram Bot API channel for IronClaw"
license = "MIT OR Apache-2.0"
[lib]
+1 -1
View File
@@ -1,7 +1,7 @@
// Telegram API types have fields reserved for future use (entities, reply threading, etc.)
#![allow(dead_code)]
//! Telegram Bot API channel for NEAR Agent.
//! Telegram Bot API channel for IronClaw.
//!
//! This WASM component implements the channel interface for handling Telegram
//! webhooks and sending messages back via the Bot API.
+1 -1
View File
@@ -2,7 +2,7 @@
name = "whatsapp-channel"
version = "0.1.0"
edition = "2021"
description = "WhatsApp channel for near-agent using the Cloud API"
description = "WhatsApp Cloud API channel for IronClaw"
[lib]
crate-type = ["cdylib"]
+1 -1
View File
@@ -1,7 +1,7 @@
// WhatsApp API types have fields reserved for future use (contacts, statuses, etc.)
#![allow(dead_code)]
//! WhatsApp Cloud API channel for NEAR Agent.
//! WhatsApp Cloud API channel for IronClaw.
//!
//! This WASM component implements the channel interface for handling WhatsApp
//! webhooks and sending messages back via the Cloud API.
+6 -6
View File
@@ -1,6 +1,6 @@
# Building WASM Channels
This guide covers how to build WASM channel modules for the NEAR Agent.
This guide covers how to build WASM channel modules for IronClaw.
## Overview
@@ -19,7 +19,7 @@ channels/ # Or channels-src/
After building, deploy to:
```
~/.near-agent/channels/
~/.ironclaw/channels/
├── my-channel.wasm
└── my-channel.capabilities.json
```
@@ -31,7 +31,7 @@ After building, deploy to:
name = "my-channel"
version = "0.1.0"
edition = "2021"
description = "My messaging platform channel for NEAR Agent"
description = "My messaging platform channel for IronClaw"
[lib]
crate-type = ["cdylib"]
@@ -251,9 +251,9 @@ Create `my-channel.capabilities.json`:
cd channels/my-channel
cargo component build --release
# Deploy to ~/.near-agent/channels/
cp target/wasm32-wasip1/release/my_channel.wasm ~/.near-agent/channels/my-channel.wasm
cp my-channel.capabilities.json ~/.near-agent/channels/
# Deploy to ~/.ironclaw/channels/
cp target/wasm32-wasip1/release/my_channel.wasm ~/.ironclaw/channels/my-channel.wasm
cp my-channel.capabilities.json ~/.ironclaw/channels/
```
## Host Functions Available
+1 -1
View File
@@ -2,7 +2,7 @@
name = "slack-tool"
version = "0.1.0"
edition = "2021"
description = "Slack integration tool for NEAR Agent (WASM component)"
description = "Slack integration tool for IronClaw (WASM component)"
license = "MIT OR Apache-2.0"
publish = false
+8 -8
View File
@@ -1,6 +1,6 @@
# Slack WASM Tool
A standalone WASM component that provides Slack integration for NEAR Agent. This serves as both a functional tool and a template for building custom WASM tools.
A standalone WASM component that provides Slack integration for IronClaw. This serves as both a functional tool and a template for building custom WASM tools.
## Features
@@ -50,9 +50,9 @@ target/wasm32-wasip2/release/slack_tool.wasm
Copy the WASM and capabilities files to the agent's tools directory:
```bash
mkdir -p ~/.near-agent/tools
cp target/wasm32-wasip2/release/slack_tool.wasm ~/.near-agent/tools/slack.wasm
cp slack.capabilities.json ~/.near-agent/tools/
mkdir -p ~/.ironclaw/tools
cp target/wasm32-wasip2/release/slack_tool.wasm ~/.ironclaw/tools/slack.wasm
cp slack.capabilities.json ~/.ironclaw/tools/
```
### Option B: Database Storage (Production)
@@ -60,7 +60,7 @@ cp slack.capabilities.json ~/.near-agent/tools/
Use the agent CLI or API to store the tool:
```bash
near-agent tool install \
ironclaw tool install \
--name slack \
--wasm target/wasm32-wasip2/release/slack_tool.wasm \
--capabilities slack.capabilities.json
@@ -71,7 +71,7 @@ near-agent tool install \
Store your Slack bot token as a secret:
```bash
near-agent secret set slack_bot_token "xoxb-your-token-here"
ironclaw secret set slack_bot_token "xoxb-your-token-here"
```
Or via SQL:
@@ -88,7 +88,7 @@ VALUES ('your_user_id', 'slack_bot_token', ...);
{
"action": "send_message",
"channel": "#general",
"text": "Hello from the NEAR Agent!"
"text": "Hello from IronClaw!"
}
```
@@ -214,7 +214,7 @@ world sandboxed-tool {
Ensure you've stored the secret:
```bash
near-agent secret set slack_bot_token "xoxb-..."
ironclaw secret set slack_bot_token "xoxb-..."
```
### "Endpoint not in allowlist"
+1 -1
View File
@@ -1,4 +1,4 @@
//! Slack WASM Tool for NEAR Agent.
//! Slack WASM Tool for IronClaw.
//!
//! This is a standalone WASM component that provides Slack integration.
//! It demonstrates how to build external tools that can be dynamically
+1 -1
View File
@@ -147,7 +147,7 @@ impl AppState {
Self {
mode: InputMode::Editing,
messages: vec![ChatMessage::system(
"Welcome to NEAR Agent. Type a message or /help for commands.",
"Welcome to IronClaw. Type a message or /help for commands.",
)],
composer: ChatComposer::new(),
approval: None,
+2 -2
View File
@@ -64,7 +64,7 @@ impl Default for ReplChannel {
fn print_help() {
println!(
r#"
NEAR Agent REPL - Interactive debugging mode
IronClaw REPL - Interactive debugging mode
Commands:
/help Show this help message
@@ -116,7 +116,7 @@ impl Channel for ReplChannel {
let stdin = io::stdin();
let mut stdout = io::stdout();
println!("NEAR Agent REPL - Type /help for commands, /quit to exit");
println!("IronClaw REPL - Type /help for commands, /quit to exit");
println!();
loop {
+3 -3
View File
@@ -1,6 +1,6 @@
//! WASM channel loader for loading channels from files or directories.
//!
//! Loads WASM channel modules from the filesystem (default: ~/.near-agent/channels/).
//! Loads WASM channel modules from the filesystem (default: ~/.ironclaw/channels/).
//! Each channel consists of:
//! - `<name>.wasm` - The compiled WASM component
//! - `<name>.capabilities.json` - Channel capabilities and configuration
@@ -329,12 +329,12 @@ pub struct DiscoveredChannel {
/// Get the default channels directory path.
///
/// Returns ~/.near-agent/channels/
/// Returns ~/.ironclaw/channels/
#[allow(dead_code)]
pub fn default_channels_dir() -> PathBuf {
dirs::home_dir()
.unwrap_or_else(|| PathBuf::from("."))
.join(".near-agent")
.join(".ironclaw")
.join("channels")
}
+2 -2
View File
@@ -63,14 +63,14 @@
//! # Example Usage
//!
//! ```ignore
//! use near_agent::channels::wasm::{WasmChannelLoader, WasmChannelRuntime};
//! use ironclaw::channels::wasm::{WasmChannelLoader, WasmChannelRuntime};
//!
//! // Create runtime (can share engine with tool runtime)
//! let runtime = WasmChannelRuntime::new(config)?;
//!
//! // Load channels from directory
//! let loader = WasmChannelLoader::new(runtime);
//! let channels = loader.load_from_dir(Path::new("~/.near-agent/channels/")).await?;
//! let channels = loader.load_from_dir(Path::new("~/.ironclaw/channels/")).await?;
//!
//! // Add to channel manager
//! for channel in channels {
+4 -2
View File
@@ -13,8 +13,10 @@ pub use tool::{ToolCommand, run_tool_command};
use clap::{Parser, Subcommand};
#[derive(Parser, Debug)]
#[command(name = "near-agent")]
#[command(about = "LLM-powered autonomous agent for the NEAR AI marketplace")]
#[command(name = "ironclaw")]
#[command(
about = "Secure personal AI assistant that protects your data and expands its capabilities"
)]
#[command(version)]
pub struct Cli {
#[command(subcommand)]
+8 -8
View File
@@ -13,8 +13,8 @@ use crate::tools::wasm::{CapabilitiesFile, compute_binary_hash};
/// Default tools directory.
fn default_tools_dir() -> PathBuf {
dirs::home_dir()
.map(|h| h.join(".near-agent").join("tools"))
.unwrap_or_else(|| PathBuf::from(".near-agent/tools"))
.map(|h| h.join(".ironclaw").join("tools"))
.unwrap_or_else(|| PathBuf::from(".ironclaw/tools"))
}
#[derive(Subcommand, Debug, Clone)]
@@ -32,7 +32,7 @@ pub enum ToolCommand {
#[arg(long)]
capabilities: Option<PathBuf>,
/// Target directory for installation (default: ~/.near-agent/tools/)
/// Target directory for installation (default: ~/.ironclaw/tools/)
#[arg(short, long)]
target: Option<PathBuf>,
@@ -51,7 +51,7 @@ pub enum ToolCommand {
/// List installed tools
List {
/// Directory to list tools from (default: ~/.near-agent/tools/)
/// Directory to list tools from (default: ~/.ironclaw/tools/)
#[arg(short, long)]
dir: Option<PathBuf>,
@@ -65,7 +65,7 @@ pub enum ToolCommand {
/// Name of the tool to remove
name: String,
/// Directory to remove tool from (default: ~/.near-agent/tools/)
/// Directory to remove tool from (default: ~/.ironclaw/tools/)
#[arg(short, long)]
dir: Option<PathBuf>,
},
@@ -75,7 +75,7 @@ pub enum ToolCommand {
/// Name of the tool or path to .wasm file
name_or_path: String,
/// Directory to look for tool (default: ~/.near-agent/tools/)
/// Directory to look for tool (default: ~/.ironclaw/tools/)
#[arg(short, long)]
dir: Option<PathBuf>,
},
@@ -420,7 +420,7 @@ async fn list_tools(dir: Option<PathBuf>, verbose: bool) -> anyhow::Result<()> {
if !tools_dir.exists() {
println!("No tools directory found at {}", tools_dir.display());
println!("Install a tool with: near-agent tool install <path>");
println!("Install a tool with: ironclaw tool install <path>");
return Ok(());
}
@@ -674,7 +674,7 @@ mod tests {
#[test]
fn test_default_tools_dir() {
let dir = default_tools_dir();
assert!(dir.to_string_lossy().contains(".near-agent"));
assert!(dir.to_string_lossy().contains(".ironclaw"));
assert!(dir.to_string_lossy().contains("tools"));
}
}
+11 -11
View File
@@ -1,4 +1,4 @@
//! Configuration for the NEAR Agent.
//! Configuration for IronClaw.
use std::path::PathBuf;
use std::time::Duration;
@@ -192,7 +192,7 @@ pub struct NearAiConfig {
pub base_url: String,
/// Base URL for auth/refresh endpoints (default: https://private.near.ai)
pub auth_base_url: String,
/// Path to session file (default: ~/.near-agent/session.json)
/// Path to session file (default: ~/.ironclaw/session.json)
pub session_path: PathBuf,
/// API mode: "responses" (chat-api) or "chat_completions" (cloud-api)
pub api_mode: NearAiApiMode,
@@ -297,11 +297,11 @@ impl EmbeddingsConfig {
}
}
/// Get the default session file path (~/.near-agent/session.json).
/// Get the default session file path (~/.ironclaw/session.json).
fn default_session_path() -> PathBuf {
dirs::home_dir()
.unwrap_or_else(|| PathBuf::from("."))
.join(".near-agent")
.join(".ironclaw")
.join("session.json")
}
@@ -310,7 +310,7 @@ fn default_session_path() -> PathBuf {
pub struct ChannelsConfig {
pub cli: CliConfig,
pub http: Option<HttpConfig>,
/// Directory containing WASM channel modules (default: ~/.near-agent/channels/).
/// Directory containing WASM channel modules (default: ~/.ironclaw/channels/).
pub wasm_channels_dir: std::path::PathBuf,
/// Whether WASM channels are enabled.
pub wasm_channels_enabled: bool,
@@ -371,11 +371,11 @@ impl ChannelsConfig {
}
}
/// Get the default channels directory (~/.near-agent/channels/).
/// Get the default channels directory (~/.ironclaw/channels/).
fn default_channels_dir() -> PathBuf {
dirs::home_dir()
.unwrap_or_else(|| PathBuf::from("."))
.join(".near-agent")
.join(".ironclaw")
.join("channels")
}
@@ -395,7 +395,7 @@ pub struct AgentConfig {
impl AgentConfig {
fn from_env() -> Result<Self, ConfigError> {
Ok(Self {
name: optional_env("AGENT_NAME")?.unwrap_or_else(|| "near-agent".to_string()),
name: optional_env("AGENT_NAME")?.unwrap_or_else(|| "ironclaw".to_string()),
max_parallel_jobs: parse_optional_env("AGENT_MAX_PARALLEL_JOBS", 5)?,
job_timeout: Duration::from_secs(parse_optional_env("AGENT_JOB_TIMEOUT_SECS", 3600)?),
stuck_threshold: Duration::from_secs(parse_optional_env(
@@ -447,7 +447,7 @@ impl SafetyConfig {
pub struct WasmConfig {
/// Whether WASM tool execution is enabled.
pub enabled: bool,
/// Directory containing installed WASM tools (default: ~/.near-agent/tools/).
/// Directory containing installed WASM tools (default: ~/.ironclaw/tools/).
pub tools_dir: PathBuf,
/// Default memory limit in bytes (default: 10 MB).
pub default_memory_limit: u64,
@@ -521,11 +521,11 @@ impl Default for WasmConfig {
}
}
/// Get the default tools directory (~/.near-agent/tools/).
/// Get the default tools directory (~/.ironclaw/tools/).
fn default_tools_dir() -> PathBuf {
dirs::home_dir()
.unwrap_or_else(|| PathBuf::from("."))
.join(".near-agent")
.join(".ironclaw")
.join("tools")
}
+1 -1
View File
@@ -1,4 +1,4 @@
//! Error types for the NEAR Agent.
//! Error types for IronClaw.
use std::time::Duration;
+5 -5
View File
@@ -1,7 +1,7 @@
//! Session management for NEAR AI authentication.
//!
//! Handles session token persistence, expiration detection, and renewal via
//! OAuth flow. Tokens are stored in `~/.near-agent/session.json` and refreshed
//! OAuth flow. Tokens are stored in `~/.ironclaw/session.json` and refreshed
//! automatically when expired.
use std::path::PathBuf;
@@ -29,7 +29,7 @@ pub struct SessionData {
pub struct SessionConfig {
/// Base URL for auth endpoints (e.g., https://private.near.ai).
pub auth_base_url: String,
/// Path to session file (e.g., ~/.near-agent/session.json).
/// Path to session file (e.g., ~/.ironclaw/session.json).
pub session_path: PathBuf,
/// Port range for OAuth callback server.
pub callback_port_range: (u16, u16),
@@ -45,11 +45,11 @@ impl Default for SessionConfig {
}
}
/// Get the default session file path (~/.near-agent/session.json).
/// Get the default session file path (~/.ironclaw/session.json).
pub fn default_session_path() -> PathBuf {
dirs::home_dir()
.unwrap_or_else(|| PathBuf::from("."))
.join(".near-agent")
.join(".ironclaw")
.join("session.json")
}
@@ -631,6 +631,6 @@ mod tests {
fn test_default_session_path() {
let path = default_session_path();
assert!(path.ends_with("session.json"));
assert!(path.to_string_lossy().contains(".near-agent"));
assert!(path.to_string_lossy().contains(".ironclaw"));
}
}
+6 -6
View File
@@ -1,11 +1,11 @@
//! NEAR Agent - Main entry point.
//! IronClaw - Main entry point.
use std::sync::Arc;
use clap::Parser;
use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitExt};
use near_agent::{
use ironclaw::{
agent::{Agent, AgentDeps},
channels::{
AppEvent, ChannelManager, HttpChannel, ReplChannel, TuiChannel,
@@ -74,7 +74,7 @@ async fn main() -> anyhow::Result<()> {
// automatically run the setup wizard
if !cli.no_setup {
let settings = Settings::load();
let session_path = near_agent::llm::session::default_session_path();
let session_path = ironclaw::llm::session::default_session_path();
if !settings.setup_completed && !session_path.exists() {
println!("First run detected. Starting setup wizard...");
@@ -102,7 +102,7 @@ async fn main() -> anyhow::Result<()> {
// Initialize tracing and channels based on mode
let env_filter = EnvFilter::try_from_default_env()
.unwrap_or_else(|_| EnvFilter::new("near_agent=info,tower_http=debug"));
.unwrap_or_else(|_| EnvFilter::new("ironclaw=info,tower_http=debug"));
// Determine which mode to use: REPL, single message, or TUI
let use_repl = cli.repl || cli.message.is_some();
@@ -150,7 +150,7 @@ async fn main() -> anyhow::Result<()> {
(None, None, None)
};
tracing::info!("Starting NEAR Agent...");
tracing::info!("Starting IronClaw...");
tracing::info!("Loaded configuration for agent: {}", config.agent.name);
tracing::info!("NEAR AI session authenticated");
@@ -578,7 +578,7 @@ async fn main() -> anyhow::Result<()> {
///
/// Returns the number of credentials injected.
async fn inject_channel_credentials(
channel: &Arc<near_agent::channels::wasm::WasmChannel>,
channel: &Arc<ironclaw::channels::wasm::WasmChannel>,
secrets: &dyn SecretsStore,
channel_name: &str,
) -> anyhow::Result<usize> {
+1 -1
View File
@@ -49,7 +49,7 @@
//! # Example
//!
//! ```rust,no_run
//! use near_agent::sandbox::{SandboxManager, SandboxManagerBuilder, SandboxPolicy};
//! use ironclaw::sandbox::{SandboxManager, SandboxManagerBuilder, SandboxPolicy};
//! use std::collections::HashMap;
//! use std::path::Path;
//!
+1 -1
View File
@@ -31,7 +31,7 @@
//! # Example
//!
//! ```ignore
//! use near_agent::secrets::{SecretsStore, PostgresSecretsStore, SecretsCrypto, CreateSecretParams};
//! use ironclaw::secrets::{SecretsStore, PostgresSecretsStore, SecretsCrypto, CreateSecretParams};
//! use secrecy::SecretString;
//!
//! // Initialize crypto with master key from environment
+3 -3
View File
@@ -1,6 +1,6 @@
//! User settings persistence.
//!
//! Stores user preferences like selected model in ~/.near-agent/settings.json.
//! Stores user preferences like selected model in ~/.ironclaw/settings.json.
use std::path::PathBuf;
@@ -55,11 +55,11 @@ pub struct ChannelSettings {
}
impl Settings {
/// Get the default settings file path (~/.near-agent/settings.json).
/// Get the default settings file path (~/.ironclaw/settings.json).
pub fn default_path() -> PathBuf {
dirs::home_dir()
.unwrap_or_else(|| PathBuf::from("."))
.join(".near-agent")
.join(".ironclaw")
.join("settings.json")
}
+2 -2
View File
@@ -1,4 +1,4 @@
//! Interactive setup wizard for NEAR Agent.
//! Interactive setup wizard for IronClaw.
//!
//! Provides a guided setup experience for:
//! - NEAR AI authentication
@@ -8,7 +8,7 @@
//! # Example
//!
//! ```ignore
//! use near_agent::setup::SetupWizard;
//! use ironclaw::setup::SetupWizard;
//!
//! let mut wizard = SetupWizard::new();
//! wizard.run().await?;
+1 -1
View File
@@ -259,7 +259,7 @@ pub fn confirm(prompt: &str, default: bool) -> io::Result<bool> {
/// # Example
///
/// ```ignore
/// print_header("NEAR Agent Setup Wizard");
/// print_header("IronClaw Setup Wizard");
/// ```
pub fn print_header(text: &str) {
let width = text.len() + 4;
+5 -5
View File
@@ -53,7 +53,7 @@ pub struct SetupConfig {
pub channels_only: bool,
}
/// Interactive setup wizard for NEAR Agent.
/// Interactive setup wizard for IronClaw.
pub struct SetupWizard {
config: SetupConfig,
settings: Settings,
@@ -87,7 +87,7 @@ impl SetupWizard {
/// Run the setup wizard.
pub async fn run(&mut self) -> Result<(), SetupError> {
print_header("NEAR Agent Setup Wizard");
print_header("IronClaw Setup Wizard");
let total_steps = if self.config.channels_only { 1 } else { 3 };
let mut current_step = 1;
@@ -336,7 +336,7 @@ impl SetupWizard {
// Discover available WASM channels
let channels_dir = dirs::home_dir()
.unwrap_or_default()
.join(".near-agent/channels");
.join(".ironclaw/channels");
let discovered_channels = discover_wasm_channels(&channels_dir).await;
@@ -438,7 +438,7 @@ impl SetupWizard {
})?;
println!();
print_success("Configuration saved to ~/.near-agent/");
print_success("Configuration saved to ~/.ironclaw/");
println!();
// Print summary
@@ -476,7 +476,7 @@ impl SetupWizard {
println!();
println!("To start the agent, run:");
println!(" near-agent");
println!(" ironclaw");
println!();
Ok(())
+1 -1
View File
@@ -218,7 +218,7 @@ pub struct BuilderConfig {
impl Default for BuilderConfig {
fn default() -> Self {
Self {
build_dir: std::env::temp_dir().join("near-agent-builds"),
build_dir: std::env::temp_dir().join("ironclaw-builds"),
max_iterations: 10,
timeout: Duration::from_secs(600), // 10 minutes
cleanup_on_failure: false, // Keep for debugging
+2 -2
View File
@@ -7,7 +7,7 @@
//! # Example: Loading from Directory
//!
//! ```text
//! ~/.near-agent/tools/
//! ~/.ironclaw/tools/
//! ├── slack.wasm
//! ├── slack.capabilities.json
//! ├── github.wasm
@@ -16,7 +16,7 @@
//!
//! ```ignore
//! let loader = WasmToolLoader::new(runtime, registry);
//! loader.load_from_dir(Path::new("~/.near-agent/tools/")).await?;
//! loader.load_from_dir(Path::new("~/.ironclaw/tools/")).await?;
//! ```
//!
//! # Security
+2 -2
View File
@@ -51,8 +51,8 @@
//! # Example
//!
//! ```ignore
//! use near_agent::tools::wasm::{WasmToolRuntime, WasmRuntimeConfig, WasmToolWrapper};
//! use near_agent::tools::wasm::Capabilities;
//! use ironclaw::tools::wasm::{WasmToolRuntime, WasmRuntimeConfig, WasmToolWrapper};
//! use ironclaw::tools::wasm::Capabilities;
//! use std::sync::Arc;
//!
//! // Create runtime
+7 -7
View File
@@ -9,8 +9,8 @@
use std::collections::HashMap;
use std::sync::Arc;
use near_agent::channels::Channel;
use near_agent::channels::wasm::{
use ironclaw::channels::Channel;
use ironclaw::channels::wasm::{
ChannelCapabilities, EmitRateLimitConfig, PreparedChannelModule, RegisteredEndpoint,
WasmChannel, WasmChannelRouter, WasmChannelRuntime, WasmChannelRuntimeConfig,
};
@@ -238,7 +238,7 @@ mod loader_tests {
async fn test_discover_channels_empty_dir() {
let dir = TempDir::new().expect("Failed to create temp dir");
let channels = near_agent::channels::wasm::discover_channels(dir.path())
let channels = ironclaw::channels::wasm::discover_channels(dir.path())
.await
.expect("Discovery failed");
@@ -253,7 +253,7 @@ mod loader_tests {
std::fs::File::create(dir.path().join("slack.wasm")).expect("Failed to create file");
std::fs::File::create(dir.path().join("telegram.wasm")).expect("Failed to create file");
let channels = near_agent::channels::wasm::discover_channels(dir.path())
let channels = ironclaw::channels::wasm::discover_channels(dir.path())
.await
.expect("Discovery failed");
@@ -284,7 +284,7 @@ mod loader_tests {
)
.expect("Failed to write capabilities");
let channels = near_agent::channels::wasm::discover_channels(dir.path())
let channels = ironclaw::channels::wasm::discover_channels(dir.path())
.await
.expect("Discovery failed");
@@ -301,7 +301,7 @@ mod loader_tests {
std::fs::File::create(dir.path().join("config.json")).expect("Failed to create file");
std::fs::File::create(dir.path().join("channel.wasm")).expect("Failed to create file");
let channels = near_agent::channels::wasm::discover_channels(dir.path())
let channels = ironclaw::channels::wasm::discover_channels(dir.path())
.await
.expect("Discovery failed");
@@ -388,7 +388,7 @@ mod capabilities_tests {
mod message_emission_tests {
use super::*;
use near_agent::channels::wasm::{ChannelHostState, EmittedMessage};
use ironclaw::channels::wasm::{ChannelHostState, EmittedMessage};
#[test]
fn test_emit_message_basic() {
+3 -3
View File
@@ -1,15 +1,15 @@
//! Integration tests for the workspace module.
//!
//! Requires a running PostgreSQL with pgvector extension.
//! Set DATABASE_URL=postgres://localhost/near_agent_test
//! Set DATABASE_URL=postgres://localhost/ironclaw_test
use std::sync::Arc;
use near_agent::workspace::{MockEmbeddings, SearchConfig, Workspace, paths};
use ironclaw::workspace::{MockEmbeddings, SearchConfig, Workspace, paths};
fn get_pool() -> deadpool_postgres::Pool {
let database_url = std::env::var("DATABASE_URL")
.unwrap_or_else(|_| "postgres://localhost/near_agent_test".to_string());
.unwrap_or_else(|_| "postgres://localhost/ironclaw_test".to_string());
let config: tokio_postgres::Config = database_url.parse().expect("Invalid DATABASE_URL");