#![warn(clippy::all, clippy::pedantic)]
#![allow(
clippy::assigning_clones,
clippy::bool_to_int_with_if,
clippy::case_sensitive_file_extension_comparisons,
clippy::cast_possible_wrap,
clippy::doc_markdown,
clippy::field_reassign_with_default,
clippy::float_cmp,
clippy::implicit_clone,
clippy::items_after_statements,
clippy::map_unwrap_or,
clippy::manual_let_else,
clippy::missing_errors_doc,
clippy::missing_panics_doc,
clippy::module_name_repetitions,
clippy::must_use_candidate,
clippy::new_without_default,
clippy::needless_pass_by_value,
clippy::needless_raw_string_hashes,
clippy::redundant_closure_for_method_calls,
clippy::return_self_not_must_use,
clippy::similar_names,
clippy::single_match_else,
clippy::struct_field_names,
clippy::too_many_lines,
clippy::uninlined_format_args,
clippy::unnecessary_cast,
clippy::unnecessary_lazy_evaluations,
clippy::unnecessary_literal_bound,
clippy::unnecessary_map_or,
clippy::unused_self,
clippy::cast_precision_loss,
clippy::unnecessary_wraps,
dead_code
)]
use clap::Subcommand;
use serde::{Deserialize, Serialize};
pub mod agent;
pub(crate) mod approval;
pub(crate) mod auth;
pub mod channels;
pub mod config;
pub(crate) mod cost;
pub(crate) mod cron;
pub(crate) mod daemon;
pub(crate) mod doctor;
pub mod gateway;
pub(crate) mod hardware;
pub(crate) mod health;
pub(crate) mod heartbeat;
pub mod hooks;
pub(crate) mod identity;
pub(crate) mod integrations;
pub mod memory;
pub(crate) mod migration;
pub(crate) mod multimodal;
pub mod observability;
pub(crate) mod onboard;
pub mod peripherals;
pub mod providers;
pub mod rag;
pub mod runtime;
pub(crate) mod security;
pub(crate) mod service;
pub(crate) mod skills;
pub mod tools;
pub(crate) mod tunnel;
pub(crate) mod util;
pub use config::Config;
#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum ServiceCommands {
Install,
Start,
Stop,
Restart,
Status,
Uninstall,
}
#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum ChannelCommands {
List,
Start,
Doctor,
#[command(long_about = "\
Add a new channel configuration.
Provide the channel type and a JSON object with the required \
configuration keys for that channel type.
Supported types: telegram, discord, slack, whatsapp, matrix, imessage, email.
Examples:
zeroclaw channel add telegram '{\"bot_token\":\"...\",\"name\":\"my-bot\"}'
zeroclaw channel add discord '{\"bot_token\":\"...\",\"name\":\"my-discord\"}'")]
Add {
channel_type: String,
config: String,
},
Remove {
name: String,
},
#[command(long_about = "\
Bind a Telegram identity into the allowlist.
Adds a Telegram username (without the '@' prefix) or numeric user \
ID to the channel allowlist so the agent will respond to messages \
from that identity.
Examples:
zeroclaw channel bind-telegram zeroclaw_user
zeroclaw channel bind-telegram 123456789")]
BindTelegram {
identity: String,
},
}
#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum SkillCommands {
List,
Audit {
source: String,
},
Install {
source: String,
},
Remove {
name: String,
},
}
#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum MigrateCommands {
Openclaw {
#[arg(long)]
source: Option<std::path::PathBuf>,
#[arg(long)]
dry_run: bool,
},
}
#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum CronCommands {
List,
#[command(long_about = "\
Add a new recurring scheduled task.
Uses standard 5-field cron syntax: 'min hour day month weekday'. \
Times are evaluated in UTC by default; use --tz with an IANA \
timezone name to override.
Examples:
zeroclaw cron add '0 9 * * 1-5' 'Good morning' --tz America/New_York
zeroclaw cron add '*/30 * * * *' 'Check system health'")]
Add {
expression: String,
#[arg(long)]
tz: Option<String>,
command: String,
},
#[command(long_about = "\
Add a one-shot task that fires at a specific UTC timestamp.
The timestamp must be in RFC 3339 format (e.g. 2025-01-15T14:00:00Z).
Examples:
zeroclaw cron add-at 2025-01-15T14:00:00Z 'Send reminder'
zeroclaw cron add-at 2025-12-31T23:59:00Z 'Happy New Year!'")]
AddAt {
at: String,
command: String,
},
#[command(long_about = "\
Add a task that repeats at a fixed interval.
Interval is specified in milliseconds. For example, 60000 = 1 minute.
Examples:
zeroclaw cron add-every 60000 'Ping heartbeat' # every minute
zeroclaw cron add-every 3600000 'Hourly report' # every hour")]
AddEvery {
every_ms: u64,
command: String,
},
#[command(long_about = "\
Add a one-shot task that fires after a delay from now.
Accepts human-readable durations: s (seconds), m (minutes), \
h (hours), d (days).
Examples:
zeroclaw cron once 30m 'Run backup in 30 minutes'
zeroclaw cron once 2h 'Follow up on deployment'
zeroclaw cron once 1d 'Daily check'")]
Once {
delay: String,
command: String,
},
Remove {
id: String,
},
#[command(long_about = "\
Update one or more fields of an existing scheduled task.
Only the fields you specify are changed; others remain unchanged.
Examples:
zeroclaw cron update <task-id> --expression '0 8 * * *'
zeroclaw cron update <task-id> --tz Europe/London --name 'Morning check'
zeroclaw cron update <task-id> --command 'Updated message'")]
Update {
id: String,
#[arg(long)]
expression: Option<String>,
#[arg(long)]
tz: Option<String>,
#[arg(long)]
command: Option<String>,
#[arg(long)]
name: Option<String>,
},
Pause {
id: String,
},
Resume {
id: String,
},
}
#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum MemoryCommands {
List {
#[arg(long)]
category: Option<String>,
#[arg(long)]
session: Option<String>,
#[arg(long, default_value = "50")]
limit: usize,
#[arg(long, default_value = "0")]
offset: usize,
},
Get {
key: String,
},
Stats,
Clear {
#[arg(long)]
key: Option<String>,
#[arg(long)]
category: Option<String>,
#[arg(long)]
yes: bool,
},
}
#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum IntegrationCommands {
Info {
name: String,
},
}
#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum HardwareCommands {
#[command(long_about = "\
Enumerate USB devices and show known boards.
Scans connected USB devices by VID/PID and matches them against \
known development boards (STM32 Nucleo, Arduino, ESP32).
Examples:
zeroclaw hardware discover")]
Discover,
#[command(long_about = "\
Introspect a device by its serial or device path.
Opens the specified device path and queries for board information, \
firmware version, and supported capabilities.
Examples:
zeroclaw hardware introspect /dev/ttyACM0
zeroclaw hardware introspect COM3")]
Introspect {
path: String,
},
#[command(long_about = "\
Get chip info via USB using probe-rs over ST-Link.
Queries the target MCU directly through the debug probe without \
requiring any firmware on the target board.
Examples:
zeroclaw hardware info
zeroclaw hardware info --chip STM32F401RETx")]
Info {
#[arg(long, default_value = "STM32F401RETx")]
chip: String,
},
}
#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum PeripheralCommands {
List,
#[command(long_about = "\
Add a peripheral by board type and transport path.
Registers a hardware board so the agent can use its tools (GPIO, \
sensors, actuators). Use 'native' as path for local GPIO on \
single-board computers like Raspberry Pi.
Supported boards: nucleo-f401re, rpi-gpio, esp32, arduino-uno.
Examples:
zeroclaw peripheral add nucleo-f401re /dev/ttyACM0
zeroclaw peripheral add rpi-gpio native
zeroclaw peripheral add esp32 /dev/ttyUSB0")]
Add {
board: String,
path: String,
},
#[command(long_about = "\
Flash ZeroClaw firmware to an Arduino board.
Generates the .ino sketch, installs arduino-cli if it is not \
already available, compiles, and uploads the firmware.
Examples:
zeroclaw peripheral flash
zeroclaw peripheral flash --port /dev/cu.usbmodem12345
zeroclaw peripheral flash -p COM3")]
Flash {
#[arg(short, long)]
port: Option<String>,
},
SetupUnoQ {
#[arg(long)]
host: Option<String>,
},
FlashNucleo,
}