Skip to content

Conversation

@elithrar
Copy link
Contributor

@elithrar elithrar commented Dec 19, 2025

note: draft for now as I want to make sure we're happy with this / think through it over the weekend.

Adds support for schedule events in the GitHub Action, allowing users to run OpenCode on a cron schedule.

  • add schedule to allowed event types
  • skip /opencode keyword check for schedule events (no comment to parse)
  • skip creating issue comment for schedule events (no issue/PR context)
  • prompt input is required for schedule events
  • branch naming: opencode/scheduled-{6-random-hex-chars}-{timestamp}
  • omit co-authored-by on commits (schedule operates as the repo)
  • add "Supported Events" section to docs with table and example workflow

Users can now create scheduled workflows that invoke OpenCode with a prompt to perform automated tasks like code reviews, reports, or maintenance. OpenCode can still open PRs/issues and call tools (webhooks, etc.) as needed.

@elithrar elithrar changed the title feat(github): support schedule events github: support schedule events Dec 19, 2025
@elithrar
Copy link
Contributor Author

I also tried to keep this pretty compact — most of the scaffolding was there, but b/c scheduled events don't get comment bodies + can't work on branches needed to make sure that was covered.

@elithrar
Copy link
Contributor Author

elithrar commented Dec 19, 2025

call Stack: schedule vs issue_comment

┌─────────────────────────────────────────────────────────────────────────────────┐
│                              GITHUB ACTION ENTRY                                │
│                       github/action.yml → opencode github run                   │
│                      packages/opencode/src/cli/cmd/github.ts                    │
└─────────────────────────────────────────────────────────────────────────────────┘
                                        │
                                        ▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│              context.eventName check (lines 391-398)                            │
│  Allowed: "issue_comment" | "pull_request_review_comment" | "schedule"          │
└─────────────────────────────────────────────────────────────────────────────────┘
                                        │
                                        ▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│                         isScheduleEvent (line 390)                              │
│                   const isScheduleEvent = context.eventName === "schedule"      │
└─────────────────────────────────────────────────────────────────────────────────┘
                                        │
                                        ▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│                              getUserPrompt()                                    │
├─────────────────────────────────────┬───────────────────────────────────────────┤
│           SCHEDULE                  │              ISSUE_COMMENT                │
├─────────────────────────────────────┼───────────────────────────────────────────┤
│  prompt = process.env["PROMPT"]     │  prompt = payload.comment.body            │
│  ├─ ✗ FAIL: !prompt → throw         │  + image processing                       │
│  └─ ✓ PASS: return { userPrompt }   │  └─ returns { userPrompt, promptFiles }   │
└─────────────────────────────────────┴───────────────────────────────────────────┘
                                        │
                                        ▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│                              configureGit()                                     │
│                          (same for both events)                                 │
└─────────────────────────────────────────────────────────────────────────────────┘
                                        │
                                        ▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│            if (!isScheduleEvent) { assertPermissions(); addReaction() }         │
├─────────────────────────────────────┬───────────────────────────────────────────┤
│           SCHEDULE                  │              ISSUE_COMMENT                │
├─────────────────────────────────────┼───────────────────────────────────────────┤
│  skipped (no actor/comment)         │  checks collaborator permission           │
│                                     │  adds 👀 reaction to comment              │
└─────────────────────────────────────┴───────────────────────────────────────────┘
                                        │
                                        ▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│                     Session.create() + subscribeSessionEvents()                 │
│                              (same for both)                                    │
└─────────────────────────────────────────────────────────────────────────────────┘
                                        │
                                        ▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│                           MAIN EVENT BRANCHING                                  │
│                     if (isScheduleEvent) { ... }                                │
│                     else if (isPullRequest) { ... }                             │
│                     else { /* issue */ }                                        │
└─────────────────────────────────────────────────────────────────────────────────┘
                                        │
        ┌───────────────────────────────┴───────────────────────────────┐
        ▼                                                               ▼
┌───────────────────────────────────┐       ┌───────────────────────────────────┐
│           SCHEDULE                │       │         ISSUE_COMMENT             │
├───────────────────────────────────┤       ├───────────────────────────────────┤
│                                   │       │                                   │
│  checkoutNewBranch("schedule")    │       │  checkoutNewBranch("issue")       │
│  → opencode/scheduled-{hex}-{ts}  │       │  → opencode/issue{N}-{ts}         │
│                                   │       │                                   │
│  chat(userPrompt, [])             │       │  fetchIssue()                     │
│                                   │       │  buildPromptDataForIssue()        │
│                                   │       │  chat(userPrompt + data, files)   │
│                                   │       │                                   │
├───────────────────────────────────┤       ├───────────────────────────────────┤
│  if (dirty) {                     │       │  if (dirty) {                     │
│    summarize()                    │       │    summarize()                    │
│    pushToNewBranch(isSchedule=✓)  │       │    pushToNewBranch(isSchedule=✗)  │
│      └─ NO co-author line         │       │      └─ WITH co-author line       │
│    createPR()  ✅                 │       │    createPR()                     │
│    console.log(PR #)              │       │    createComment(PR #)            │
│  } else {                         │       │    removeReaction()               │
│    console.log(response)          │       │  } else {                         │
│  }                                │       │    createComment(response)        │
│                                   │       │    removeReaction()               │
│  // NO createComment              │       │  }                                │
│  // NO removeReaction             │       │                                   │
└───────────────────────────────────┘       └───────────────────────────────────┘

Failure Modes

Stage Schedule Event Issue Comment Event
eventName check ✓ passes ✓ passes
getUserPrompt ✗ fails if PROMPT env missing ✗ fails if no /oc or /opencode in body
assertPermissions skipped ✓ typically passes (human actor)
addReaction skipped ✓ adds 👀 to comment
chat ✗ fails on LLM/tool errors ✗ fails on LLM/tool errors
pushToNewBranch ✗ fails on git push errors ✗ fails on git push errors
createPR ✅ can create PRs ✅ can create PRs
createComment skipped ✗ fails on API error
removeReaction skipped ✓ removes 👀 from comment

Key Differences

Aspect Schedule Issue/PR Comment
Prompt source PROMPT env var (required) Comment body
Branch name opencode/scheduled-{6-char-hex}-{timestamp} opencode/issue{N}-{timestamp}
Co-authored-by Omitted (schedule operates as repo) Included (credits human actor)
Output Console logs GitHub comment
Reactions None 👀 added/removed
Permission check Skipped Required

@opencode-agent
Copy link
Contributor

User elithrar does not have write permissions

github run

@elithrar elithrar force-pushed the support-scheduled-events branch from 8f05095 to d98ec97 Compare December 20, 2025 01:31
@elithrar elithrar marked this pull request as ready for review December 20, 2025 15:39
@elithrar
Copy link
Contributor Author

OK, I think I’m happy with this after staring at it again last night.

@rekram1-node
Copy link
Collaborator

/review

@github-actions
Copy link
Contributor

lgtm

@rekram1-node
Copy link
Collaborator

oh @elithrar I should really clean this up but rn github/index.ts does nothing, rn all the github workflow stuff is in ...../cmd/github.ts

At one point we meant to move it to be fully contained in the action and that's why github/index.ts exists but we never finished the migration and now it's just sitting there, so youll probably want to make changes to cmd/github.ts instead

Unless this changed recently ig, but last I checked that was the case still...

@rekram1-node
Copy link
Collaborator

Yeah appears to still use github cmd:

run: opencode github run

@elithrar
Copy link
Contributor Author

ah duh — all the other PRs I've made have been against the CLI imp. Fixing.

@elithrar elithrar force-pushed the support-scheduled-events branch from d2c8e5f to 5a779fd Compare December 20, 2025 19:00
@elithrar
Copy link
Contributor Author

fixed + upgraded diagram to show a couple of tweaks

@elithrar elithrar force-pushed the support-scheduled-events branch 2 times, most recently from 2eb281e to 981bcd2 Compare December 20, 2025 19:11
@elithrar elithrar marked this pull request as draft December 20, 2025 19:12
@elithrar elithrar marked this pull request as ready for review December 20, 2025 19:13
@rekram1-node
Copy link
Collaborator

/review

- add schedule to allowed event types
- skip keyword check, permissions, reactions for schedule events
- require PROMPT input for schedule events
- branch naming: opencode/scheduled-{6-char-hex}-{timestamp}
- omit co-authored-by on commits (schedule operates as the repo)
- output to console instead of creating comments
- add docs with Supported Events table and schedule example
@elithrar elithrar force-pushed the support-scheduled-events branch from f2b5bf9 to aecb8b8 Compare December 20, 2025 22:22
@elithrar
Copy link
Contributor Author

elithrar commented Dec 20, 2025 via email

@rekram1-node
Copy link
Collaborator

/review

@github-actions
Copy link
Contributor

Code review complete. Found one potential bug (commented inline). Otherwise the code follows the style guide - uses early returns where appropriate, keeps functions together, and doesn't introduce unnecessary else statements or excessive nesting. The changes look good overall.

@elithrar
Copy link
Contributor Author

elithrar commented Dec 21, 2025

Reviewed and addressed the following for schedule event handling:

  • Skip assertPermissions for schedule events (avoids github-actions[bot] actor failure)
  • Fix summarize() fallback to avoid accessing undefined payload for schedule events
  • Verified all issue.title, issue.body, pr.title, pr.body callsites are guarded

@rekram1-node rekram1-node merged commit 1037526 into sst:dev Dec 21, 2025
2 checks passed
Destreyf pushed a commit to Destreyf/opencode that referenced this pull request Dec 22, 2025
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.

2 participants