Pin ubuntu:22.04 to its current manifest digest to ensure
reproducible builds and prevent supply-chain mutations.
Closes#513
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Replace floating tag refs (@v1, @v2) with SHA-pinned refs to prevent
supply-chain attacks via tag mutation on third-party Actions.
Pinned:
- useblacksmith/setup-docker-builder@v1 → ef12d5b1
- useblacksmith/build-push-action@v2 → 30c71162
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(security): add config file permission hardening
Set 0o600 permissions on newly created config.toml files and warn if
an existing config file is world-readable. Prevents accidental exposure
of API keys on multi-user systems. Unix-only (#[cfg(unix)]).
Follows existing pattern from src/security/secrets.rs.
Closes#517
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* style: apply rustfmt formatting
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(memory): add session_id isolation to Memory trait
Add optional session_id parameter to store(), recall(), and list()
methods across the Memory trait and all four backends (sqlite, markdown,
lucid, none). This enables per-session memory isolation so different
agent sessions cannot cross-read each other's stored memories.
Changes:
- traits.rs: Add session_id: Option<&str> to store/recall/list
- sqlite.rs: Schema migration (ALTER TABLE ADD COLUMN session_id),
index, persist/filter by session_id in all query paths
- markdown.rs, lucid.rs, none.rs: Updated signatures
- All callers pass None for backward compatibility
- 5 new tests: session-filtered recall, cross-session isolation,
session-filtered list, no-filter returns all, migration idempotency
Closes#518
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(channels): fix discord _channel_id typo and lark missing reply_to
Pre-existing compilation errors on main after reply_to was added to
ChannelMessage: discord.rs used _channel_id (underscore prefix) but
referenced channel_id, and lark.rs was missing the reply_to field.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Add `lmstudio` / `lm-studio` as a built-in provider alias for local LM Studio instances
(`http://localhost:1234/v1`)
- Uses a dummy API key when none is provided, since LM Studio does not require authentication
- Users can connect to remote LM Studio instances via `custom:http://<ip>:1234/v1`
ChannelMessage.sender was used both for display (username) and as the
reply target in Channel::send(). For Telegram, sender is the username
(e.g. "unknown") while send() requires the numeric chat_id, causing
"Bad Request: chat not found" errors.
Add a dedicated reply_to field to ChannelMessage that stores the
channel-specific reply address (Telegram chat_id, Discord channel_id,
Slack channel, etc.). Update all channel implementations and dispatch
code to use reply_to for send/start_typing/stop_typing calls.
This also fixes the same latent bug in Discord and Slack channels where
sender (user ID) was incorrectly passed as the reply target.
`cargo install` places the binary in ~/.cargo/bin, which may not be in
the user's PATH by default. This adds an explicit export step so new
users don't hit a "not found" error after install.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add ProviderCapabilities struct to enable runtime detection of
provider-specific features, starting with native tool calling support.
This is a foundational change that enables future PRs to implement
intelligent tool calling mode selection (native vs prompt-guided).
Changes:
- Add ProviderCapabilities struct with native_tool_calling field
- Add capabilities() method to Provider trait with default impl
- Add unit tests for capabilities equality and defaults
Why:
- Current design cannot distinguish providers with native tool calling
- Needed to enable Gemini/Anthropic/OpenAI native function calling
- Fully backward compatible (all providers inherit default)
What did NOT change:
- No existing Provider methods modified
- No behavior changes for existing code
- Zero breaking changes
Testing:
- cargo test: all tests passed
- cargo fmt: pass
- cargo clippy: pass
Replace bare .body() call with .singlepart(SinglePart::plain()) to ensure
outgoing emails have explicit Content-Type: text/plain; charset=utf-8
header. This fixes recipients seeing raw quoted-printable encoding
(e.g., =E2=80=99) instead of properly decoded UTF-8 characters.
- Move ZEROCLAW_WORKSPACE check to the start of load_or_init()
- Use custom workspace for both config and workspace directories
- Fixes issue where env var was applied AFTER config loading
Fixes#417
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove unused import AsyncBufReadExt in compatible.rs
- Remove unused mut keywords from response and tx
- Remove unused variable 'name'
- Prefix unused parameters with _ in traits.rs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
browser.rs:
- Extract parse_browser_action() from Tool::execute, removing one
#[allow(clippy::too_many_lines)] suppression
irc.rs:
- Replace 10-parameter IrcChannel::new() with IrcChannelConfig struct,
removing #[allow(clippy::too_many_arguments)] suppression
- Update all call sites (mod.rs and tests)
Closes#366
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- feat(streaming): add streaming support for LLM responses (fixes#211)
- security(deps): remove vulnerable xmas-elf dependency via embuild (fixes#399)
- fix: resolve merge conflicts and integrate chat_with_tools from main
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>