Skip to main content

zeroclaw/
lib.rs

1#![warn(clippy::all, clippy::pedantic)]
2#![allow(
3    clippy::assigning_clones,
4    clippy::bool_to_int_with_if,
5    clippy::case_sensitive_file_extension_comparisons,
6    clippy::cast_possible_wrap,
7    clippy::doc_markdown,
8    clippy::field_reassign_with_default,
9    clippy::float_cmp,
10    clippy::implicit_clone,
11    clippy::items_after_statements,
12    clippy::map_unwrap_or,
13    clippy::manual_let_else,
14    clippy::missing_errors_doc,
15    clippy::missing_panics_doc,
16    clippy::module_name_repetitions,
17    clippy::must_use_candidate,
18    clippy::new_without_default,
19    clippy::needless_pass_by_value,
20    clippy::needless_raw_string_hashes,
21    clippy::redundant_closure_for_method_calls,
22    clippy::return_self_not_must_use,
23    clippy::similar_names,
24    clippy::single_match_else,
25    clippy::struct_field_names,
26    clippy::too_many_lines,
27    clippy::uninlined_format_args,
28    clippy::unnecessary_cast,
29    clippy::unnecessary_lazy_evaluations,
30    clippy::unnecessary_literal_bound,
31    clippy::unnecessary_map_or,
32    clippy::unused_self,
33    clippy::cast_precision_loss,
34    clippy::unnecessary_wraps,
35    dead_code
36)]
37
38use clap::Subcommand;
39use serde::{Deserialize, Serialize};
40
41pub mod agent;
42pub(crate) mod approval;
43pub(crate) mod auth;
44pub mod channels;
45pub mod config;
46pub(crate) mod cost;
47pub(crate) mod cron;
48pub(crate) mod daemon;
49pub(crate) mod doctor;
50pub mod gateway;
51pub(crate) mod hardware;
52pub(crate) mod health;
53pub(crate) mod heartbeat;
54pub mod hooks;
55pub(crate) mod identity;
56pub(crate) mod integrations;
57pub mod memory;
58pub(crate) mod migration;
59pub(crate) mod multimodal;
60pub mod observability;
61pub(crate) mod onboard;
62pub mod peripherals;
63pub mod providers;
64pub mod rag;
65pub mod runtime;
66pub(crate) mod security;
67pub(crate) mod service;
68pub(crate) mod skills;
69pub mod tools;
70pub(crate) mod tunnel;
71pub(crate) mod util;
72
73pub use config::Config;
74
75/// Service management subcommands
76#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
77pub enum ServiceCommands {
78    /// Install daemon service unit for auto-start and restart
79    Install,
80    /// Start daemon service
81    Start,
82    /// Stop daemon service
83    Stop,
84    /// Restart daemon service to apply latest config
85    Restart,
86    /// Check daemon service status
87    Status,
88    /// Uninstall daemon service unit
89    Uninstall,
90}
91
92/// Channel management subcommands
93#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
94pub enum ChannelCommands {
95    /// List all configured channels
96    List,
97    /// Start all configured channels (handled in main.rs for async)
98    Start,
99    /// Run health checks for configured channels (handled in main.rs for async)
100    Doctor,
101    /// Add a new channel configuration
102    #[command(long_about = "\
103Add a new channel configuration.
104
105Provide the channel type and a JSON object with the required \
106configuration keys for that channel type.
107
108Supported types: telegram, discord, slack, whatsapp, matrix, imessage, email.
109
110Examples:
111  zeroclaw channel add telegram '{\"bot_token\":\"...\",\"name\":\"my-bot\"}'
112  zeroclaw channel add discord '{\"bot_token\":\"...\",\"name\":\"my-discord\"}'")]
113    Add {
114        /// Channel type (telegram, discord, slack, whatsapp, matrix, imessage, email)
115        channel_type: String,
116        /// Optional configuration as JSON
117        config: String,
118    },
119    /// Remove a channel configuration
120    Remove {
121        /// Channel name to remove
122        name: String,
123    },
124    /// Bind a Telegram identity (username or numeric user ID) into allowlist
125    #[command(long_about = "\
126Bind a Telegram identity into the allowlist.
127
128Adds a Telegram username (without the '@' prefix) or numeric user \
129ID to the channel allowlist so the agent will respond to messages \
130from that identity.
131
132Examples:
133  zeroclaw channel bind-telegram zeroclaw_user
134  zeroclaw channel bind-telegram 123456789")]
135    BindTelegram {
136        /// Telegram identity to allow (username without '@' or numeric user ID)
137        identity: String,
138    },
139}
140
141/// Skills management subcommands
142#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
143pub enum SkillCommands {
144    /// List all installed skills
145    List,
146    /// Audit a skill source directory or installed skill name
147    Audit {
148        /// Skill path or installed skill name
149        source: String,
150    },
151    /// Install a new skill from a URL or local path
152    Install {
153        /// Source URL or local path
154        source: String,
155    },
156    /// Remove an installed skill
157    Remove {
158        /// Skill name to remove
159        name: String,
160    },
161}
162
163/// Migration subcommands
164#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
165pub enum MigrateCommands {
166    /// Import memory from an `OpenClaw` workspace into this `ZeroClaw` workspace
167    Openclaw {
168        /// Optional path to `OpenClaw` workspace (defaults to ~/.openclaw/workspace)
169        #[arg(long)]
170        source: Option<std::path::PathBuf>,
171
172        /// Validate and preview migration without writing any data
173        #[arg(long)]
174        dry_run: bool,
175    },
176}
177
178/// Cron subcommands
179#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
180pub enum CronCommands {
181    /// List all scheduled tasks
182    List,
183    /// Add a new scheduled task
184    #[command(long_about = "\
185Add a new recurring scheduled task.
186
187Uses standard 5-field cron syntax: 'min hour day month weekday'. \
188Times are evaluated in UTC by default; use --tz with an IANA \
189timezone name to override.
190
191Examples:
192  zeroclaw cron add '0 9 * * 1-5' 'Good morning' --tz America/New_York
193  zeroclaw cron add '*/30 * * * *' 'Check system health'")]
194    Add {
195        /// Cron expression
196        expression: String,
197        /// Optional IANA timezone (e.g. America/Los_Angeles)
198        #[arg(long)]
199        tz: Option<String>,
200        /// Command to run
201        command: String,
202    },
203    /// Add a one-shot scheduled task at an RFC3339 timestamp
204    #[command(long_about = "\
205Add a one-shot task that fires at a specific UTC timestamp.
206
207The timestamp must be in RFC 3339 format (e.g. 2025-01-15T14:00:00Z).
208
209Examples:
210  zeroclaw cron add-at 2025-01-15T14:00:00Z 'Send reminder'
211  zeroclaw cron add-at 2025-12-31T23:59:00Z 'Happy New Year!'")]
212    AddAt {
213        /// One-shot timestamp in RFC3339 format
214        at: String,
215        /// Command to run
216        command: String,
217    },
218    /// Add a fixed-interval scheduled task
219    #[command(long_about = "\
220Add a task that repeats at a fixed interval.
221
222Interval is specified in milliseconds. For example, 60000 = 1 minute.
223
224Examples:
225  zeroclaw cron add-every 60000 'Ping heartbeat'     # every minute
226  zeroclaw cron add-every 3600000 'Hourly report'    # every hour")]
227    AddEvery {
228        /// Interval in milliseconds
229        every_ms: u64,
230        /// Command to run
231        command: String,
232    },
233    /// Add a one-shot delayed task (e.g. "30m", "2h", "1d")
234    #[command(long_about = "\
235Add a one-shot task that fires after a delay from now.
236
237Accepts human-readable durations: s (seconds), m (minutes), \
238h (hours), d (days).
239
240Examples:
241  zeroclaw cron once 30m 'Run backup in 30 minutes'
242  zeroclaw cron once 2h 'Follow up on deployment'
243  zeroclaw cron once 1d 'Daily check'")]
244    Once {
245        /// Delay duration
246        delay: String,
247        /// Command to run
248        command: String,
249    },
250    /// Remove a scheduled task
251    Remove {
252        /// Task ID
253        id: String,
254    },
255    /// Update a scheduled task
256    #[command(long_about = "\
257Update one or more fields of an existing scheduled task.
258
259Only the fields you specify are changed; others remain unchanged.
260
261Examples:
262  zeroclaw cron update <task-id> --expression '0 8 * * *'
263  zeroclaw cron update <task-id> --tz Europe/London --name 'Morning check'
264  zeroclaw cron update <task-id> --command 'Updated message'")]
265    Update {
266        /// Task ID
267        id: String,
268        /// New cron expression
269        #[arg(long)]
270        expression: Option<String>,
271        /// New IANA timezone
272        #[arg(long)]
273        tz: Option<String>,
274        /// New command to run
275        #[arg(long)]
276        command: Option<String>,
277        /// New job name
278        #[arg(long)]
279        name: Option<String>,
280    },
281    /// Pause a scheduled task
282    Pause {
283        /// Task ID
284        id: String,
285    },
286    /// Resume a paused task
287    Resume {
288        /// Task ID
289        id: String,
290    },
291}
292
293/// Memory management subcommands
294#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
295pub enum MemoryCommands {
296    /// List memory entries with optional filters
297    List {
298        /// Filter by category (core, daily, conversation, or custom name)
299        #[arg(long)]
300        category: Option<String>,
301        /// Filter by session ID
302        #[arg(long)]
303        session: Option<String>,
304        /// Maximum number of entries to display
305        #[arg(long, default_value = "50")]
306        limit: usize,
307        /// Number of entries to skip (for pagination)
308        #[arg(long, default_value = "0")]
309        offset: usize,
310    },
311    /// Get a specific memory entry by key
312    Get {
313        /// Memory key to look up
314        key: String,
315    },
316    /// Show memory backend statistics and health
317    Stats,
318    /// Clear memories by category, by key, or clear all
319    Clear {
320        /// Delete a single entry by key (supports prefix match)
321        #[arg(long)]
322        key: Option<String>,
323        /// Only clear entries in this category
324        #[arg(long)]
325        category: Option<String>,
326        /// Skip confirmation prompt
327        #[arg(long)]
328        yes: bool,
329    },
330}
331
332/// Integration subcommands
333#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
334pub enum IntegrationCommands {
335    /// Show details about a specific integration
336    Info {
337        /// Integration name
338        name: String,
339    },
340}
341
342/// Hardware discovery subcommands
343#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
344pub enum HardwareCommands {
345    /// Enumerate USB devices (VID/PID) and show known boards
346    #[command(long_about = "\
347Enumerate USB devices and show known boards.
348
349Scans connected USB devices by VID/PID and matches them against \
350known development boards (STM32 Nucleo, Arduino, ESP32).
351
352Examples:
353  zeroclaw hardware discover")]
354    Discover,
355    /// Introspect a device by path (e.g. /dev/ttyACM0)
356    #[command(long_about = "\
357Introspect a device by its serial or device path.
358
359Opens the specified device path and queries for board information, \
360firmware version, and supported capabilities.
361
362Examples:
363  zeroclaw hardware introspect /dev/ttyACM0
364  zeroclaw hardware introspect COM3")]
365    Introspect {
366        /// Serial or device path
367        path: String,
368    },
369    /// Get chip info via USB (probe-rs over ST-Link). No firmware needed on target.
370    #[command(long_about = "\
371Get chip info via USB using probe-rs over ST-Link.
372
373Queries the target MCU directly through the debug probe without \
374requiring any firmware on the target board.
375
376Examples:
377  zeroclaw hardware info
378  zeroclaw hardware info --chip STM32F401RETx")]
379    Info {
380        /// Chip name (e.g. STM32F401RETx). Default: STM32F401RETx for Nucleo-F401RE
381        #[arg(long, default_value = "STM32F401RETx")]
382        chip: String,
383    },
384}
385
386/// Peripheral (hardware) management subcommands
387#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
388pub enum PeripheralCommands {
389    /// List configured peripherals
390    List,
391    /// Add a peripheral (board path, e.g. nucleo-f401re /dev/ttyACM0)
392    #[command(long_about = "\
393Add a peripheral by board type and transport path.
394
395Registers a hardware board so the agent can use its tools (GPIO, \
396sensors, actuators). Use 'native' as path for local GPIO on \
397single-board computers like Raspberry Pi.
398
399Supported boards: nucleo-f401re, rpi-gpio, esp32, arduino-uno.
400
401Examples:
402  zeroclaw peripheral add nucleo-f401re /dev/ttyACM0
403  zeroclaw peripheral add rpi-gpio native
404  zeroclaw peripheral add esp32 /dev/ttyUSB0")]
405    Add {
406        /// Board type (nucleo-f401re, rpi-gpio, esp32)
407        board: String,
408        /// Path for serial transport (/dev/ttyACM0) or "native" for local GPIO
409        path: String,
410    },
411    /// Flash ZeroClaw firmware to Arduino (creates .ino, installs arduino-cli if needed, uploads)
412    #[command(long_about = "\
413Flash ZeroClaw firmware to an Arduino board.
414
415Generates the .ino sketch, installs arduino-cli if it is not \
416already available, compiles, and uploads the firmware.
417
418Examples:
419  zeroclaw peripheral flash
420  zeroclaw peripheral flash --port /dev/cu.usbmodem12345
421  zeroclaw peripheral flash -p COM3")]
422    Flash {
423        /// Serial port (e.g. /dev/cu.usbmodem12345). If omitted, uses first arduino-uno from config.
424        #[arg(short, long)]
425        port: Option<String>,
426    },
427    /// Setup Arduino Uno Q Bridge app (deploy GPIO bridge for agent control)
428    SetupUnoQ {
429        /// Uno Q IP (e.g. 192.168.0.48). If omitted, assumes running ON the Uno Q.
430        #[arg(long)]
431        host: Option<String>,
432    },
433    /// Flash ZeroClaw firmware to Nucleo-F401RE (builds + probe-rs run)
434    FlashNucleo,
435}