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(crate) mod cli_input;
46pub mod commands;
47pub mod config;
48pub(crate) mod cost;
49pub mod cron;
50pub(crate) mod daemon;
51pub(crate) mod doctor;
52pub mod gateway;
53pub mod hands;
54pub(crate) mod hardware;
55pub(crate) mod health;
56pub(crate) mod heartbeat;
57pub mod hooks;
58pub mod i18n;
59pub(crate) mod identity;
60pub(crate) mod integrations;
61pub mod memory;
62pub(crate) mod migration;
63pub(crate) mod multimodal;
64pub mod nodes;
65pub mod observability;
66pub(crate) mod onboard;
67pub mod peripherals;
68pub mod providers;
69pub mod rag;
70pub mod routines;
71pub mod runtime;
72pub(crate) mod security;
73pub(crate) mod service;
74pub(crate) mod skills;
75pub mod sop;
76pub mod tools;
77pub(crate) mod trust;
78pub mod tui;
79pub(crate) mod tunnel;
80pub(crate) mod util;
81pub mod verifiable_intent;
82
83#[cfg(feature = "plugins-wasm")]
84pub mod plugins;
85
86pub use config::Config;
87
88#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
90pub enum GatewayCommands {
91 #[command(long_about = "\
93Start the gateway server (webhooks, websockets).
94
95Runs the HTTP/WebSocket gateway that accepts incoming webhook events \
96and WebSocket connections. Bind address defaults to the values in \
97your config file (gateway.host / gateway.port).
98
99Examples:
100 zeroclaw gateway start # use config defaults
101 zeroclaw gateway start -p 8080 # listen on port 8080
102 zeroclaw gateway start --host 0.0.0.0 # requires [gateway].allow_public_bind=true or a tunnel
103 zeroclaw gateway start -p 0 # random available port")]
104 Start {
105 #[arg(short, long)]
107 port: Option<u16>,
108
109 #[arg(long)]
112 host: Option<String>,
113 },
114 #[command(long_about = "\
116Restart the gateway server.
117
118Stops the running gateway if present, then starts a new instance \
119with the current configuration.
120
121Examples:
122 zeroclaw gateway restart # restart with config defaults
123 zeroclaw gateway restart -p 8080 # restart on port 8080")]
124 Restart {
125 #[arg(short, long)]
127 port: Option<u16>,
128
129 #[arg(long)]
132 host: Option<String>,
133 },
134 #[command(long_about = "\
136Show or generate the gateway pairing code.
137
138Displays the pairing code for connecting new clients without \
139restarting the gateway. Requires the gateway to be running.
140
141With --new, generates a fresh pairing code even if the gateway \
142was previously paired (useful for adding additional clients).
143
144Examples:
145 zeroclaw gateway get-paircode # show current pairing code
146 zeroclaw gateway get-paircode --new # generate a new pairing code")]
147 GetPaircode {
148 #[arg(long)]
150 new: bool,
151 },
152}
153
154#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
156pub enum ServiceCommands {
157 Install,
159 Start,
161 Stop,
163 Restart,
165 Status,
167 Uninstall,
169 Logs {
171 #[arg(short = 'n', long, default_value = "50")]
173 lines: usize,
174 #[arg(short, long)]
176 follow: bool,
177 },
178}
179
180#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
182pub enum ChannelCommands {
183 List,
185 Start,
187 Doctor,
189 #[command(long_about = "\
191Add a new channel configuration.
192
193Provide the channel type and a JSON object with the required \
194configuration keys for that channel type.
195
196Supported types: telegram, discord, slack, whatsapp, matrix, imessage, email.
197
198Examples:
199 zeroclaw channel add telegram '{\"bot_token\":\"...\",\"name\":\"my-bot\"}'
200 zeroclaw channel add discord '{\"bot_token\":\"...\",\"name\":\"my-discord\"}'")]
201 Add {
202 channel_type: String,
204 config: String,
206 },
207 Remove {
209 name: String,
211 },
212 #[command(long_about = "\
214Bind a Telegram identity into the allowlist.
215
216Adds a Telegram username (without the '@' prefix) or numeric user \
217ID to the channel allowlist so the agent will respond to messages \
218from that identity.
219
220Examples:
221 zeroclaw channel bind-telegram zeroclaw_user
222 zeroclaw channel bind-telegram 123456789")]
223 BindTelegram {
224 identity: String,
226 },
227 #[command(long_about = "\
229Send a one-off message to a configured channel.
230
231Sends a text message through the specified channel without starting \
232the full agent loop. Useful for scripted notifications, hardware \
233sensor alerts, and automation pipelines.
234
235The --channel-id selects the channel by its config section name \
236(e.g. 'telegram', 'discord', 'slack'). The --recipient is the \
237platform-specific destination (e.g. a Telegram chat ID).
238
239Examples:
240 zeroclaw channel send 'Someone is near your device.' --channel-id telegram --recipient 123456789
241 zeroclaw channel send 'Build succeeded!' --channel-id discord --recipient 987654321")]
242 Send {
243 message: String,
245 #[arg(long)]
247 channel_id: String,
248 #[arg(long)]
250 recipient: String,
251 },
252}
253
254#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
256pub enum SkillCommands {
257 List,
259 Audit {
261 source: String,
263 },
264 Install {
266 source: String,
268 },
269 Remove {
271 name: String,
273 },
274 Test {
276 name: Option<String>,
278 #[arg(long)]
280 verbose: bool,
281 },
282}
283
284#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
286pub enum MigrateCommands {
287 Openclaw {
289 #[arg(long)]
291 source: Option<std::path::PathBuf>,
292
293 #[arg(long)]
295 dry_run: bool,
296 },
297}
298
299#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
301pub enum CronCommands {
302 List,
304 #[command(long_about = "\
306Add a new recurring scheduled task.
307
308Uses standard 5-field cron syntax: 'min hour day month weekday'. \
309Times are evaluated in UTC by default; use --tz with an IANA \
310timezone name to override.
311
312Examples:
313 zeroclaw cron add '0 9 * * 1-5' 'Good morning' --tz America/New_York --agent
314 zeroclaw cron add '*/30 * * * *' 'Check system health' --agent
315 zeroclaw cron add '*/5 * * * *' 'echo ok'")]
316 Add {
317 expression: String,
319 #[arg(long)]
321 tz: Option<String>,
322 #[arg(long)]
324 agent: bool,
325 #[arg(long = "allowed-tool")]
327 allowed_tools: Vec<String>,
328 command: String,
330 },
331 #[command(long_about = "\
333Add a one-shot task that fires at a specific UTC timestamp.
334
335The timestamp must be in RFC 3339 format (e.g. 2025-01-15T14:00:00Z).
336
337Examples:
338 zeroclaw cron add-at 2025-01-15T14:00:00Z 'Send reminder'
339 zeroclaw cron add-at 2025-12-31T23:59:00Z 'Happy New Year!'")]
340 AddAt {
341 at: String,
343 #[arg(long)]
345 agent: bool,
346 #[arg(long = "allowed-tool")]
348 allowed_tools: Vec<String>,
349 command: String,
351 },
352 #[command(long_about = "\
354Add a task that repeats at a fixed interval.
355
356Interval is specified in milliseconds. For example, 60000 = 1 minute.
357
358Examples:
359 zeroclaw cron add-every 60000 'Ping heartbeat' # every minute
360 zeroclaw cron add-every 3600000 'Hourly report' # every hour")]
361 AddEvery {
362 every_ms: u64,
364 #[arg(long)]
366 agent: bool,
367 #[arg(long = "allowed-tool")]
369 allowed_tools: Vec<String>,
370 command: String,
372 },
373 #[command(long_about = "\
375Add a one-shot task that fires after a delay from now.
376
377Accepts human-readable durations: s (seconds), m (minutes), \
378h (hours), d (days).
379
380Examples:
381 zeroclaw cron once 30m 'Run backup in 30 minutes'
382 zeroclaw cron once 2h 'Follow up on deployment'
383 zeroclaw cron once 1d 'Daily check'")]
384 Once {
385 delay: String,
387 #[arg(long)]
389 agent: bool,
390 #[arg(long = "allowed-tool")]
392 allowed_tools: Vec<String>,
393 command: String,
395 },
396 Remove {
398 id: String,
400 },
401 #[command(long_about = "\
403Update one or more fields of an existing scheduled task.
404
405Only the fields you specify are changed; others remain unchanged.
406
407Examples:
408 zeroclaw cron update <task-id> --expression '0 8 * * *'
409 zeroclaw cron update <task-id> --tz Europe/London --name 'Morning check'
410 zeroclaw cron update <task-id> --command 'Updated message'")]
411 Update {
412 id: String,
414 #[arg(long)]
416 expression: Option<String>,
417 #[arg(long)]
419 tz: Option<String>,
420 #[arg(long)]
422 command: Option<String>,
423 #[arg(long)]
425 name: Option<String>,
426 #[arg(long = "allowed-tool")]
428 allowed_tools: Vec<String>,
429 },
430 Pause {
432 id: String,
434 },
435 Resume {
437 id: String,
439 },
440}
441
442#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
444pub enum MemoryCommands {
445 List {
447 #[arg(long)]
449 category: Option<String>,
450 #[arg(long)]
452 session: Option<String>,
453 #[arg(long, default_value = "50")]
455 limit: usize,
456 #[arg(long, default_value = "0")]
458 offset: usize,
459 },
460 Get {
462 key: String,
464 },
465 Stats,
467 Clear {
469 #[arg(long)]
471 key: Option<String>,
472 #[arg(long)]
474 category: Option<String>,
475 #[arg(long)]
477 yes: bool,
478 },
479}
480
481#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
483pub enum IntegrationCommands {
484 Info {
486 name: String,
488 },
489}
490
491#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
493pub enum HardwareCommands {
494 #[command(long_about = "\
496Enumerate USB devices and show known boards.
497
498Scans connected USB devices by VID/PID and matches them against \
499known development boards (STM32 Nucleo, Arduino, ESP32).
500
501Examples:
502 zeroclaw hardware discover")]
503 Discover,
504 #[command(long_about = "\
506Introspect a device by its serial or device path.
507
508Opens the specified device path and queries for board information, \
509firmware version, and supported capabilities.
510
511Examples:
512 zeroclaw hardware introspect /dev/ttyACM0
513 zeroclaw hardware introspect COM3")]
514 Introspect {
515 path: String,
517 },
518 #[command(long_about = "\
520Get chip info via USB using probe-rs over ST-Link.
521
522Queries the target MCU directly through the debug probe without \
523requiring any firmware on the target board.
524
525Examples:
526 zeroclaw hardware info
527 zeroclaw hardware info --chip STM32F401RETx")]
528 Info {
529 #[arg(long, default_value = "STM32F401RETx")]
531 chip: String,
532 },
533}
534
535#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
537pub enum PeripheralCommands {
538 List,
540 #[command(long_about = "\
542Add a peripheral by board type and transport path.
543
544Registers a hardware board so the agent can use its tools (GPIO, \
545sensors, actuators). Use 'native' as path for local GPIO on \
546single-board computers like Raspberry Pi.
547
548Supported boards: nucleo-f401re, rpi-gpio, esp32, arduino-uno.
549
550Examples:
551 zeroclaw peripheral add nucleo-f401re /dev/ttyACM0
552 zeroclaw peripheral add rpi-gpio native
553 zeroclaw peripheral add esp32 /dev/ttyUSB0")]
554 Add {
555 board: String,
557 path: String,
559 },
560 #[command(long_about = "\
562Flash ZeroClaw firmware to an Arduino board.
563
564Generates the .ino sketch, installs arduino-cli if it is not \
565already available, compiles, and uploads the firmware.
566
567Examples:
568 zeroclaw peripheral flash
569 zeroclaw peripheral flash --port /dev/cu.usbmodem12345
570 zeroclaw peripheral flash -p COM3")]
571 Flash {
572 #[arg(short, long)]
574 port: Option<String>,
575 },
576 SetupUnoQ {
578 #[arg(long)]
580 host: Option<String>,
581 },
582 FlashNucleo,
584}
585
586#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
588pub enum SopCommands {
589 List,
591 Validate {
593 name: Option<String>,
595 },
596 Show {
598 name: String,
600 },
601}