aias 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.envrc +1 -0
- data/.github/workflows/deploy-github-pages.yml +52 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +140 -0
- data/COMMITS.md +196 -0
- data/LICENSE.txt +21 -0
- data/README.md +249 -0
- data/Rakefile +27 -0
- data/aia_schedule_idea.md +256 -0
- data/docs/assets/images/logo.jpg +0 -0
- data/docs/cli/add.md +101 -0
- data/docs/cli/check.md +70 -0
- data/docs/cli/clear.md +45 -0
- data/docs/cli/dry-run.md +57 -0
- data/docs/cli/index.md +51 -0
- data/docs/cli/install.md +198 -0
- data/docs/cli/last.md +49 -0
- data/docs/cli/list.md +40 -0
- data/docs/cli/next.md +49 -0
- data/docs/cli/remove.md +87 -0
- data/docs/cli/show.md +54 -0
- data/docs/cli/uninstall.md +29 -0
- data/docs/cli/update.md +75 -0
- data/docs/getting-started/installation.md +69 -0
- data/docs/getting-started/quick-start.md +105 -0
- data/docs/guides/configuration-layering.md +168 -0
- data/docs/guides/cron-environment.md +112 -0
- data/docs/guides/scheduling-prompts.md +319 -0
- data/docs/guides/understanding-cron.md +134 -0
- data/docs/guides/validation.md +114 -0
- data/docs/index.md +100 -0
- data/docs/reference/api.md +409 -0
- data/docs/reference/architecture.md +122 -0
- data/docs/reference/environment.md +67 -0
- data/docs/reference/logging.md +73 -0
- data/example_prompts/code_health_check.md +51 -0
- data/example_prompts/daily_digest.md +19 -0
- data/example_prompts/morning_standup.md +19 -0
- data/example_prompts/reports/monthly_review.md +44 -0
- data/example_prompts/reports/weekly_summary.md +22 -0
- data/example_prompts/you_are_good.md +22 -0
- data/exe/aias +5 -0
- data/lib/aias/block_parser.rb +42 -0
- data/lib/aias/cli/add.rb +30 -0
- data/lib/aias/cli/check.rb +50 -0
- data/lib/aias/cli/clear.rb +11 -0
- data/lib/aias/cli/dry_run.rb +24 -0
- data/lib/aias/cli/install.rb +57 -0
- data/lib/aias/cli/last.rb +26 -0
- data/lib/aias/cli/list.rb +20 -0
- data/lib/aias/cli/next.rb +28 -0
- data/lib/aias/cli/remove.rb +14 -0
- data/lib/aias/cli/show.rb +18 -0
- data/lib/aias/cli/uninstall.rb +15 -0
- data/lib/aias/cli/update.rb +30 -0
- data/lib/aias/cli/version.rb +10 -0
- data/lib/aias/cli.rb +91 -0
- data/lib/aias/cron_describer.rb +142 -0
- data/lib/aias/crontab_manager.rb +140 -0
- data/lib/aias/env_file.rb +75 -0
- data/lib/aias/job_builder.rb +56 -0
- data/lib/aias/paths.rb +14 -0
- data/lib/aias/prompt_scanner.rb +111 -0
- data/lib/aias/schedule_config.rb +31 -0
- data/lib/aias/validator.rb +101 -0
- data/lib/aias/version.rb +5 -0
- data/lib/aias.rb +17 -0
- data/mkdocs.yml +137 -0
- data/sig/aias.rbs +4 -0
- metadata +191 -0
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
# Scheduling Prompts
|
|
2
|
+
|
|
3
|
+
## The `schedule:` Key
|
|
4
|
+
|
|
5
|
+
Add a single `schedule:` key to any AIA prompt's YAML frontmatter to make it a scheduled job:
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
---
|
|
9
|
+
description: Morning briefing
|
|
10
|
+
schedule: "0 8 * * *"
|
|
11
|
+
---
|
|
12
|
+
Summarize what happened overnight.
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The value is a plain string — either a standard cron expression or a natural language phrase that fugit understands. That is all `aias` needs. At install time `aias` calls `Fugit.parse_cronish` to resolve the value to a canonical cron expression, which is what gets written to the crontab.
|
|
16
|
+
|
|
17
|
+
## Enabling and Disabling
|
|
18
|
+
|
|
19
|
+
| Action | How |
|
|
20
|
+
|---|---|
|
|
21
|
+
| Enable scheduling | Add `schedule:` to the frontmatter |
|
|
22
|
+
| Disable scheduling | Remove the `schedule:` line, then run `aias update` |
|
|
23
|
+
| Change the schedule | Edit the `schedule:` value, then run `aias update` or `aias add PATH` |
|
|
24
|
+
|
|
25
|
+
Removing the `schedule:` line from a prompt that is already installed in the crontab does **not** automatically remove the cron entry. You must run `aias update` (full sync) or `aias remove PROMPT_ID` to remove it.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Schedule Formats
|
|
30
|
+
|
|
31
|
+
### Standard Cron Expressions
|
|
32
|
+
|
|
33
|
+
Five-field cron syntax:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
┌─ minute (0–59)
|
|
37
|
+
│ ┌─ hour (0–23)
|
|
38
|
+
│ │ ┌─ day (1–31)
|
|
39
|
+
│ │ │ ┌─ month (1–12 or jan–dec)
|
|
40
|
+
│ │ │ │ └─ weekday (0–7, 0=Sun, 7=Sun, or sun–sat)
|
|
41
|
+
│ │ │ │ │
|
|
42
|
+
* * * * *
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
```yaml
|
|
46
|
+
schedule: "0 8 * * *" # 8:00 AM every day
|
|
47
|
+
schedule: "30 6 * * 1-5" # 6:30 AM Monday–Friday
|
|
48
|
+
schedule: "0 */4 * * *" # every 4 hours (at 0, 4, 8, 12, 16, 20)
|
|
49
|
+
schedule: "0 9 1,15 * *" # 9 AM on the 1st and 15th of each month
|
|
50
|
+
schedule: "0 0 * * 0" # midnight every Sunday
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### `@` Shorthand Keywords
|
|
54
|
+
|
|
55
|
+
```yaml
|
|
56
|
+
schedule: "@hourly" # 0 * * * *
|
|
57
|
+
schedule: "@daily" # 0 0 * * *
|
|
58
|
+
schedule: "@weekly" # 0 0 * * 0
|
|
59
|
+
schedule: "@monthly" # 0 0 1 * *
|
|
60
|
+
schedule: "@yearly" # 0 0 1 1 *
|
|
61
|
+
schedule: "@midnight" # 0 0 * * *
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Natural Language Scheduling (fugit)
|
|
67
|
+
|
|
68
|
+
`aias` uses the [fugit](https://github.com/floraison/fugit) gem (version 1.12.1) to parse natural language schedule strings. fugit converts them to cron expressions via `Fugit.parse_cronish`.
|
|
69
|
+
|
|
70
|
+
**Important:** fugit 1.12.1 generates explicit time lists rather than the `*/N` step notation. For example, `every 6 hours` produces `0 0,6,12,18 * * *`, not `0 */6 * * *`. Both are equivalent in meaning, but the explicit form is what you will see in the crontab.
|
|
71
|
+
|
|
72
|
+
### Frequency Intervals
|
|
73
|
+
|
|
74
|
+
```yaml
|
|
75
|
+
schedule: "every minute" # 0,1,2,...,59 * * * * (every minute)
|
|
76
|
+
schedule: "every 5 minutes" # 0,5,10,15,20,25,30,35,40,45,50,55 * * * *
|
|
77
|
+
schedule: "every 10 minutes" # 0,10,20,30,40,50 * * * *
|
|
78
|
+
schedule: "every 30 minutes" # 0,30 * * * *
|
|
79
|
+
schedule: "every hour" # 0 * * * *
|
|
80
|
+
schedule: "every 2 hours" # 0 0,2,4,6,8,10,12,14,16,18,20,22 * * *
|
|
81
|
+
schedule: "every 4 hours" # 0 0,4,8,12,16,20 * * *
|
|
82
|
+
schedule: "every 6 hours" # 0 0,6,12,18 * * *
|
|
83
|
+
schedule: "every 12 hours" # 0 0,12 * * *
|
|
84
|
+
schedule: "every day" # 0 0 * * *
|
|
85
|
+
schedule: "every week" # 0 0 * * 0
|
|
86
|
+
schedule: "every month" # 0 0 1 * *
|
|
87
|
+
schedule: "every year" # 0 0 1 1 *
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Supported abbreviations:
|
|
91
|
+
|
|
92
|
+
| Abbreviation | Meaning |
|
|
93
|
+
|---|---|
|
|
94
|
+
| `s`, `sec`, `secs`, `second`, `seconds` | seconds |
|
|
95
|
+
| `m`, `min`, `mins`, `minute`, `minutes` | minutes |
|
|
96
|
+
| `h`, `hou`, `hour`, `hours` | hours |
|
|
97
|
+
| `d`, `day`, `days` | days |
|
|
98
|
+
| `M`, `month`, `months` | months (capital `M`) |
|
|
99
|
+
|
|
100
|
+
Note: `M` (capital) means months; `m` (lowercase) means minutes. Case matters here.
|
|
101
|
+
|
|
102
|
+
### Days of the Week
|
|
103
|
+
|
|
104
|
+
Day names are case-insensitive. Three-letter abbreviations work.
|
|
105
|
+
|
|
106
|
+
```yaml
|
|
107
|
+
schedule: "every monday" # 0 0 * * 1
|
|
108
|
+
schedule: "every tuesday" # 0 0 * * 2
|
|
109
|
+
schedule: "every friday" # 0 0 * * 5
|
|
110
|
+
schedule: "every weekday" # 0 0 * * 1,2,3,4,5
|
|
111
|
+
schedule: "every weekend" # 0 0 * * 6,0
|
|
112
|
+
schedule: "every monday and wednesday" # 0 0 * * 1,3
|
|
113
|
+
schedule: "every tuesday and monday at 5pm" # 0 17 * * 1,2
|
|
114
|
+
schedule: "every friday and saturday at 11pm" # 0 23 * * 5,6
|
|
115
|
+
schedule: "every Mon to Fri at 9am" # 0 9 * * 1,2,3,4,5
|
|
116
|
+
schedule: "every monday through friday at 9am" # 0 9 * * 1,2,3,4,5
|
|
117
|
+
schedule: "every Mon,Tue,Wed,Thu,Fri at 9am" # 0 9 * * 1,2,3,4,5
|
|
118
|
+
schedule: "every Mon, Tue, and Wed at 18:15" # 15 18 * * 1,2,3
|
|
119
|
+
schedule: "from Monday to Friday at 9am" # 0 9 * * 1,2,3,4,5
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Times of Day
|
|
123
|
+
|
|
124
|
+
```yaml
|
|
125
|
+
# Named times
|
|
126
|
+
schedule: "every day at noon" # 0 12 * * *
|
|
127
|
+
schedule: "every day at midnight" # 0 0 * * *
|
|
128
|
+
schedule: "every day at five" # 0 5 * * *
|
|
129
|
+
|
|
130
|
+
# 24-hour clock
|
|
131
|
+
schedule: "every day at 8:30" # 30 8 * * *
|
|
132
|
+
schedule: "every day at 16:00" # 0 16 * * *
|
|
133
|
+
schedule: "every day at 18:22" # 22 18 * * *
|
|
134
|
+
|
|
135
|
+
# AM/PM
|
|
136
|
+
schedule: "every day at 8am" # 0 8 * * *
|
|
137
|
+
schedule: "every day at 5pm" # 0 17 * * *
|
|
138
|
+
schedule: "every day at 8:30am" # 30 8 * * *
|
|
139
|
+
schedule: "every day at 8:30 pm" # 30 20 * * *
|
|
140
|
+
|
|
141
|
+
# Combined day + time
|
|
142
|
+
schedule: "every weekday at 9am" # 0 9 * * 1,2,3,4,5
|
|
143
|
+
schedule: "every monday at 9am" # 0 9 * * 1
|
|
144
|
+
|
|
145
|
+
# Multiple times — same minutes merge into one cron entry
|
|
146
|
+
schedule: "every day at 8am and 5pm" # 0 8,17 * * *
|
|
147
|
+
schedule: "every day at 8:00 and 17:00" # 0 8,17 * * *
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**Limitation:** When two times have *different* minutes (e.g. `8:15 and 17:45`), only the first time is used. Use two separate prompt files with individual `schedule:` lines if you need two runs at different minutes.
|
|
151
|
+
|
|
152
|
+
### 12 AM/PM Edge Cases
|
|
153
|
+
|
|
154
|
+
Noon and midnight have special handling:
|
|
155
|
+
|
|
156
|
+
```yaml
|
|
157
|
+
schedule: "every day at 12pm" # 0 12 * * * (noon)
|
|
158
|
+
schedule: "every day at 12am" # 0 0 * * * (midnight)
|
|
159
|
+
schedule: "every day at 12 noon" # 0 12 * * *
|
|
160
|
+
schedule: "every day at 12 midnight" # 0 0 * * *
|
|
161
|
+
schedule: "every day at 12:30pm" # 30 12 * * *
|
|
162
|
+
schedule: "every day at 12:30am" # 30 0 * * *
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Day of Month
|
|
166
|
+
|
|
167
|
+
Ordinal words (`1st`, `2nd`, `3rd`, etc.) and the word `last` are supported:
|
|
168
|
+
|
|
169
|
+
```yaml
|
|
170
|
+
schedule: "every 1st of the month at midnight" # 0 0 1 * *
|
|
171
|
+
schedule: "every 15th of the month at noon" # 0 12 15 * *
|
|
172
|
+
schedule: "every month on the 1st at 9am" # 0 9 1 * *
|
|
173
|
+
schedule: "every month on the 1st and 15th at noon" # 0 12 1,15 * *
|
|
174
|
+
schedule: "every month on the 1st and last at noon" # 0 12 1,L * *
|
|
175
|
+
schedule: "every month on days 1,15 at 10:00" # 0 10 1,15 * *
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Time Windows (Range Within a Day)
|
|
179
|
+
|
|
180
|
+
Run a job on every hour (or minute) within a time range:
|
|
181
|
+
|
|
182
|
+
```yaml
|
|
183
|
+
schedule: "every weekday 9am to 5pm on the hour" # 0 9,10,11,12,13,14,15,16,17 * * 1,2,3,4,5
|
|
184
|
+
schedule: "every hour, from 8am to 5pm" # 0 8,9,10,11,12,13,14,15,16,17 * * *
|
|
185
|
+
schedule: "every minute from 8am to 5pm" # * 8,9,10,11,12,13,14,15,16 * * *
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Timezone
|
|
189
|
+
|
|
190
|
+
Append `in TIMEZONE`, `on TIMEZONE`, or a bare timezone name:
|
|
191
|
+
|
|
192
|
+
```yaml
|
|
193
|
+
schedule: "every day at 9am in America/New_York" # 0 9 * * * America/New_York
|
|
194
|
+
schedule: "every day at 5pm on America/Chicago" # 0 17 * * * America/Chicago
|
|
195
|
+
schedule: "every day at midnight America/Los_Angeles" # 0 0 * * * America/Los_Angeles
|
|
196
|
+
schedule: "every day at 6pm UTC" # 0 18 * * * UTC
|
|
197
|
+
schedule: "every day at 9am in Etc/GMT+5" # 0 9 * * * Etc/GMT+5
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Supported formats: IANA city names (`America/New_York`, `Asia/Tokyo`, etc.), `UTC`, `Z`, and offset codes (`Etc/GMT+5`).
|
|
201
|
+
|
|
202
|
+
If no timezone is given, the job runs in the system timezone of the machine where cron is running.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Limitations
|
|
207
|
+
|
|
208
|
+
**`every 2 weeks` is not supported.** fugit does not parse multi-week intervals. Use a cron expression instead:
|
|
209
|
+
|
|
210
|
+
```yaml
|
|
211
|
+
schedule: "0 9 * * 1" # every Monday — effectively every week
|
|
212
|
+
schedule: "0 9 1,15 * *" # approximate bi-weekly (1st and 15th of month)
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**Maximum 256 characters.** Natural language strings longer than 256 characters are rejected.
|
|
216
|
+
|
|
217
|
+
**Two times with different minutes only fires at the first time.** `"every day at 8:15 and 17:45"` resolves to `15 8 * * *` — the 17:45 is silently dropped. Split into two prompts if you need both.
|
|
218
|
+
|
|
219
|
+
**`every 2 days` produces a long explicit list.** `"every 2 days"` resolves to `0 0 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 * *`. This is correct but verbose. A simpler alternative is the raw cron `"0 0 */2 * *"`.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Checking Your Schedule
|
|
224
|
+
|
|
225
|
+
Before installing, preview exactly what cron expression your `schedule:` string resolves to:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
aias dry-run
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
The output shows the literal cron line that will be written, so you can verify the expression is correct before committing it to the crontab.
|
|
232
|
+
|
|
233
|
+
You can also test a fugit parse directly in a Ruby one-liner:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
ruby -rfugit -e 'puts Fugit.parse_cronish("every weekday at 9am").to_cron_s'
|
|
237
|
+
# => 0 9 * * 1,2,3,4,5
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Parameters in Scheduled Prompts
|
|
243
|
+
|
|
244
|
+
If your prompt uses `parameters:`, **every parameter must have a default value**. Cron runs unattended — there is no interactive session to prompt for input.
|
|
245
|
+
|
|
246
|
+
**This will fail validation:**
|
|
247
|
+
|
|
248
|
+
```yaml
|
|
249
|
+
---
|
|
250
|
+
schedule: "0 8 * * *"
|
|
251
|
+
parameters:
|
|
252
|
+
topic: # no default — invalid for scheduled prompts
|
|
253
|
+
---
|
|
254
|
+
Write about <%= topic %>.
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
**This is valid:**
|
|
258
|
+
|
|
259
|
+
```yaml
|
|
260
|
+
---
|
|
261
|
+
schedule: "0 8 * * *"
|
|
262
|
+
parameters:
|
|
263
|
+
topic: "Ruby news" # default provided — safe to run unattended
|
|
264
|
+
---
|
|
265
|
+
Write about <%= topic %>.
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
`aias` rejects prompts with missing parameter defaults and warns during `update` or `add`. The prompt is excluded from the crontab.
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## Nested Prompts
|
|
273
|
+
|
|
274
|
+
Prompts in subdirectories work exactly the same. The full subpath (minus `.md`) becomes the prompt ID:
|
|
275
|
+
|
|
276
|
+
```
|
|
277
|
+
$AIA_PROMPTS_DIR/
|
|
278
|
+
reports/
|
|
279
|
+
weekly_digest.md → prompt ID: reports/weekly_digest
|
|
280
|
+
daily_digest.md → prompt ID: daily_digest
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
The log file mirrors the directory structure:
|
|
284
|
+
|
|
285
|
+
```
|
|
286
|
+
~/.config/aia/schedule/logs/reports/weekly_digest.log
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Quick Reference
|
|
292
|
+
|
|
293
|
+
| Natural language | Resolved cron |
|
|
294
|
+
|---|---|
|
|
295
|
+
| `every minute` | `0,1,...,59 * * * *` |
|
|
296
|
+
| `every 5 minutes` | `0,5,10,...,55 * * * *` |
|
|
297
|
+
| `every 10 minutes` | `0,10,20,30,40,50 * * * *` |
|
|
298
|
+
| `every 30 minutes` | `0,30 * * * *` |
|
|
299
|
+
| `every hour` | `0 * * * *` |
|
|
300
|
+
| `every 6 hours` | `0 0,6,12,18 * * *` |
|
|
301
|
+
| `every 12 hours` | `0 0,12 * * *` |
|
|
302
|
+
| `every day` | `0 0 * * *` |
|
|
303
|
+
| `every day at 8am` | `0 8 * * *` |
|
|
304
|
+
| `every day at noon` | `0 12 * * *` |
|
|
305
|
+
| `every day at midnight` | `0 0 * * *` |
|
|
306
|
+
| `every day at 8:30` | `30 8 * * *` |
|
|
307
|
+
| `every weekday` | `0 0 * * 1,2,3,4,5` |
|
|
308
|
+
| `every weekday at 9am` | `0 9 * * 1,2,3,4,5` |
|
|
309
|
+
| `every monday` | `0 0 * * 1` |
|
|
310
|
+
| `every monday at 9am` | `0 9 * * 1` |
|
|
311
|
+
| `every monday through friday at 9am` | `0 9 * * 1,2,3,4,5` |
|
|
312
|
+
| `every friday and saturday at 11pm` | `0 23 * * 5,6` |
|
|
313
|
+
| `every 1st of the month at midnight` | `0 0 1 * *` |
|
|
314
|
+
| `every 15th of the month at noon` | `0 12 15 * *` |
|
|
315
|
+
| `every month on the 1st and 15th at noon` | `0 12 1,15 * *` |
|
|
316
|
+
| `@daily` | `0 0 * * *` |
|
|
317
|
+
| `@weekly` | `0 0 * * 0` |
|
|
318
|
+
| `@monthly` | `0 0 1 * *` |
|
|
319
|
+
| `@hourly` | `0 * * * *` |
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Understanding Cron and Crontab
|
|
2
|
+
|
|
3
|
+
`aias` schedules AIA prompts using your operating system's built-in job scheduler: **cron**. This page explains what cron is, how it works, and how `aias` fits into it — so you know what is happening when you run `aias update`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## What Is Cron?
|
|
8
|
+
|
|
9
|
+
**Cron** is a time-based job scheduler built into every Unix-like operating system (macOS, Linux). It runs in the background at all times, waking up once per minute to check whether any scheduled job is due to run. When one is, cron launches it as a separate process and goes back to sleep.
|
|
10
|
+
|
|
11
|
+
Cron requires no ongoing configuration once a job is installed. Your Mac does not need to be awake — if the machine is asleep at the scheduled time, cron skips that run and waits for the next one. If you need guaranteed execution even after a missed run, look into `launchd` (macOS) or `systemd` timers (Linux) — but for most prompt scheduling purposes, cron is sufficient.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## What Is a Crontab?
|
|
16
|
+
|
|
17
|
+
**Crontab** (cron table) is the file that lists your scheduled jobs. Each user on the system has their own private crontab. Jobs in your crontab run as you, with your user permissions — they cannot see another user's files or processes.
|
|
18
|
+
|
|
19
|
+
To view your current crontab:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
crontab -l
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
If you have no scheduled jobs yet, this prints nothing (or "no crontab for \<user\>").
|
|
26
|
+
|
|
27
|
+
A crontab entry looks like this:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
0 8 * * * /bin/bash -c 'source ~/.config/aia/schedule/env.sh && aia daily_digest > ~/.config/aia/schedule/logs/daily_digest.log 2>&1'
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The five fields before the command are the **schedule expression**.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Reading a Cron Expression
|
|
38
|
+
|
|
39
|
+
A cron expression is five space-separated fields:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
┌─── minute (0–59)
|
|
43
|
+
│ ┌── hour (0–23)
|
|
44
|
+
│ │ ┌─ day of month (1–31)
|
|
45
|
+
│ │ │ ┌ month (1–12)
|
|
46
|
+
│ │ │ │ ┌ day of week (0–7, 0 and 7 = Sunday)
|
|
47
|
+
│ │ │ │ │
|
|
48
|
+
* * * * * command
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
An asterisk (`*`) means "every". Common examples:
|
|
52
|
+
|
|
53
|
+
| Expression | Meaning |
|
|
54
|
+
|---|---|
|
|
55
|
+
| `0 8 * * *` | Every day at 8:00 AM |
|
|
56
|
+
| `0 9 * * 1-5` | Every weekday (Mon–Fri) at 9:00 AM |
|
|
57
|
+
| `30 6 * * 1` | Every Monday at 6:30 AM |
|
|
58
|
+
| `0 */6 * * *` | Every 6 hours |
|
|
59
|
+
| `0 0 1 * *` | The 1st of every month at midnight |
|
|
60
|
+
|
|
61
|
+
`aias` also accepts natural language — `"every weekday at 9am"` — and converts it to a cron expression automatically using the [fugit](https://github.com/floraison/fugit) gem. Use `aias dry-run` to see the resolved expression before installing.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## How aias Manages Your Crontab
|
|
66
|
+
|
|
67
|
+
`aias` never overwrites your entire crontab. It owns a single marked block, delimited by comments:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
# BEGIN aias
|
|
71
|
+
0 8 * * * /bin/bash -c 'source ~/.config/aia/schedule/env.sh && aia daily_digest > ...'
|
|
72
|
+
0 9 * * 1-5 /bin/bash -c 'source ~/.config/aia/schedule/env.sh && aia standup > ...'
|
|
73
|
+
# END aias
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Any jobs you have added outside this block — whether written by hand or installed by another tool — are left completely untouched. `aias update` replaces only the content between the markers.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Why Cron Has No Environment
|
|
81
|
+
|
|
82
|
+
When cron launches a job it starts a new, bare-minimum process. Your shell profile (`~/.zshrc`, `~/.bash_profile`) is **not** sourced. Your `PATH` is reduced to `/usr/bin:/bin`. Your API keys, Ruby version manager shims, and `AIA_*` variables are gone.
|
|
83
|
+
|
|
84
|
+
This is the single biggest source of cron job failures. A command that works perfectly in your terminal fails silently under cron because `aia` is not on the stripped PATH.
|
|
85
|
+
|
|
86
|
+
`aias install` solves this once. It captures the critical parts of your live environment — `PATH`, `LANG`, `LC_ALL`, `AIA_*` variables, and `*_API_KEY` keys — and writes them to `~/.config/aia/schedule/env.sh`. Every `aias`-managed cron entry sources that file before running:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
source ~/.config/aia/schedule/env.sh && aia prompt_id > log 2>&1
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
See [Cron Environment](cron-environment.md) for the full details on what is captured and how to keep it current.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Crontab Commands You Should Know
|
|
97
|
+
|
|
98
|
+
| Command | What it does |
|
|
99
|
+
|---|---|
|
|
100
|
+
| `crontab -l` | Print your current crontab to the terminal |
|
|
101
|
+
| `crontab -e` | Open your crontab in `$EDITOR` for manual editing |
|
|
102
|
+
| `EDITOR=nano crontab -e` | Open with a specific editor |
|
|
103
|
+
| `crontab -r` | **Delete your entire crontab** — use with care |
|
|
104
|
+
|
|
105
|
+
> **Warning:** `crontab -r` removes *everything*, including any non-aias jobs. To remove only the `aias`-managed entries, use `aias clear`.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Checking Whether a Job Ran
|
|
110
|
+
|
|
111
|
+
Cron itself provides no built-in log viewer. `aias` directs each job's output to a per-prompt log file:
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
~/.config/aia/schedule/logs/<prompt_id>.log
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# View the log for a specific job
|
|
119
|
+
cat ~/.config/aia/schedule/logs/daily_digest.log
|
|
120
|
+
|
|
121
|
+
# Show when a job last ran
|
|
122
|
+
aias last
|
|
123
|
+
|
|
124
|
+
# Show when a job is next scheduled to run
|
|
125
|
+
aias next
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
If a job is failing, the log is the first place to look. Common causes and fixes are covered in [Cron Environment — Troubleshooting](cron-environment.md#troubleshooting).
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## macOS Notes
|
|
133
|
+
|
|
134
|
+
On macOS, cron is managed by `launchd` and runs continuously in the background — you do not need to start or enable it. However, macOS may show a **Full Disk Access** prompt the first time a cron job runs, because cron does not automatically inherit the permissions granted to your terminal. If a job fails with a permission error, open **System Settings → Privacy & Security → Full Disk Access** and add `/usr/sbin/cron`.
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Validation
|
|
2
|
+
|
|
3
|
+
Before writing anything to the crontab, `aias` validates every scheduled prompt. This prevents broken cron entries from silently failing at runtime.
|
|
4
|
+
|
|
5
|
+
## Validation Rules
|
|
6
|
+
|
|
7
|
+
### 1. Schedule Syntax
|
|
8
|
+
|
|
9
|
+
The `schedule:` value must be parseable as either a cron expression or a whenever DSL string.
|
|
10
|
+
|
|
11
|
+
`aias` validates this by evaluating a minimal whenever DSL fragment:
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
every '0 8 * * *' do
|
|
15
|
+
command 'true'
|
|
16
|
+
end
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Valid examples:**
|
|
20
|
+
|
|
21
|
+
```yaml
|
|
22
|
+
schedule: "0 8 * * *"
|
|
23
|
+
schedule: "@daily"
|
|
24
|
+
schedule: "every 1.day at 8:00am"
|
|
25
|
+
schedule: "every :monday at 9:00am"
|
|
26
|
+
schedule: "every 6.hours"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Invalid examples (fail with an error):**
|
|
30
|
+
|
|
31
|
+
```yaml
|
|
32
|
+
schedule: "every banana" # not valid whenever DSL
|
|
33
|
+
schedule: "0 8 *" # too few cron fields
|
|
34
|
+
schedule: "" # empty
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 2. Parameter Completeness
|
|
38
|
+
|
|
39
|
+
All `parameters:` keys must have non-nil, non-empty default values. Cron jobs run unattended — there is no interactive session to supply missing values.
|
|
40
|
+
|
|
41
|
+
```yaml
|
|
42
|
+
# VALID — all parameters have defaults
|
|
43
|
+
parameters:
|
|
44
|
+
topic: "Ruby news"
|
|
45
|
+
format: "bullet points"
|
|
46
|
+
|
|
47
|
+
# INVALID — missing default
|
|
48
|
+
parameters:
|
|
49
|
+
topic: # nil value — rejected
|
|
50
|
+
format: "" # empty string — rejected
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 3. AIA Binary
|
|
54
|
+
|
|
55
|
+
The `aia` binary must be locatable. Two checks are performed in order; if either succeeds, the prompt passes:
|
|
56
|
+
|
|
57
|
+
1. **Login-shell `which`** — spawns a login shell and runs `which aia`. This is the normal path when the shell profile initialises the version manager (rbenv, rvm, asdf, etc.).
|
|
58
|
+
|
|
59
|
+
2. **Fallback directory scan** — if the login-shell check fails (common when `rbenv init` is not in the bash login profile), `aias` scans these directories for an executable named `aia`:
|
|
60
|
+
|
|
61
|
+
| Directory | Manager |
|
|
62
|
+
|---|---|
|
|
63
|
+
| `~/.rbenv/shims` | rbenv |
|
|
64
|
+
| `~/.rbenv/bin` | rbenv |
|
|
65
|
+
| `~/.rvm/bin` | rvm |
|
|
66
|
+
| `~/.asdf/shims` | asdf |
|
|
67
|
+
| `/usr/local/bin` | Homebrew / manual |
|
|
68
|
+
| `/usr/bin` | system |
|
|
69
|
+
| `/opt/homebrew/bin` | Homebrew (Apple Silicon) |
|
|
70
|
+
|
|
71
|
+
Only an **executable** file satisfies the check — a non-executable file at the path is ignored.
|
|
72
|
+
|
|
73
|
+
If `aia` is not found by either method, **all** prompts fail this check — no jobs are installed.
|
|
74
|
+
|
|
75
|
+
The check result is cached per `Validator` instance (shell spawn is expensive).
|
|
76
|
+
|
|
77
|
+
### 4. Prompts Directory
|
|
78
|
+
|
|
79
|
+
`$AIA_PROMPTS_DIR` must be set, exist, and be readable. This check happens before scanning, not per-prompt. If it fails, `aias` exits immediately with an error.
|
|
80
|
+
|
|
81
|
+
## Validation Flow
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
For each prompt file with schedule: in frontmatter:
|
|
85
|
+
1. Check schedule syntax → error if invalid
|
|
86
|
+
2. Check parameter defaults → error per missing default
|
|
87
|
+
3. Check aia binary → error if not found (cached)
|
|
88
|
+
|
|
89
|
+
If all checks pass → prompt is included in install
|
|
90
|
+
If any check fails → prompt is skipped, warning to stderr
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The crontab write happens only after all valid prompts have been collected. A mix of valid and invalid prompts is handled gracefully — valid ones are installed, invalid ones are skipped.
|
|
94
|
+
|
|
95
|
+
## Seeing Validation Results
|
|
96
|
+
|
|
97
|
+
Use `aias check` to see validation results without modifying the crontab:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
aias check
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
INVALID (would be skipped by update):
|
|
105
|
+
bad_prompt: Schedule 'every banana': undefined method 'banana' for Integer
|
|
106
|
+
|
|
107
|
+
bad_params: Parameter 'topic' has no default value (required for unattended cron execution)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Use `aias dry-run` to see what the valid prompts would generate:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
aias dry-run
|
|
114
|
+
```
|
data/docs/index.md
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# aias
|
|
2
|
+
|
|
3
|
+
<table>
|
|
4
|
+
<tr>
|
|
5
|
+
<td width="40%" align="center" valign="top">
|
|
6
|
+
<img src="assets/images/logo.jpg" alt="aias"><br>
|
|
7
|
+
<em>"Schedule. Batch. Execute."</em>
|
|
8
|
+
</td>
|
|
9
|
+
<td width="60%" valign="top">
|
|
10
|
+
<h2>Key Features</h2>
|
|
11
|
+
<ul>
|
|
12
|
+
<li>Natural Language Scheduling</li>
|
|
13
|
+
<li>Zero Configuration</li>
|
|
14
|
+
<li>Reliable Cron Environment</li>
|
|
15
|
+
<li>MCP Server Support</li>
|
|
16
|
+
<li>Per-Prompt Overrides</li>
|
|
17
|
+
<li>Schedule-Specific Config</li>
|
|
18
|
+
<li>Single-Prompt Control</li>
|
|
19
|
+
<li>Full Sync on Update</li>
|
|
20
|
+
<li>Safe Validation</li>
|
|
21
|
+
<li>Rich Inspection Commands</li>
|
|
22
|
+
</ul>
|
|
23
|
+
</td>
|
|
24
|
+
</tr>
|
|
25
|
+
</table>
|
|
26
|
+
|
|
27
|
+
`aias` turns any AIA prompt into a recurring batch job by reading a `schedule:` key directly from its YAML frontmatter. It scans your prompts directory, validates each scheduled prompt, and installs the results into your crontab.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Commands
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
$ aias help
|
|
35
|
+
Commands:
|
|
36
|
+
aias add PATH # Add (or replace) a single scheduled prompt in the crontab
|
|
37
|
+
aias check # Diff view: scheduled prompts vs what is installed
|
|
38
|
+
aias clear # Remove all aias-managed crontab entries
|
|
39
|
+
aias dry-run # Show what `update` would write without touching the crontab
|
|
40
|
+
aias help [COMMAND] # Describe available commands or one specific command
|
|
41
|
+
aias install [PATTERN...] # Capture PATH, API keys, and env vars into ~/.config/aia/schedule/env.sh
|
|
42
|
+
aias last [N] # Show last-run time for installed jobs (default 5)
|
|
43
|
+
aias list # List all installed aias cron jobs
|
|
44
|
+
aias next [N] # Show next scheduled run time for installed jobs (default 5)
|
|
45
|
+
aias remove PROMPT_ID # Remove a single scheduled prompt from the crontab
|
|
46
|
+
aias show PROMPT_ID # Show the installed crontab entry for a single prompt
|
|
47
|
+
aias uninstall # Remove managed env block from ~/.config/aia/schedule/env.sh
|
|
48
|
+
aias update # Scan prompts, regenerate all crontab entries, and install
|
|
49
|
+
aias version # Print the aias version
|
|
50
|
+
|
|
51
|
+
Options:
|
|
52
|
+
-p, [--prompts-dir=PROMPTS_DIR] # Prompts directory (overrides AIA_PROMPTS__DIR / AIA_PROMPTS_DIR env vars)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## How It Works
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
Prompt file with schedule: in YAML frontmatter
|
|
61
|
+
│
|
|
62
|
+
▼
|
|
63
|
+
aias update scans prompts directory for schedule: keys
|
|
64
|
+
│
|
|
65
|
+
▼
|
|
66
|
+
Each prompt is validated: schedule syntax, parameter defaults, aia binary
|
|
67
|
+
│
|
|
68
|
+
▼
|
|
69
|
+
A cron entry is written for each valid prompt
|
|
70
|
+
│
|
|
71
|
+
▼
|
|
72
|
+
OS cron daemon runs each job on schedule:
|
|
73
|
+
source env.sh && aia [--prompts-dir DIR] prompt_id > log 2>&1
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Core Design Principles
|
|
79
|
+
|
|
80
|
+
**Self-describing prompts.** A prompt that wants to run on a schedule says so in its own frontmatter. No external config file maps prompts to schedules.
|
|
81
|
+
|
|
82
|
+
**Full sync on every `update`.** The entire managed crontab block is replaced on each run. Deleted or de-scheduled prompts are automatically removed — there are no orphaned entries to clean up manually.
|
|
83
|
+
|
|
84
|
+
**OS cron reliability.** No long-running daemon. The system cron daemon handles job execution, reboots, and missed runs. Each `aia` invocation is a fresh, clean process.
|
|
85
|
+
|
|
86
|
+
**Explicit environment capture.** `aias install` snapshots your live PATH, API keys, and AIA variables into `~/.config/aia/schedule/env.sh`. Every cron entry sources that file, giving `aia` the same environment it has in your interactive shell — without relying on a login shell that may rebuild PATH unexpectedly.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## At a Glance
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# Add schedule: to a prompt's frontmatter, then:
|
|
94
|
+
aias update # install all scheduled prompts into crontab
|
|
95
|
+
aias check # diff: prompts with schedule: vs what is installed
|
|
96
|
+
aias list # show all installed jobs
|
|
97
|
+
aias dry-run # preview what update would write
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
See the [Quick Start](getting-started/quick-start.md) to get running in under five minutes.
|