Skip to content

feat(daemon): add cron-based schedule triggers for workflows#433

Merged
zhubert merged 2 commits intomainfrom
issue-419
Mar 16, 2026
Merged

feat(daemon): add cron-based schedule triggers for workflows#433
zhubert merged 2 commits intomainfrom
issue-419

Conversation

@zhubert
Copy link
Copy Markdown
Owner

@zhubert zhubert commented Mar 16, 2026

Summary

  • Add a top-level triggers block to workflow config for cron-based scheduled workflows (standard 5-field cron syntax)
  • Each firing creates a synthetic work item that flows through the normal workflow state machine
  • Implements startScheduler/stopScheduler using robfig/cron/v3 with automatic skip in --once mode
  • Synthetic items skip issue-provider calls since they have no real issue backing them
  • Dedup prevents double-enqueue while a previous item from the same trigger is still active/queued

Note: The ai.summarize action has been extracted into #432.

Test plan

  • TestInjectScheduledIssue_EnqueuesWorkItem — verifies synthetic work item creation
  • TestInjectScheduledIssue_RespectsMaxConcurrent — verifies concurrency limit enforcement
  • TestInjectScheduledIssue_SkipsWhilePreviousActive — verifies dedup logic
  • TestInjectScheduledIssue_AllowedAfterPreviousCompletes — verifies re-enqueue after terminal
  • TestInjectScheduledIssue_SkippedWhenConfigSavePaused — verifies safety check
  • TestFetchIssueComments_SkipsSyntheticItems — verifies synthetic skip
  • TestIsIssueClosed_ReturnsFalseForSyntheticItems — verifies synthetic skip
  • TestStartQueuedItems_PreservesScheduledCurrentStep — verifies trigger state is preserved
  • TestStartQueuedItems_DefaultsToStartState — verifies normal items still use start state
  • TestStartScheduler_SkippedInOnceMode — verifies no-op in single-shot mode
  • TestStartScheduler_RegistersTriggers — verifies cron entries are registered
  • TestValidateTriggers — table-driven validation of trigger configs
  • TestValidate_WithValidTrigger / TestValidate_WithInvalidTrigger — end-to-end validation
  • go test -p=1 -count=1 ./... passes

Fixes #419

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings March 16, 2026 03:41
Add a top-level `triggers` block to workflow config for cron-based
scheduled workflows using standard 5-field cron syntax. Each firing
creates a synthetic work item that flows through the normal workflow
state machine.

- Add TriggerConfig type and validation for cron expressions and state names
- Implement startScheduler/stopScheduler using robfig/cron/v3
- Add injectScheduledIssue for creating synthetic work items with
  dedup based on active/queued status
- Skip issue-provider calls (fetchIssueComments, isIssueClosed) for
  synthetic items since they have no real issue
- Preserve scheduled trigger's CurrentStep in startQueuedItems
- Automatic skip in --once mode and when at concurrency limit

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds cron-based scheduled triggers to the workflow engine by introducing a top-level triggers config block and wiring a UTC cron scheduler into the daemon to enqueue synthetic work items that run through the normal state machine.

Changes:

  • Add triggers to workflow config + validation (5-field cron parsing shared with runtime scheduler).
  • Start/stop a robfig/cron/v3 scheduler in the daemon (skipped in --once mode) and inject synthetic scheduled work items.
  • Skip issue-provider calls for synthetic items and preserve CurrentStep when starting queued items.

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
internal/workflow/config.go Adds TriggerConfig and triggers to workflow YAML schema.
internal/workflow/validate.go Validates trigger schedule syntax + referenced state; exports shared cron parser spec.
internal/workflow/validate_test.go Adds unit + integration tests for trigger validation.
internal/daemon/daemon.go Introduces daemon scheduler lifecycle and registers cron entries per repo workflow config.
internal/daemon/polling.go Injects synthetic scheduled work items, preserves CurrentStep on queued start, and skips “closed issue” checks for synthetic items.
internal/daemon/coding.go Skips fetching issue comments for synthetic scheduled work items.
internal/daemon/actions_test.go Adds tests for scheduled injection/dedup/max-concurrent and synthetic skip behaviors.
docs/workflow.html Documents the new triggers block semantics and examples.
go.mod / go.sum Adds github.com/robfig/cron/v3.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +1445 to +1446
require an existing session or branch (like
<code>ai.summarize</code>) will fail on synthetic work items.
- stopScheduler now waits (up to 5s) for in-flight jobs via the context
  returned by cron.Stop(), and clears the scheduler field
- Scope scheduled issue IDs by repoPath to avoid collisions when
  multiple repos share the same state name
- Use UnixNano for higher-resolution uniqueness in issue IDs
- Scope hasActiveScheduledItem dedup by repoPath so triggers in
  different repos don't block each other
- Move robfig/cron/v3 from indirect to direct require in go.mod

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@zhubert zhubert merged commit 30a8319 into main Mar 16, 2026
1 check passed
@zhubert zhubert deleted the issue-419 branch March 16, 2026 13:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Workflow Engine Enhancements (parallel branches, schedules, conditional gates, dry-run)

2 participants