diff --git a/CLAUDE.md b/CLAUDE.md index 6ae73405..1c5d81eb 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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 diff --git a/Cargo.lock b/Cargo.lock index 3f545e36..9230cda0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index 8af7ba00..9f8f6e50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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] diff --git a/FEATURE_PARITY.md b/FEATURE_PARITY.md index 3d44f86f..6f791052 100644 --- a/FEATURE_PARITY.md +++ b/FEATURE_PARITY.md @@ -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_ diff --git a/README.md b/README.md index 675b051a..d815c833 100644 --- a/README.md +++ b/README.md @@ -5,58 +5,60 @@

IronClaw

- LLM-powered autonomous agent for the NEAR AI marketplace + Your secure personal AI assistant, always on your side

+ PhilosophyFeatures • - ParityInstallationConfiguration • - Architecture • - Security + Security • + Architecture

--- +## 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: diff --git a/channels-src/slack/Cargo.toml b/channels-src/slack/Cargo.toml index c434519e..18d2fd39 100644 --- a/channels-src/slack/Cargo.toml +++ b/channels-src/slack/Cargo.toml @@ -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] diff --git a/channels-src/slack/src/lib.rs b/channels-src/slack/src/lib.rs index 18748833..adb2c5aa 100644 --- a/channels-src/slack/src/lib.rs +++ b/channels-src/slack/src/lib.rs @@ -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. diff --git a/channels-src/telegram/Cargo.toml b/channels-src/telegram/Cargo.toml index d33266e5..855aa8fa 100644 --- a/channels-src/telegram/Cargo.toml +++ b/channels-src/telegram/Cargo.toml @@ -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] diff --git a/channels-src/telegram/src/lib.rs b/channels-src/telegram/src/lib.rs index 8b5c7517..146b1e11 100644 --- a/channels-src/telegram/src/lib.rs +++ b/channels-src/telegram/src/lib.rs @@ -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. diff --git a/channels/whatsapp/Cargo.toml b/channels/whatsapp/Cargo.toml index 6e91d1f3..8dd03499 100644 --- a/channels/whatsapp/Cargo.toml +++ b/channels/whatsapp/Cargo.toml @@ -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"] diff --git a/channels/whatsapp/src/lib.rs b/channels/whatsapp/src/lib.rs index 6633ba4a..346c0f23 100644 --- a/channels/whatsapp/src/lib.rs +++ b/channels/whatsapp/src/lib.rs @@ -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. diff --git a/docs/BUILDING_CHANNELS.md b/docs/BUILDING_CHANNELS.md index 7032bda3..a819bc01 100644 --- a/docs/BUILDING_CHANNELS.md +++ b/docs/BUILDING_CHANNELS.md @@ -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 diff --git a/examples/wasm-tools/slack/Cargo.toml b/examples/wasm-tools/slack/Cargo.toml index 92e34820..83425bc8 100644 --- a/examples/wasm-tools/slack/Cargo.toml +++ b/examples/wasm-tools/slack/Cargo.toml @@ -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 diff --git a/examples/wasm-tools/slack/README.md b/examples/wasm-tools/slack/README.md index 2836643a..aee92f18 100644 --- a/examples/wasm-tools/slack/README.md +++ b/examples/wasm-tools/slack/README.md @@ -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" diff --git a/examples/wasm-tools/slack/src/lib.rs b/examples/wasm-tools/slack/src/lib.rs index 432ba31f..04cc2b70 100644 --- a/examples/wasm-tools/slack/src/lib.rs +++ b/examples/wasm-tools/slack/src/lib.rs @@ -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 diff --git a/src/channels/cli/app.rs b/src/channels/cli/app.rs index a0e76113..8bae51bb 100644 --- a/src/channels/cli/app.rs +++ b/src/channels/cli/app.rs @@ -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, diff --git a/src/channels/repl.rs b/src/channels/repl.rs index c9c3f452..1046460e 100644 --- a/src/channels/repl.rs +++ b/src/channels/repl.rs @@ -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 { diff --git a/src/channels/wasm/loader.rs b/src/channels/wasm/loader.rs index 5e94d38c..6ab145f2 100644 --- a/src/channels/wasm/loader.rs +++ b/src/channels/wasm/loader.rs @@ -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: //! - `.wasm` - The compiled WASM component //! - `.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") } diff --git a/src/channels/wasm/mod.rs b/src/channels/wasm/mod.rs index 24905fc0..7535d033 100644 --- a/src/channels/wasm/mod.rs +++ b/src/channels/wasm/mod.rs @@ -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 { diff --git a/src/cli/mod.rs b/src/cli/mod.rs index adc0a009..7fdcb3fe 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -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)] diff --git a/src/cli/tool.rs b/src/cli/tool.rs index bee90001..1fa2df89 100644 --- a/src/cli/tool.rs +++ b/src/cli/tool.rs @@ -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, - /// Target directory for installation (default: ~/.near-agent/tools/) + /// Target directory for installation (default: ~/.ironclaw/tools/) #[arg(short, long)] target: Option, @@ -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, @@ -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, }, @@ -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, }, @@ -420,7 +420,7 @@ async fn list_tools(dir: Option, 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 "); + println!("Install a tool with: ironclaw tool install "); 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")); } } diff --git a/src/config.rs b/src/config.rs index ee5d6668..5038fad8 100644 --- a/src/config.rs +++ b/src/config.rs @@ -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, - /// 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 { 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") } diff --git a/src/error.rs b/src/error.rs index 0f0d304a..a8fbced0 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,4 @@ -//! Error types for the NEAR Agent. +//! Error types for IronClaw. use std::time::Duration; diff --git a/src/llm/session.rs b/src/llm/session.rs index 05006e30..5a136171 100644 --- a/src/llm/session.rs +++ b/src/llm/session.rs @@ -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")); } } diff --git a/src/main.rs b/src/main.rs index 78944fe2..89eeaed8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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, + channel: &Arc, secrets: &dyn SecretsStore, channel_name: &str, ) -> anyhow::Result { diff --git a/src/sandbox/mod.rs b/src/sandbox/mod.rs index ca6e9f9f..5a7aed0f 100644 --- a/src/sandbox/mod.rs +++ b/src/sandbox/mod.rs @@ -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; //! diff --git a/src/secrets/mod.rs b/src/secrets/mod.rs index 7335ec82..06bdfc2d 100644 --- a/src/secrets/mod.rs +++ b/src/secrets/mod.rs @@ -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 diff --git a/src/settings.rs b/src/settings.rs index de2aea02..b5276d9b 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -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") } diff --git a/src/setup/mod.rs b/src/setup/mod.rs index c082c56c..50711ffa 100644 --- a/src/setup/mod.rs +++ b/src/setup/mod.rs @@ -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?; diff --git a/src/setup/prompts.rs b/src/setup/prompts.rs index 7a581cef..b07ae090 100644 --- a/src/setup/prompts.rs +++ b/src/setup/prompts.rs @@ -259,7 +259,7 @@ pub fn confirm(prompt: &str, default: bool) -> io::Result { /// # Example /// /// ```ignore -/// print_header("NEAR Agent Setup Wizard"); +/// print_header("IronClaw Setup Wizard"); /// ``` pub fn print_header(text: &str) { let width = text.len() + 4; diff --git a/src/setup/wizard.rs b/src/setup/wizard.rs index d63cf741..6ad22295 100644 --- a/src/setup/wizard.rs +++ b/src/setup/wizard.rs @@ -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(()) diff --git a/src/tools/builder/core.rs b/src/tools/builder/core.rs index cb441e2a..e46c8aaa 100644 --- a/src/tools/builder/core.rs +++ b/src/tools/builder/core.rs @@ -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 diff --git a/src/tools/wasm/loader.rs b/src/tools/wasm/loader.rs index 7fad73f9..0029b4c3 100644 --- a/src/tools/wasm/loader.rs +++ b/src/tools/wasm/loader.rs @@ -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 diff --git a/src/tools/wasm/mod.rs b/src/tools/wasm/mod.rs index c496acbe..378aa6ba 100644 --- a/src/tools/wasm/mod.rs +++ b/src/tools/wasm/mod.rs @@ -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 diff --git a/tests/wasm_channel_integration.rs b/tests/wasm_channel_integration.rs index 388ccc52..7ac0b909 100644 --- a/tests/wasm_channel_integration.rs +++ b/tests/wasm_channel_integration.rs @@ -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() { diff --git a/tests/workspace_integration.rs b/tests/workspace_integration.rs index 63519abb..568d00b9 100644 --- a/tests/workspace_integration.rs +++ b/tests/workspace_integration.rs @@ -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");