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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
//! Path builders for the moadim jobs and handlers directory layout.
use OsString;
use PathBuf;
/// Environment variable that, when set, overrides the home directory all moadim paths resolve
/// under. Used by tests to redirect config/routines/jobs/agents/workbenches into a tempdir so they
/// never read or write the user's real `~/.config/moadim`.
const HOME_OVERRIDE_ENV: &str = "MOADIM_HOME_OVERRIDE";
/// Environment variable from the XDG Base Directory spec that relocates the user's config root.
const XDG_CONFIG_HOME_ENV: &str = "XDG_CONFIG_HOME";
/// Resolve the base home directory, honoring the [`HOME_OVERRIDE_ENV`] test seam when set.
///
/// Exposed to the crate so platform service installers resolve their home-relative paths (e.g. the
/// macOS LaunchAgents plist) through the same override seam, keeping tests off the real home.
pub
/// Resolve the config root the moadim config tree nests under, honoring the XDG Base Directory
/// spec.
///
/// When `$XDG_CONFIG_HOME` is set to an **absolute** path it is used verbatim; an unset, empty, or
/// relative value falls back to `$HOME/.config`. This mirrors the `dirs` crate that the Linux
/// systemd installer ([`crate::service`]) already uses for the unit path, so a user who relocates
/// their config root via `$XDG_CONFIG_HOME` gets a single coherent config tree instead of a
/// surprise second one under `~/.config`.
/// Resolve the config root from an explicit `$XDG_CONFIG_HOME` value and home directory.
///
/// Split out from [`config_root`] so the resolution rules are unit-testable without mutating
/// process-global environment variables. A relative `$XDG_CONFIG_HOME` is ignored, per the spec
/// ("All paths set in these environment variables must be absolute"). Falls back to `.` when the
/// home directory is undeterminable.
/// Returns the moadim config directory: `$XDG_CONFIG_HOME/moadim`, defaulting to `~/.config/moadim`.
/// Returns the path to `{config_dir}/jobs/` (default `~/.config/moadim/jobs/`).
/// Returns the path to `{config_dir}/handlers/` (default `~/.config/moadim/handlers/`).
/// Returns the path to `{jobs_dir}/{id}/`.
/// Returns the path to `{jobs_dir}/{id}/job.toml`.
/// Returns the path to `{jobs_dir}/{id}/job.local.toml`.
/// Returns the path to `{jobs_dir}/{id}/.gitignore`.
/// Returns the path to `{jobs_dir}/{id}/job.local.log`.
// ─── Routines ────────────────────────────────────────────────────────────────
/// Returns the path to `{config_dir}/routines/` (default `~/.config/moadim/routines/`).
/// Returns the path to `{routines_dir}/{id}/`.
/// Returns the path to `{routines_dir}/{id}/routine.toml`.
/// Returns the path to `{routines_dir}/{id}/prompt.md`.
/// Returns the path to `{routines_dir}/{id}/.gitignore`.
/// Returns the path to `{routines_dir}/{id}/state.local.toml`, the gitignored sidecar holding
/// daemon-written runtime state (e.g. `last_manual_trigger_at`) kept out of the tracked `routine.toml`.
///
/// The `.local.` infix matches the `*.local.*` pattern seeded into each routine's `.gitignore`, so
/// trigger churn never produces version-control diffs.
/// Returns the path to `{routines_dir}/{id}/scheduled.local.toml`, the gitignored sidecar that
/// records `last_scheduled_trigger_at`.
///
/// Unlike [`routine_state_path`] this sidecar is written by the routine's launch command (the
/// `printf` step of [`crate::routines::build_routine_command`]) at each scheduled cron firing, and is
/// only ever *read* by the daemon — kept in its own file so a daemon-side re-persist of
/// `state.local.toml` can't clobber the scheduler-written timestamp. The `.local.` infix matches the
/// `*.local.*` `.gitignore` pattern, so scheduled-fire churn never produces version-control diffs.
/// Returns the path to `{routines_dir}/{id}/run.sh`, a legacy per-routine launch script.
///
/// No longer generated — the crontab line now invokes `moadim schedule trigger <id>` directly. The
/// path is retained so [`crate::routine_storage::write_routine`] can delete any stale script left by
/// an older daemon.
// ─── Agent registry ──────────────────────────────────────────────────────────
/// Returns the path to `{config_dir}/agents/` (default `~/.config/moadim/agents/`).
/// Returns the path to `{agents_dir}/{name}.toml`.
// ─── Daemon runtime files ────────────────────────────────────────────────────
/// Returns the path to `{config_dir}/moadim.pid`, where the running server records its PID.
/// Returns the path to `{config_dir}/daemon.log`, where a backgrounded server writes its output.
/// Returns the path to `{config_dir}/.gitignore`, used to keep generated runtime
/// files (`*.pid`, `*.log`) out of version control when the config dir is tracked.
/// Returns the path to `~/.config/moadim/.lock`, a committed global lock that halts all routine
/// scheduling and manual triggers when present. Checked into version control so the lock can be
/// shared across machines via a git push/pull.
/// Returns the path to `~/.config/moadim/.local.lock`, a machine-local global lock that halts all
/// routine scheduling and manual triggers when present. The `.local.` infix matches the `*.local.*`
/// pattern seeded into the config `.gitignore`, so this sentinel never leaks into version control.
/// Returns the path to `~/.config/moadim/machine.local.toml`, the gitignored, per-machine file
/// that records this install's machine identity (the `name` used to match a routine/job's
/// `machines` targeting list). The `.local.` infix matches the `*.local.*` pattern seeded into the
/// config `.gitignore`, so a machine name set on one host never leaks into the shared config repo.
/// Returns the machine-config path under `home`, or `.` if `home` is `None`.
pub
// ─── System prompts ──────────────────────────────────────────────────────────
/// Returns the path to `{config_dir}/user_prompt.md`, where the user writes a persistent
/// system prompt injected into every agent workbench `CLAUDE.md` alongside the moadim prompt.
// ─── Workbenches ─────────────────────────────────────────────────────────────
/// Returns the path to `~/.moadim/`.
/// Returns the moadim home directory under `home`, or `.` if `home` is `None`.
pub
/// Returns the path to `~/.moadim/workbenches/`.