1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
//! Schedule — unified schedule definitions shared between mur CLI and Commander.
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// How to handle missed schedule executions.
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum MissedPolicy {
/// Skip missed executions
#[default]
Skip,
/// Run only the latest missed execution
RunLatest,
/// Run all missed executions
RunAll,
}
/// Who is ticking this schedule.
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum ScheduleExecutor {
/// System cron/launchd (mur CLI solo mode)
#[default]
SystemCron,
/// Commander daemon tick loop
Commander,
/// Server-side tick
Server,
}
/// Notification target for schedule results.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ScheduleNotify {
/// Notification type: slack_dm, slack_channel, terminal, webhook, none
#[serde(default, rename = "type")]
pub notify_type: String,
/// Target channel/user ID
#[serde(default)]
pub target: String,
}
/// Capability required to execute a workflow.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum Capability {
Shell,
Docker,
Browser,
Ai,
Http,
Ssh,
}
/// A schedule definition — the canonical shared type.
///
/// Used in `~/.mur/schedules.yaml` and synced to server.
/// Commander adds runtime state (last_run, next_run, etc.) separately.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Schedule {
/// Unique schedule ID
pub id: String,
/// Workflow name to execute
pub workflow: String,
/// Cron expression (5-7 fields)
pub cron: String,
/// Timezone (e.g. "Asia/Taipei", "UTC")
#[serde(default = "default_timezone")]
pub timezone: String,
/// Whether this schedule is active
#[serde(default = "default_enabled")]
pub enabled: bool,
/// Owner user ID (empty for solo mode)
#[serde(default)]
pub user_id: String,
/// Variables to pass to the workflow
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub variables: HashMap<String, String>,
/// Notification config
#[serde(default)]
pub notify: ScheduleNotify,
/// What to do when executions are missed
#[serde(default)]
pub on_missed: MissedPolicy,
/// Who is currently ticking this schedule
#[serde(default)]
pub executor: ScheduleExecutor,
}
fn default_timezone() -> String {
"UTC".into()
}
fn default_enabled() -> bool {
true
}
/// Container for schedules.yaml file format.
#[derive(Debug, Serialize, Deserialize)]
pub struct SchedulesFile {
#[serde(default)]
pub schedules: Vec<Schedule>,
}