Skip to content

Commit 81d5149

Browse files
authored
Merge pull request #72 from flashcatcloud/codex/automation-utc-help
fix: document automation schedules as UTC
2 parents 592bcb8 + 80051e2 commit 81d5149

3 files changed

Lines changed: 54 additions & 22 deletions

File tree

‎internal/cli/automation.go‎

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
)
1515

1616
const automationHTTPPostOnlyCron = "0 0 * * *"
17+
const automationUTCNote = "Convert local wall-clock requests to UTC before passing --at or --cron-expr."
1718

1819
func newAutomationCmd() *cobra.Command {
1920
cmd := &cobra.Command{
@@ -63,11 +64,14 @@ By default the rule is enabled. Use --disabled only when the user explicitly
6364
asks to create it disabled. team_id=0 means personal scope; --team-id >0 creates
6465
the rule under that team. The scope is immutable after creation.
6566
66-
Schedule helpers build a 5-field cron expression. Use --cron-expr for exact
67-
minute-level control. For HTTP POST-only rules, pass --http-post-trigger without
68-
a schedule; the CLI sends a valid placeholder cron and disables the schedule trigger.`, "Automations", "RuleWriteCreate"),
69-
Example: ` flashduty automation create --name "Daily SRE brief" --schedule daily --at 09:30 --prompt "Summarize yesterday's incidents"
70-
flashduty automation create --name "Weekly noise review" --team-id 123 --schedule weekly --weekday mon --at 10:00 --prompt-file ./prompt.md
67+
Schedule helpers build a 5-field UTC cron expression. --at and --cron-expr are
68+
interpreted in UTC, not the caller's local timezone. Convert local wall-clock
69+
requests to UTC before passing --at or --cron-expr.
70+
71+
For HTTP POST-only rules, pass --http-post-trigger without a schedule; the CLI
72+
sends a valid placeholder cron and disables the schedule trigger.`, "Automations", "RuleWriteCreate"),
73+
Example: ` flashduty automation create --name "Daily SRE brief" --schedule daily --at 01:30 --prompt "Summarize yesterday's incidents"
74+
flashduty automation create --name "Weekly noise review" --team-id 123 --schedule weekly --weekday mon --at 02:00 --prompt-file ./prompt.md
7175
flashduty automation create --name "Webhook triage" --http-post-trigger --prompt "Handle the posted payload"`,
7276
RunE: func(cmd *cobra.Command, args []string) error {
7377
return runCommand(cmd, args, func(ctx *RunContext) error {
@@ -111,10 +115,10 @@ a schedule; the CLI sends a valid placeholder cron and disables the schedule tri
111115

112116
cmd.Flags().StringVar(&name, "name", "", "Automation name")
113117
cmd.Flags().Int64Var(&teamID, "team-id", 0, "Scope team ID; 0 means personal scope")
114-
cmd.Flags().StringVar(&schedule, "schedule", "", "Schedule helper: hourly, daily, weekly, or cron")
115-
cmd.Flags().StringVar(&at, "at", "", "Wall-clock time in HH:MM; for hourly schedules, only the minute is used")
118+
cmd.Flags().StringVar(&schedule, "schedule", "", "UTC schedule helper: hourly, daily, weekly, or cron")
119+
cmd.Flags().StringVar(&at, "at", "", "UTC time in HH:MM; for hourly schedules, only the minute is used. "+automationUTCNote)
116120
cmd.Flags().StringVar(&weekday, "weekday", "", "Weekday for weekly schedules: sun, mon, tue, wed, thu, fri, sat, or 0-7")
117-
cmd.Flags().StringVar(&cronExpr, "cron-expr", "", "Exact 5-field cron expression; overrides --schedule helpers")
121+
cmd.Flags().StringVar(&cronExpr, "cron-expr", "", "Exact 5-field UTC cron expression; overrides --schedule helpers. "+automationUTCNote)
118122
cmd.Flags().BoolVar(&disabled, "disabled", false, "Create the Automation disabled")
119123
cmd.Flags().BoolVar(&scheduleEnabled, "schedule-enabled", true, "Whether the schedule trigger is enabled")
120124
cmd.Flags().BoolVar(&httpPostTrigger, "http-post-trigger", false, "Create and enable an HTTP POST trigger")
@@ -218,9 +222,13 @@ func newAutomationUpdateCmd() *cobra.Command {
218222
Short: "Update an Automation",
219223
Long: curatedLong(`Update mutable fields on an Automation rule.
220224
221-
The personal/team scope is intentionally not exposed here. Scope is immutable
222-
after creation; create a new Automation if the target person/team scope needs to change.`, "Automations", "RuleWriteUpdate"),
223-
Example: ` flashduty automation update auto_123 --name "Daily brief v2" --cron-expr "15 9 * * *"
225+
The personal/team scope is intentionally not exposed here. Scope is immutable
226+
after creation; create a new Automation if the target person/team scope needs to change.
227+
228+
Schedule helpers build a 5-field UTC cron expression. --at and --cron-expr are
229+
interpreted in UTC, not the caller's local timezone. Convert local wall-clock
230+
requests to UTC before passing --at or --cron-expr.`, "Automations", "RuleWriteUpdate"),
231+
Example: ` flashduty automation update auto_123 --name "Daily brief v2" --cron-expr "15 1 * * *"
224232
flashduty automation update auto_123 --disable
225233
flashduty automation update auto_123 --enable-http-post-trigger --rotate-http-post-token`,
226234
Args: requireExactArg("rule_id"),
@@ -311,10 +319,10 @@ after creation; create a new Automation if the target person/team scope needs to
311319
}
312320

313321
cmd.Flags().StringVar(&name, "name", "", "New Automation name")
314-
cmd.Flags().StringVar(&schedule, "schedule", "", "Schedule helper: hourly, daily, weekly, or cron")
315-
cmd.Flags().StringVar(&at, "at", "", "Wall-clock time in HH:MM; for hourly schedules, only the minute is used")
322+
cmd.Flags().StringVar(&schedule, "schedule", "", "UTC schedule helper: hourly, daily, weekly, or cron")
323+
cmd.Flags().StringVar(&at, "at", "", "UTC time in HH:MM; for hourly schedules, only the minute is used. "+automationUTCNote)
316324
cmd.Flags().StringVar(&weekday, "weekday", "", "Weekday for weekly schedules: sun, mon, tue, wed, thu, fri, sat, or 0-7")
317-
cmd.Flags().StringVar(&cronExpr, "cron-expr", "", "Exact 5-field cron expression; overrides --schedule helpers")
325+
cmd.Flags().StringVar(&cronExpr, "cron-expr", "", "Exact 5-field UTC cron expression; overrides --schedule helpers. "+automationUTCNote)
318326
cmd.Flags().BoolVar(&enableRule, "enable", false, "Enable the Automation")
319327
cmd.Flags().BoolVar(&disableRule, "disable", false, "Disable the Automation")
320328
cmd.Flags().BoolVar(&enableSchedule, "enable-schedule", false, "Enable the schedule trigger")

‎internal/cli/automation_test.go‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,28 @@ func TestAutomationCreateDailyDefaultsEnabled(t *testing.T) {
3434
assertBody(t, stub.lastBody, "prompt", "Summarize yesterday's incidents")
3535
}
3636

37+
func TestAutomationScheduleHelpDocumentsUTC(t *testing.T) {
38+
saveAndResetGlobals(t)
39+
40+
for _, args := range [][]string{
41+
{"automation", "create", "--help"},
42+
{"automation", "update", "auto_123", "--help"},
43+
} {
44+
out, err := execCommand(args...)
45+
if err != nil {
46+
t.Fatalf("%v unexpected error: %v", args, err)
47+
}
48+
for _, want := range []string{
49+
"UTC",
50+
"Convert local wall-clock requests to UTC before passing --at or --cron-expr.",
51+
} {
52+
if !strings.Contains(out, want) {
53+
t.Fatalf("%v help missing %q\n%s", args, want, out)
54+
}
55+
}
56+
}
57+
}
58+
3759
func TestAutomationCreateHTTPPostOnly(t *testing.T) {
3860
saveAndResetGlobals(t)
3961
stub := newGFStub(t)

‎skills/flashduty/reference/automation.md‎

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,14 @@ Prereq: `SKILL.md` read. Automations create AI SRE sessions on a schedule or thr
2929
## Scheduling
3030

3131
- Default create behavior: enabled immediately. Use `--disabled` only if the user asks for a disabled Automation.
32-
- No timezone flag is exposed by the current API. Build the requested wall-clock schedule in the account/customer timezone context.
32+
- No timezone flag is exposed by the current API. Automation schedules are stored and sent as UTC cron.
33+
- If the user asks for a local wall-clock schedule, first identify the intended timezone from the session context, runner `date`, or the user's wording. Convert that local time to UTC before calling the CLI. If the timezone is unclear, ask before creating or updating the schedule.
3334
- Helper schedules:
34-
- `--schedule hourly --at 00:15` -> minute 15 of every hour.
35-
- `--schedule daily --at 09:30` -> every day at 09:30.
36-
- `--schedule weekly --weekday mon --at 10:00` -> every Monday at 10:00.
37-
- For exact minute-level control, use `--cron-expr '<minute> <hour> <day> <month> <weekday>'`.
35+
- `--schedule hourly --at 00:15` -> minute 15 of every UTC hour.
36+
- `--schedule daily --at 01:30` -> every day at 01:30 UTC.
37+
- `--schedule weekly --weekday mon --at 02:00` -> every Monday at 02:00 UTC.
38+
- For exact minute-level control, use `--cron-expr '<minute> <hour> <day> <month> <weekday>'` in UTC.
39+
- Example: Asia/Shanghai 11:00 is UTC 03:00, so use `--schedule daily --at 03:00` or `--cron-expr "0 3 * * *"`.
3840
- HTTP POST-only rule: pass `--http-post-trigger` without schedule flags. The CLI sends a placeholder cron and disables the schedule trigger.
3941

4042
## Hot flow - create from chat
@@ -44,7 +46,7 @@ fduty automation create \
4446
--name "Daily SRE brief" \
4547
--team-id <team-id> \
4648
--schedule daily \
47-
--at 09:30 \
49+
--at 01:30 \
4850
--prompt "Summarize yesterday's incidents, noisy alerts, and follow-up risks." \
4951
--output-format toon
5052
```
@@ -72,7 +74,7 @@ fduty automation update <rule-id> --rotate-http-post-token --output-format toon
7274
```bash
7375
fduty automation create \
7476
--name "Weekday 08:05 review" \
75-
--cron-expr "5 8 * * 1-5" \
77+
--cron-expr "5 0 * * 1-5" \
7678
--prompt "Review open incidents and alert noise before the workday." \
7779
--output-format toon
7880
```
@@ -85,7 +87,7 @@ fduty automation get <rule-id> --output-format toon
8587
fduty automation runs <rule-id> --since 7d --output-format toon
8688

8789
fduty automation update <rule-id> --disable --output-format toon
88-
fduty automation update <rule-id> --enable --cron-expr "30 9 * * *" --output-format toon
90+
fduty automation update <rule-id> --enable --cron-expr "30 1 * * *" --output-format toon
8991
fduty automation delete <rule-id> --force
9092
```
9193

0 commit comments

Comments
 (0)