1#![warn(clippy::all)]
2#![allow(
3 clippy::assigning_clones,
4 clippy::await_holding_lock,
5 clippy::bool_to_int_with_if,
6 clippy::case_sensitive_file_extension_comparisons,
7 clippy::cast_possible_truncation,
8 clippy::cast_sign_loss,
9 clippy::cast_possible_wrap,
10 clippy::doc_markdown,
11 clippy::collapsible_if,
12 clippy::collapsible_str_replace,
13 clippy::derivable_impls,
14 clippy::field_reassign_with_default,
15 clippy::float_cmp,
16 clippy::format_collect,
17 clippy::format_push_string,
18 clippy::if_not_else,
19 clippy::ignore_without_reason,
20 clippy::implicit_clone,
21 clippy::incompatible_msrv,
22 clippy::items_after_statements,
23 clippy::large_futures,
24 clippy::manual_pattern_char_comparison,
25 clippy::manual_string_new,
26 clippy::manual_unwrap_or_default,
27 clippy::map_unwrap_or,
28 clippy::match_same_arms,
29 clippy::match_wildcard_for_single_variants,
30 clippy::manual_let_else,
31 clippy::missing_errors_doc,
32 clippy::missing_panics_doc,
33 clippy::module_name_repetitions,
34 clippy::must_use_candidate,
35 clippy::needless_borrow,
36 clippy::needless_return,
37 clippy::new_ret_no_self,
38 clippy::new_without_default,
39 clippy::needless_pass_by_value,
40 clippy::needless_raw_string_hashes,
41 clippy::question_mark,
42 clippy::ref_option,
43 clippy::redundant_closure_for_method_calls,
44 clippy::return_self_not_must_use,
45 clippy::similar_names,
46 clippy::single_match_else,
47 clippy::struct_excessive_bools,
48 clippy::struct_field_names,
49 clippy::too_many_lines,
50 clippy::type_complexity,
51 clippy::uninlined_format_args,
52 clippy::unreadable_literal,
53 clippy::unnecessary_cast,
54 clippy::unnecessary_lazy_evaluations,
55 clippy::unnecessary_literal_bound,
56 clippy::unnecessary_map_or,
57 clippy::unused_async,
58 clippy::used_underscore_binding,
59 clippy::unused_self,
60 clippy::cast_precision_loss,
61 clippy::unnecessary_wraps,
62 dead_code
63)]
64
65use clap::Subcommand;
66use serde::{Deserialize, Serialize};
67
68pub mod agent;
69pub(crate) mod approval;
70pub(crate) mod auth;
71pub mod channels;
72pub mod config;
73pub(crate) mod cost;
74pub(crate) mod cron;
75pub(crate) mod daemon;
76pub(crate) mod doctor;
77pub mod gateway;
78pub mod grounding;
79pub(crate) mod hardware;
80pub(crate) mod health;
81pub(crate) mod heartbeat;
82pub mod hooks;
83pub(crate) mod identity;
84pub(crate) mod integrations;
85pub mod memory;
86pub(crate) mod migration;
87pub(crate) mod multimodal;
88pub mod observability;
89pub(crate) mod onboard;
90pub mod perception;
91pub mod peripherals;
92pub mod providers;
93pub mod rag;
94pub mod runtime;
95pub(crate) mod security;
96pub(crate) mod service;
97pub(crate) mod skills;
98pub mod tools;
99pub(crate) mod tunnel;
100pub(crate) mod util;
101
102pub use config::Config;
103
104#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
106pub enum ServiceCommands {
107 Install,
109 Start,
111 Stop,
113 Restart,
115 Status,
117 Uninstall,
119}
120
121#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
123pub enum ChannelCommands {
124 List,
126 Start,
128 Doctor,
130 #[command(long_about = "\
132Add a new channel configuration.
133
134Provide the channel type and a JSON object with the required \
135configuration keys for that channel type.
136
137Supported types: telegram, discord, slack, whatsapp, matrix, imessage, email.
138
139Examples:
140 gloamy channel add telegram '{\"bot_token\":\"...\",\"name\":\"my-bot\"}'
141 gloamy channel add discord '{\"bot_token\":\"...\",\"name\":\"my-discord\"}'")]
142 Add {
143 channel_type: String,
145 config: String,
147 },
148 Remove {
150 name: String,
152 },
153 #[command(long_about = "\
155Bind a Telegram identity into the allowlist.
156
157Adds a Telegram username (without the '@' prefix) or numeric user \
158ID to the channel allowlist so the agent will respond to messages \
159from that identity.
160
161Examples:
162 gloamy channel bind-telegram gloamy_user
163 gloamy channel bind-telegram 123456789")]
164 BindTelegram {
165 identity: String,
167 },
168}
169
170#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
172pub enum SkillCommands {
173 List,
175 Audit {
177 source: String,
179 },
180 Install {
182 source: String,
184 },
185 Remove {
187 name: String,
189 },
190}
191
192#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
194pub enum MigrateCommands {
195 Openclaw {
197 #[arg(long)]
199 source: Option<std::path::PathBuf>,
200
201 #[arg(long)]
203 dry_run: bool,
204 },
205}
206
207#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
209pub enum CronCommands {
210 List,
212 #[command(long_about = "\
214Add a new recurring scheduled task.
215
216Uses standard 5-field cron syntax: 'min hour day month weekday'. \
217Times are evaluated in UTC by default; use --tz with an IANA \
218timezone name to override.
219
220Examples:
221 gloamy cron add '0 9 * * 1-5' 'Good morning' --tz America/New_York
222 gloamy cron add '*/30 * * * *' 'Check system health'")]
223 Add {
224 expression: String,
226 #[arg(long)]
228 tz: Option<String>,
229 command: String,
231 },
232 #[command(long_about = "\
234Add a one-shot task that fires at a specific UTC timestamp.
235
236The timestamp must be in RFC 3339 format (e.g. 2025-01-15T14:00:00Z).
237
238Examples:
239 gloamy cron add-at 2025-01-15T14:00:00Z 'Send reminder'
240 gloamy cron add-at 2025-12-31T23:59:00Z 'Happy New Year!'")]
241 AddAt {
242 at: String,
244 command: String,
246 },
247 #[command(long_about = "\
249Add a task that repeats at a fixed interval.
250
251Interval is specified in milliseconds. For example, 60000 = 1 minute.
252
253Examples:
254 gloamy cron add-every 60000 'Ping heartbeat' # every minute
255 gloamy cron add-every 3600000 'Hourly report' # every hour")]
256 AddEvery {
257 every_ms: u64,
259 command: String,
261 },
262 #[command(long_about = "\
264Add a one-shot task that fires after a delay from now.
265
266Accepts human-readable durations: s (seconds), m (minutes), \
267h (hours), d (days).
268
269Examples:
270 gloamy cron once 30m 'Run backup in 30 minutes'
271 gloamy cron once 2h 'Follow up on deployment'
272 gloamy cron once 1d 'Daily check'")]
273 Once {
274 delay: String,
276 command: String,
278 },
279 Remove {
281 id: String,
283 },
284 #[command(long_about = "\
286Update one or more fields of an existing scheduled task.
287
288Only the fields you specify are changed; others remain unchanged.
289
290Examples:
291 gloamy cron update <task-id> --expression '0 8 * * *'
292 gloamy cron update <task-id> --tz Europe/London --name 'Morning check'
293 gloamy cron update <task-id> --command 'Updated message'")]
294 Update {
295 id: String,
297 #[arg(long)]
299 expression: Option<String>,
300 #[arg(long)]
302 tz: Option<String>,
303 #[arg(long)]
305 command: Option<String>,
306 #[arg(long)]
308 name: Option<String>,
309 },
310 Pause {
312 id: String,
314 },
315 Resume {
317 id: String,
319 },
320}
321
322#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
324pub enum MemoryCommands {
325 List {
327 #[arg(long)]
329 category: Option<String>,
330 #[arg(long)]
332 session: Option<String>,
333 #[arg(long, default_value = "50")]
335 limit: usize,
336 #[arg(long, default_value = "0")]
338 offset: usize,
339 },
340 Get {
342 key: String,
344 },
345 Stats,
347 Clear {
349 #[arg(long)]
351 key: Option<String>,
352 #[arg(long)]
354 category: Option<String>,
355 #[arg(long)]
357 yes: bool,
358 },
359}
360
361#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
363pub enum IntegrationCommands {
364 Info {
366 name: String,
368 },
369}
370
371#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
373pub enum HardwareCommands {
374 #[command(long_about = "\
376Enumerate USB devices and show known boards.
377
378Scans connected USB devices by VID/PID and matches them against \
379known development boards (STM32 Nucleo, Arduino, ESP32).
380
381Examples:
382 gloamy hardware discover")]
383 Discover,
384 #[command(long_about = "\
386Introspect a device by its serial or device path.
387
388Opens the specified device path and queries for board information, \
389firmware version, and supported capabilities.
390
391Examples:
392 gloamy hardware introspect /dev/ttyACM0
393 gloamy hardware introspect COM3")]
394 Introspect {
395 path: String,
397 },
398 #[command(long_about = "\
400Get chip info via USB using probe-rs over ST-Link.
401
402Queries the target MCU directly through the debug probe without \
403requiring any firmware on the target board.
404
405Examples:
406 gloamy hardware info
407 gloamy hardware info --chip STM32F401RETx")]
408 Info {
409 #[arg(long, default_value = "STM32F401RETx")]
411 chip: String,
412 },
413}
414
415#[derive(Subcommand, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
417pub enum PeripheralCommands {
418 List,
420 #[command(long_about = "\
422Add a peripheral by board type and transport path.
423
424Registers a hardware board so the agent can use its tools (GPIO, \
425sensors, actuators). Use 'native' as path for local GPIO on \
426single-board computers like Raspberry Pi.
427
428Supported boards: nucleo-f401re, rpi-gpio, esp32, arduino-uno.
429
430Examples:
431 gloamy peripheral add nucleo-f401re /dev/ttyACM0
432 gloamy peripheral add rpi-gpio native
433 gloamy peripheral add esp32 /dev/ttyUSB0")]
434 Add {
435 board: String,
437 path: String,
439 },
440 #[command(long_about = "\
442Flash Gloamy firmware to an Arduino board.
443
444Generates the .ino sketch, installs arduino-cli if it is not \
445already available, compiles, and uploads the firmware.
446
447Examples:
448 gloamy peripheral flash
449 gloamy peripheral flash --port /dev/cu.usbmodem12345
450 gloamy peripheral flash -p COM3")]
451 Flash {
452 #[arg(short, long)]
454 port: Option<String>,
455 },
456 SetupUnoQ {
458 #[arg(long)]
460 host: Option<String>,
461 },
462 FlashNucleo,
464}