@openhands/extensions 0.18.0 → 0.20.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.
Files changed (62) hide show
  1. package/.agents/skills/custom-codereview-guide.md +7 -0
  2. package/.github/dependabot.yml +24 -0
  3. package/.github/scripts/check_issue_readiness.py +272 -0
  4. package/.github/scripts/check_pr_description.py +226 -0
  5. package/.github/scripts/post-readiness-comment.mjs +184 -0
  6. package/.github/scripts/refresh_linked_pr_checks.py +171 -0
  7. package/.github/workflows/issue-readiness-check.yml +142 -0
  8. package/.github/workflows/pr-description-check.yml +37 -0
  9. package/.pr/custom-automation-event-trigger.png +0 -0
  10. package/.pr/custom-automation-plugin-fields.png +0 -0
  11. package/.pr/custom-automation-prompt-review.png +0 -0
  12. package/.pr/custom-automation-prompt-scheduled.png +0 -0
  13. package/.pr/custom-automation-upload-fields.png +0 -0
  14. package/.release-please-manifest.json +1 -1
  15. package/AGENTS.md +17 -1
  16. package/README.md +10 -2
  17. package/automations/README.md +52 -36
  18. package/automations/bundle-index.js +1 -1
  19. package/automations/catalog/custom-automation/manifest.json +229 -0
  20. package/automations/catalog/github-agents-md-maintainer/manifest.json +5 -0
  21. package/automations/catalog/github-issue-to-pr/manifest.json +6 -1
  22. package/automations/catalog/github-pr-reviewer/manifest.json +6 -1
  23. package/automations/catalog/github-repo-monitor/manifest.json +5 -0
  24. package/automations/catalog/jira-issue-to-bitbucket-pr/manifest.json +23 -0
  25. package/automations/catalog/jira-issue-to-gitlab-mr/manifest.json +23 -0
  26. package/automations/catalog/linear-issue-to-bitbucket-pr/manifest.json +23 -0
  27. package/automations/catalog/linear-issue-to-github-pr/manifest.json +23 -0
  28. package/automations/catalog/linear-issue-to-gitlab-mr/manifest.json +23 -0
  29. package/automations/catalog/news-digest/manifest.json +5 -0
  30. package/automations/catalog/qa-changes/manifest.json +72 -0
  31. package/automations/catalog/slack-github-linear-daily-organization.json +27 -0
  32. package/automations/catalog-index.js +25 -11
  33. package/automations/catalog.schema.json +106 -7
  34. package/automations/index.d.ts +68 -2
  35. package/automations/interface.json +2 -1
  36. package/integrations/catalog/datadog.json +2 -2
  37. package/integrations/catalog/gitlab.json +63 -0
  38. package/integrations/catalog/notion.json +1 -1
  39. package/integrations/catalog-index.js +71 -69
  40. package/integrations/index.d.ts +1 -1
  41. package/marketplaces/openhands-extensions.json +21 -6
  42. package/package.json +1 -1
  43. package/plugins/pr-review/scripts/prompt.py +2 -0
  44. package/pyproject.toml +1 -1
  45. package/python/openhands_extensions/_version.py +1 -1
  46. package/skills/github-pr-reviewer/SKILL.md +2 -1
  47. package/skills/github-pr-reviewer/scripts/main.py +45 -4
  48. package/skills/github-pr-reviewer/tests/test_main.py +74 -0
  49. package/skills/index.js +11 -2
  50. package/skills/openhands-sdk/SKILL.md +1 -0
  51. package/skills/ticket-to-code-change/.plugin/plugin.json +21 -0
  52. package/skills/ticket-to-code-change/README.md +5 -0
  53. package/skills/ticket-to-code-change/SKILL.md +50 -0
  54. package/skills/ticket-to-code-change/commands/ticket-to-code-change-setup.md +8 -0
  55. package/tests/fixtures/automations/custom-automation.json +398 -0
  56. package/tests/fixtures/automations/github-pr-reviewer.json +9 -9
  57. package/tests/test_automation_setup.py +362 -92
  58. package/tests/test_catalogs.py +2 -2
  59. package/tests/test_check_issue_readiness.py +135 -0
  60. package/tests/test_check_pr_description.py +228 -0
  61. package/tests/test_pr_review_prompt.py +10 -0
  62. package/tests/test_refresh_linked_pr_checks.py +130 -0
@@ -0,0 +1,229 @@
1
+ {
2
+ "id": "custom-automation",
3
+ "name": "Custom automation",
4
+ "category": "Custom",
5
+ "icon": "sparkles",
6
+ "description": "Create a custom automation from a prompt, plugin-powered prompt, or uploaded script tarball.",
7
+ "requires": {
8
+ "integrations": {
9
+ "github": {
10
+ "message": "Optional. Used when you choose a GitHub repository to clone or trigger from GitHub events.",
11
+ "required": false
12
+ }
13
+ }
14
+ },
15
+ "popularityRank": 99,
16
+ "estimatedSetupMinutes": 5,
17
+ "skill": "openhands-automation",
18
+ "exampleImplementation": "Action: a user-selected prompt, plugin, or uploaded tarball creation path\nTrigger: a user-selected cron schedule or event source and event type\n\n1. Ask whether the automation should run a prompt, run a prompt with plugins, or upload a tarball.\n2. Render only the fields for the selected creation path.\n3. Create prompt automations through /v1/preset/prompt, plugin automations through /v1/preset/plugin, and uploaded tarball automations by uploading to /v1/uploads then creating through /v1.\n4. The selected trigger and common run settings are shared by all creation paths.",
19
+ "setup": {
20
+ "version": "1.0",
21
+ "mode": "direct",
22
+ "form": {
23
+ "note": "Choose whether this custom automation runs a plain prompt, a prompt with plugins, or your own uploaded tarball. Prompt and plugin runs use the LLM; uploaded tarballs are best for deterministic scripts.",
24
+ "triggers": {
25
+ "cron": {
26
+ "schedule": {
27
+ "type": "cron",
28
+ "label": "Schedule",
29
+ "help": "How often this automation should run.",
30
+ "default": "0 9 * * *",
31
+ "required": true
32
+ },
33
+ "timezone": {
34
+ "type": "timezone",
35
+ "label": "Timezone",
36
+ "help": "Timezone used to evaluate the schedule.",
37
+ "default": "UTC",
38
+ "required": true
39
+ }
40
+ },
41
+ "event": {
42
+ "source": {
43
+ "type": "event-source",
44
+ "label": "Event source",
45
+ "help": "Webhook source that starts the automation.",
46
+ "default": "github",
47
+ "required": true
48
+ },
49
+ "on": {
50
+ "type": "event-type",
51
+ "label": "Event type",
52
+ "help": "Event key or wildcard pattern that starts the automation.",
53
+ "placeholder": "issue_comment.created",
54
+ "required": true
55
+ },
56
+ "filter": {
57
+ "type": "textarea",
58
+ "label": "Event filter",
59
+ "help": "Optional JMESPath expression evaluated against the event payload.",
60
+ "placeholder": "glob(repository.full_name, 'OpenHands/*')",
61
+ "required": false,
62
+ "constraints": {
63
+ "maxLength": 2000
64
+ }
65
+ }
66
+ }
67
+ },
68
+ "args": {
69
+ "name": {
70
+ "type": "text",
71
+ "label": "Automation name",
72
+ "help": "Name shown in the automations list.",
73
+ "placeholder": "Daily repository summary",
74
+ "required": true,
75
+ "constraints": {
76
+ "minLength": 1,
77
+ "maxLength": 500
78
+ }
79
+ },
80
+ "model": {
81
+ "type": "llm-profile",
82
+ "label": "LLM profile",
83
+ "help": "Optional model profile used for automation runs. Leave blank to use the active profile.",
84
+ "required": false
85
+ },
86
+ "timeout": {
87
+ "type": "number",
88
+ "label": "Timeout (seconds)",
89
+ "help": "Maximum time a single run may take. Leave blank for the service default.",
90
+ "required": false,
91
+ "constraints": {
92
+ "min": 1,
93
+ "max": 1800
94
+ }
95
+ }
96
+ }
97
+ },
98
+ "actions": {
99
+ "prompt": {
100
+ "label": "Prompt",
101
+ "help": "Run a natural-language prompt with the default OpenHands agent.",
102
+ "features": [
103
+ "presetPrompt"
104
+ ],
105
+ "args": {
106
+ "prompt": {
107
+ "type": "textarea",
108
+ "label": "Prompt",
109
+ "help": "Instructions the agent follows every time the automation runs.",
110
+ "placeholder": "Summarize recent repository activity and post the result to Slack.",
111
+ "required": true,
112
+ "constraints": {
113
+ "minLength": 1,
114
+ "maxLength": 50000
115
+ }
116
+ },
117
+ "repository": {
118
+ "type": "repo-picker",
119
+ "label": "Repository",
120
+ "help": "Optional GitHub repository to clone before each run.",
121
+ "provider": "github",
122
+ "required": false
123
+ },
124
+ "ref": {
125
+ "type": "text",
126
+ "label": "Branch or ref",
127
+ "help": "Branch, tag, or commit to check out when a repository is selected.",
128
+ "placeholder": "main",
129
+ "required": false,
130
+ "constraints": {
131
+ "minLength": 1,
132
+ "maxLength": 255
133
+ }
134
+ }
135
+ },
136
+ "prompt": "{{form.prompt}}"
137
+ },
138
+ "plugin": {
139
+ "label": "Plugin",
140
+ "help": "Run a prompt with one or more OpenHands plugins loaded.",
141
+ "features": [
142
+ "presetPlugin"
143
+ ],
144
+ "args": {
145
+ "plugins": {
146
+ "type": "plugin-sources",
147
+ "label": "Plugins",
148
+ "help": "One or more plugin sources to load. Each source may include an optional ref and repository path.",
149
+ "required": true
150
+ },
151
+ "prompt": {
152
+ "type": "textarea",
153
+ "label": "Prompt",
154
+ "help": "Instructions the agent follows after loading the plugins.",
155
+ "placeholder": "Use the plugin commands to inspect the repository and summarize findings.",
156
+ "required": true,
157
+ "constraints": {
158
+ "minLength": 1,
159
+ "maxLength": 50000
160
+ }
161
+ },
162
+ "repository": {
163
+ "type": "repo-picker",
164
+ "label": "Repository",
165
+ "help": "Optional GitHub repository to clone before each run.",
166
+ "provider": "github",
167
+ "required": false
168
+ },
169
+ "ref": {
170
+ "type": "text",
171
+ "label": "Branch or ref",
172
+ "help": "Branch, tag, or commit to check out when a repository is selected.",
173
+ "placeholder": "main",
174
+ "required": false,
175
+ "constraints": {
176
+ "minLength": 1,
177
+ "maxLength": 255
178
+ }
179
+ }
180
+ },
181
+ "prompt": "{{form.prompt}}",
182
+ "plugins": "{{form.plugins}}"
183
+ },
184
+ "upload": {
185
+ "label": "Upload tarball",
186
+ "help": "Upload a .tar or .tar.gz containing the automation code to run.",
187
+ "features": [
188
+ "customTarball"
189
+ ],
190
+ "args": {
191
+ "tarball": {
192
+ "type": "tarball-upload",
193
+ "label": "Tarball",
194
+ "help": "A .tar or .tar.gz archive containing the automation code. Maximum size is enforced by the automation service.",
195
+ "required": true
196
+ },
197
+ "entrypoint": {
198
+ "type": "text",
199
+ "label": "Entrypoint",
200
+ "help": "Command to run after the tarball is extracted.",
201
+ "default": "python3 main.py",
202
+ "placeholder": "python3 main.py",
203
+ "required": true,
204
+ "constraints": {
205
+ "minLength": 1,
206
+ "maxLength": 500
207
+ }
208
+ },
209
+ "setupScript": {
210
+ "type": "text",
211
+ "label": "Setup script",
212
+ "help": "Optional path inside the tarball to run before the entrypoint.",
213
+ "placeholder": "setup.sh",
214
+ "required": false,
215
+ "constraints": {
216
+ "minLength": 1,
217
+ "maxLength": 255
218
+ }
219
+ }
220
+ },
221
+ "tarballPath": "{{form.tarball}}",
222
+ "entrypoint": "{{form.entrypoint}}",
223
+ "setupScript": "{{form.setupScript}}"
224
+ }
225
+ },
226
+ "filter": "{{form.filter}}",
227
+ "message": "This deployment cannot create custom automations directly. Set it up in this conversation instead: choose prompt, plugin, or uploaded tarball mode; confirm the selected trigger, model profile, timeout, and mode-specific fields; then create the automation."
228
+ }
229
+ }
@@ -17,6 +17,11 @@
17
17
  "popularityRank": 80,
18
18
  "estimatedSetupMinutes": 3,
19
19
  "exampleImplementation": "Trigger: cron, weekly by default (0 9 * * 1)\nRequired secret: GITHUB_PERSONAL_ACCESS_TOKEN, with permission to write contents and pull requests\n\n1. Read the repositories, branch prefix, pull request mode, and schedule from setup.\n2. Process each repository independently, with its own state, so one falling behind never blocks another.\n3. Key one unit of work to the ISO week, so a cron that fires more often, a retried run, or a restarted service cannot open the same pull request twice.\n4. Skip a repository whose previous pull request from this automation is still open; a second one would edit the same file.\n5. Ask GitHub whether AGENTS.md exists, which decides create vs update and the pull request title.\n6. Clone the default branch into a directory of its own, create the working branch, and start an OpenHands conversation with that directory as its workspace.\n7. The agent reads the repository, edits AGENTS.md, commits, pushes, and opens the pull request; the script verifies that on GitHub and opens it itself when the agent did not.\n8. Record no-changes when AGENTS.md is already accurate, which is the expected result most weeks.\n9. Remove the clone once the conversation has stopped.",
20
+ "impact": {
21
+ "basis": "completed-runs",
22
+ "one": "1 maintenance pass completed",
23
+ "other": "{{count}} maintenance passes completed"
24
+ },
20
25
  "setup": {
21
26
  "version": "1.0",
22
27
  "mode": "direct",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "github-issue-to-pr",
3
- "name": "GitHub Issue to PR Agent",
3
+ "name": "GitHub issue to PR",
4
4
  "category": "Software development",
5
5
  "description": "Watch for a configurable label on GitHub issues, implement the issue in a clone of the default branch, and open a pull request for each label event.",
6
6
  "requires": {
@@ -16,6 +16,11 @@
16
16
  "popularityRank": 95,
17
17
  "estimatedSetupMinutes": 4,
18
18
  "exampleImplementation": "Trigger: cron polling for open GitHub issues with a configured label such as openhands\nRequired secret: GITHUB_PERSONAL_ACCESS_TOKEN, with permission to write contents, issues, and pull requests\n\n1. Read the repositories, trigger label, branch prefix, draft mode, and polling schedule from setup.\n2. Poll each repository independently, with its own state, so issue numbers never collide.\n3. List open labelled issues, drop pull requests, and find the latest matching GitHub labeled issue event for each.\n4. Deduplicate on the label event ID so every label application queues exactly one attempt.\n5. Clone the default branch into a directory of its own, create the working branch, and start an OpenHands conversation with that directory as its workspace. The clone carries no credential and the agent is handed no secrets, because the prompt is built from an issue body that anyone can write.\n6. Comment on the issue with the branch and the conversation link.\n7. Once the conversation has stopped, commit whatever the agent left, push the branch, open a draft pull request titled after the issue, and comment the link on the issue. An agent that made no changes gets its answer posted instead.\n8. Remove the clone once the conversation has stopped, so nothing accumulates between runs.",
19
+ "impact": {
20
+ "basis": "completed-runs",
21
+ "one": "1 issue sweep completed",
22
+ "other": "{{count}} issue sweeps completed"
23
+ },
19
24
  "setup": {
20
25
  "version": "1.0",
21
26
  "mode": "direct",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "github-pr-reviewer",
3
3
  "version": "1.0.0",
4
- "name": "GitHub Code Review Agent",
4
+ "name": "GitHub code review",
5
5
  "category": "Code review",
6
6
  "description": "Watch for a configurable label on GitHub pull requests, inspect full PR and repository context, and post an AI review comment once per label event.",
7
7
  "requires": {
@@ -17,6 +17,11 @@
17
17
  "popularityRank": 100,
18
18
  "estimatedSetupMinutes": 4,
19
19
  "exampleImplementation": "Trigger: cron polling for open GitHub PRs with a configured label such as openhands-review\nRequired secret: GITHUB_PERSONAL_ACCESS_TOKEN, with permission to write pull request reviews\n\n1. Read the repositories, trigger label, review tone, and polling schedule from setup.\n2. Poll each repository independently, with its own state, so PR numbers never collide.\n3. List open PRs and find the latest matching GitHub labeled issue event for each labeled PR.\n4. Deduplicate on the label event ID so every label application queues exactly one review.\n5. Extract the PR head commit into a directory of its own and start an OpenHands conversation with that directory as its workspace, so the agent reviews the exact commit without cloning anything.\n6. Post an acknowledgement with the conversation link, then confirm on GitHub that the review was published for that head SHA, falling back to posting the agent's text as a comment.\n7. Remove the checkout once the conversation has stopped, so nothing accumulates between runs.",
20
+ "impact": {
21
+ "basis": "completed-runs",
22
+ "one": "1 PR review sweep completed",
23
+ "other": "{{count}} PR review sweeps completed"
24
+ },
20
25
  "setup": {
21
26
  "version": "1.0",
22
27
  "mode": "direct",
@@ -18,6 +18,11 @@
18
18
  "popularityRank": 98,
19
19
  "estimatedSetupMinutes": 5,
20
20
  "exampleImplementation": "Trigger: cron polling (e.g. every 15 minutes, configurable)\nRequired secret: GITHUB_PERSONAL_ACCESS_TOKEN\n\n1. Poll GitHub for new issue and PR comments since the last run.\n2. Match comments containing the trigger phrase (case-insensitive, default: @OpenHands).\n3. Post an acknowledgment comment with a link to the new OpenHands conversation.\n4. Forward follow-up replies in the same thread to the running conversation.\n5. Post the agent's final response back to GitHub when the conversation completes.",
21
+ "impact": {
22
+ "basis": "completed-runs",
23
+ "one": "1 repo scan completed",
24
+ "other": "{{count}} repo scans completed"
25
+ },
21
26
  "setup": {
22
27
  "version": "1.0",
23
28
  "mode": "direct",
@@ -0,0 +1,23 @@
1
+ {
2
+ "id": "jira-issue-to-bitbucket-pr",
3
+ "name": "Jira issue to Bitbucket PR",
4
+ "category": "Project management",
5
+ "description": "Watch Jira for implementation-ready issues, start an agent to make the requested code change, and open a Bitbucket pull request.",
6
+ "requires": {
7
+ "integrations": {
8
+ "jira": {
9
+ "message": "Reads implementation-ready issues and posts progress back to Jira."
10
+ },
11
+ "bitbucket": {
12
+ "message": "Clones the target repository, pushes a branch, and opens the pull request."
13
+ }
14
+ },
15
+ "features": [
16
+ "conversationDispatch"
17
+ ]
18
+ },
19
+ "popularityRank": 83,
20
+ "estimatedSetupMinutes": 6,
21
+ "skill": "ticket-to-code-change",
22
+ "exampleImplementation": "Trigger: Jira issue marked implementation-ready\nRequired integrations: Jira, Bitbucket\n\n1. Watch the selected Jira team or project for issues carrying a configurable implementation-ready label or state.\n2. Deduplicate issue IDs so each transition dispatches once.\n3. Read the issue, linked dependencies, acceptance criteria, and target repository.\n4. Start an independent OpenHands conversation that clones the Bitbucket repository, creates an issue-keyed branch, implements and tests the change, and opens a pull request.\n5. Post the conversation and pull request links back to the Jira issue and update its status according to the team's workflow."
23
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "id": "jira-issue-to-gitlab-mr",
3
+ "name": "Jira issue to GitLab MR",
4
+ "category": "Project management",
5
+ "description": "Watch Jira for implementation-ready issues, start an agent to make the requested code change, and open a GitLab merge request.",
6
+ "requires": {
7
+ "integrations": {
8
+ "jira": {
9
+ "message": "Reads implementation-ready issues and posts progress back to Jira."
10
+ },
11
+ "gitlab": {
12
+ "message": "Clones the target repository, pushes a branch, and opens the merge request."
13
+ }
14
+ },
15
+ "features": [
16
+ "conversationDispatch"
17
+ ]
18
+ },
19
+ "popularityRank": 84,
20
+ "estimatedSetupMinutes": 6,
21
+ "skill": "ticket-to-code-change",
22
+ "exampleImplementation": "Trigger: Jira issue marked implementation-ready\nRequired integrations: Jira, GitLab\n\n1. Watch the selected Jira team or project for issues carrying a configurable implementation-ready label or state.\n2. Deduplicate issue IDs so each transition dispatches once.\n3. Read the issue, linked dependencies, acceptance criteria, and target repository.\n4. Start an independent OpenHands conversation that clones the GitLab repository, creates an issue-keyed branch, implements and tests the change, and opens a merge request.\n5. Post the conversation and merge request links back to the Jira issue and update its status according to the team's workflow."
23
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "id": "linear-issue-to-bitbucket-pr",
3
+ "name": "Linear issue to Bitbucket PR",
4
+ "category": "Project management",
5
+ "description": "Watch Linear for implementation-ready issues, start an agent to make the requested code change, and open a Bitbucket pull request.",
6
+ "requires": {
7
+ "integrations": {
8
+ "linear": {
9
+ "message": "Reads implementation-ready issues and posts progress back to Linear."
10
+ },
11
+ "bitbucket": {
12
+ "message": "Clones the target repository, pushes a branch, and opens the pull request."
13
+ }
14
+ },
15
+ "features": [
16
+ "conversationDispatch"
17
+ ]
18
+ },
19
+ "popularityRank": 87,
20
+ "estimatedSetupMinutes": 6,
21
+ "skill": "ticket-to-code-change",
22
+ "exampleImplementation": "Trigger: Linear issue marked implementation-ready\nRequired integrations: Linear, Bitbucket\n\n1. Watch the selected Linear team or project for issues carrying a configurable implementation-ready label or state.\n2. Deduplicate issue IDs so each transition dispatches once.\n3. Read the issue, linked dependencies, acceptance criteria, and target repository.\n4. Start an independent OpenHands conversation that clones the Bitbucket repository, creates an issue-keyed branch, implements and tests the change, and opens a pull request.\n5. Post the conversation and pull request links back to the Linear issue and update its status according to the team's workflow."
23
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "id": "linear-issue-to-github-pr",
3
+ "name": "Linear issue to GitHub PR",
4
+ "category": "Project management",
5
+ "description": "Watch Linear for implementation-ready issues, start an agent to make the requested code change, and open a GitHub pull request.",
6
+ "requires": {
7
+ "integrations": {
8
+ "linear": {
9
+ "message": "Reads implementation-ready issues and posts progress back to Linear."
10
+ },
11
+ "github": {
12
+ "message": "Clones the target repository, pushes a branch, and opens the pull request."
13
+ }
14
+ },
15
+ "features": [
16
+ "conversationDispatch"
17
+ ]
18
+ },
19
+ "popularityRank": 89,
20
+ "estimatedSetupMinutes": 6,
21
+ "skill": "ticket-to-code-change",
22
+ "exampleImplementation": "Trigger: Linear issue marked implementation-ready\nRequired integrations: Linear, GitHub\n\n1. Watch the selected Linear team or project for issues carrying a configurable implementation-ready label or state.\n2. Deduplicate issue IDs so each transition dispatches once.\n3. Read the issue, linked dependencies, acceptance criteria, and target repository.\n4. Start an independent OpenHands conversation that clones the GitHub repository, creates an issue-keyed branch, implements and tests the change, and opens a pull request.\n5. Post the conversation and pull request links back to the Linear issue and update its status according to the team's workflow."
23
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "id": "linear-issue-to-gitlab-mr",
3
+ "name": "Linear issue to GitLab MR",
4
+ "category": "Project management",
5
+ "description": "Watch Linear for implementation-ready issues, start an agent to make the requested code change, and open a GitLab merge request.",
6
+ "requires": {
7
+ "integrations": {
8
+ "linear": {
9
+ "message": "Reads implementation-ready issues and posts progress back to Linear."
10
+ },
11
+ "gitlab": {
12
+ "message": "Clones the target repository, pushes a branch, and opens the merge request."
13
+ }
14
+ },
15
+ "features": [
16
+ "conversationDispatch"
17
+ ]
18
+ },
19
+ "popularityRank": 88,
20
+ "estimatedSetupMinutes": 6,
21
+ "skill": "ticket-to-code-change",
22
+ "exampleImplementation": "Trigger: Linear issue marked implementation-ready\nRequired integrations: Linear, GitLab\n\n1. Watch the selected Linear team or project for issues carrying a configurable implementation-ready label or state.\n2. Deduplicate issue IDs so each transition dispatches once.\n3. Read the issue, linked dependencies, acceptance criteria, and target repository.\n4. Start an independent OpenHands conversation that clones the GitLab repository, creates an issue-keyed branch, implements and tests the change, and opens a merge request.\n5. Post the conversation and merge request links back to the Linear issue and update its status according to the team's workflow."
23
+ }
@@ -13,6 +13,11 @@
13
13
  "popularityRank": 78,
14
14
  "estimatedSetupMinutes": 2,
15
15
  "exampleImplementation": "Trigger: cron, daily by default (0 8 * * *)\nRequired secret: none. The feeds are public URLs and the conversation is started with an empty secret allow-list and no MCP servers.\n\n1. Read the feed list, the topics, and the schedule from setup.\n2. Key one unit of work to the UTC date, so a cron that fires more often, a retried run, or a restarted service cannot write the same digest twice.\n3. Fetch every feed over plain HTTPS and parse RSS 2.0, RSS 1.0/RDF and Atom by local element name. A feed that is down, moved, or no longer a feed is reported and skipped; the run fails only when every feed fails.\n4. Drop stories already covered by an earlier digest and stories older than the lookback window. Do not judge what a story is about: that has no right answer and is the agent's call.\n5. Start no conversation at all when nothing new was published, and leave the day open for a later run. A quiet day costs no tokens.\n6. Otherwise start an OpenHands conversation with the newest stories and the topics in the prompt, and let it decide which are relevant, group them, merge duplicate coverage, and write the digest.\n7. Deliver it three ways that need no credentials: it stays in the conversation, it is printed into the run log, and its opening is kept in state.\n8. Remember the reported stories only once a digest exists, so a failed run is recovered by the next one rather than lost.",
16
+ "impact": {
17
+ "basis": "completed-runs",
18
+ "one": "1 feed check completed",
19
+ "other": "{{count}} feed checks completed"
20
+ },
16
21
  "setup": {
17
22
  "version": "1.0",
18
23
  "mode": "direct",
@@ -0,0 +1,72 @@
1
+ {
2
+ "id": "qa-changes",
3
+ "name": "QA changes",
4
+ "category": "Code review",
5
+ "description": "When a pull request is opened for review, run the QA changes methodology — set up the environment, exercise the changed behavior as a real user would, and post the outcome by editing the PR description with a QA Agent section.",
6
+ "requires": {
7
+ "integrations": {
8
+ "github": {
9
+ "message": "Used to read the pull request, check the author's commit history, and edit the PR description."
10
+ }
11
+ },
12
+ "features": [
13
+ "repoClone",
14
+ "presetPrompt",
15
+ "webhookDelivery"
16
+ ]
17
+ },
18
+ "popularityRank": 85,
19
+ "estimatedSetupMinutes": 5,
20
+ "skill": "qa-changes",
21
+ "exampleImplementation": "Trigger: GitHub pull_request.opened and pull_request.ready_for_review events\nRequired secret: GITHUB_TOKEN\n\n1. Receive a GitHub pull_request event (opened or ready_for_review).\n2. Filter: the PR must not be a draft (draft == false), the PR description must not already contain a QA Agent section, and the PR author must have more than 3 commits already in main.\n3. Start an OpenHands conversation that clones the repo, checks out the PR head, and runs the /qa-changes methodology: understand the change, set up the environment, exercise the changed behavior as a real user would.\n4. Instead of posting a review comment, edit the PR description to append a horizontal rule followed by a QA Agent section containing the structured QA report.",
22
+ "setup": {
23
+ "version": "1.0",
24
+ "mode": "direct",
25
+ "form": {
26
+ "triggers": {
27
+ "event": {
28
+ "on": {
29
+ "type": "select",
30
+ "label": "Trigger on",
31
+ "help": "Which GitHub pull request event starts a QA run. Opened fires when a non-draft PR is created; Ready for review fires when a draft PR is marked ready.",
32
+ "default": "pull_request.opened",
33
+ "required": true,
34
+ "options": [
35
+ {
36
+ "value": "pull_request.opened",
37
+ "label": "Pull request opened"
38
+ },
39
+ {
40
+ "value": "pull_request.ready_for_review",
41
+ "label": "Pull request ready for review"
42
+ }
43
+ ]
44
+ }
45
+ }
46
+ },
47
+ "args": {
48
+ "repository": {
49
+ "type": "repo-picker",
50
+ "label": "Repository",
51
+ "help": "The repository whose pull requests will be QA'd.",
52
+ "provider": "github",
53
+ "required": true
54
+ },
55
+ "ref": {
56
+ "type": "text",
57
+ "label": "Base branch",
58
+ "help": "Branch checked out when the agent runs QA.",
59
+ "default": "main",
60
+ "required": true,
61
+ "constraints": {
62
+ "minLength": 1,
63
+ "maxLength": 255
64
+ }
65
+ }
66
+ }
67
+ },
68
+ "prompt": "A pull request was opened or marked ready for review in {{form.repository}}. Before doing any QA work, run these gate checks and stop immediately (making no changes) if any fails:\n\n1. The PR must not be a draft — it must be open for review. If the PR is a draft, stop.\n2. The PR author (the human who opened it) must have more than 3 commits already merged into the {{form.ref}} branch. Use the GitHub API to count the author's commits in {{form.ref}}. If the count is 3 or fewer, stop without making any changes.\n3. The PR description must not already contain a section named QA Agent (i.e., a header like ## QA Agent or ### QA Agent). If that section already exists, stop without making any changes or starting a conversation.\n\nIf all gate checks pass, proceed with the QA validation using the /qa-changes skill methodology:\n\n- Phase 1: Understand the change. Read the PR diff, title, and description. Identify the goal of the PR. Classify every changed file. Form a hypothesis about what the PR should achieve.\n- Phase 2: Set up the environment. Read the repo's bootstrap instructions, install dependencies, and build if needed. Note CI status but do not re-run tests.\n- Phase 3: Exercise the changed behavior. Actually run the software the way a real user would — start servers, run CLI commands, make HTTP requests, open browsers. Do NOT run the test suite, linters, or code analysis. For bug fixes, reproduce the bug before and after the fix. Show before/after evidence.\n- Phase 4: Report results.\n\nIMPORTANT — how to post your report:\nDo NOT post a new comment, review, or inline review comment. Instead, EDIT the PR description (the pull request body) to append your QA report at the very end, after a horizontal rule (---), under a new section titled QA Agent. Use the GitHub API (PATCH /repos/{owner}/{repo}/pulls/{pr_number} with a body field) to update the PR description. Append the following structure to the existing PR body:\n\n---\n\n## QA Agent\n\n{Your full QA report following the /qa-changes skill report format: verdict, summary, Does this PR achieve its stated goal? section, status table, collapsible evidence in details blocks, and issues found.}\n\nDo not make any other changes to the PR description — only append the QA Agent section at the end. Do not post any comments or reviews.",
69
+ "filter": "!pull_request.draft && !icontains(pull_request.body, 'QA Agent') && glob(repository.full_name, '{{form.repository}}')",
70
+ "message": "This deployment cannot run the webhook-driven QA automation directly. Set it up in this conversation instead: confirm the repository to QA, the base branch, and the PR event to trigger on, then create the automation."
71
+ }
72
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "id": "slack-github-linear-daily-organization",
3
+ "name": "Slack + GitHub + Linear daily organization",
4
+ "category": "Personal productivity",
5
+ "description": "Every morning, reconcile your open GitHub PRs with Linear issues, align active work, surface relevant Slack context, and send yourself a concise daily plan.",
6
+ "exampleImplementation": "Trigger: cron, every morning at 7:00 AM in the configured timezone\nRequired integrations: GitHub, Linear, Slack\n\n1. Verify access to all three services before making changes.\n2. Reconcile open GitHub PRs with issues and import missing issues into Linear.\n3. Align active Linear work with open PRs and recent Slack context.\n4. Send a concise, prioritized daily plan to the configured Slack recipient.",
7
+ "requiredIntegrationIds": [
8
+ "slack",
9
+ "github",
10
+ "linear"
11
+ ],
12
+ "popularityRank": 88,
13
+ "estimatedSetupMinutes": 10,
14
+ "suggestedTrigger": {
15
+ "type": "cron",
16
+ "schedule": "0 7 * * *",
17
+ "timezone": "[IANA_TIMEZONE]"
18
+ },
19
+ "placeholders": [
20
+ "[GITHUB_USERNAME]",
21
+ "[LINEAR_ASSIGNEE_QUERY]",
22
+ "[GITHUB_ORG_OR_REPO_SCOPE]",
23
+ "[SLACK_RECIPIENT_QUERY]",
24
+ "[IANA_TIMEZONE]"
25
+ ],
26
+ "prompt": "You are running a daily GitHub/Linear/Slack organization automation.\n\nSchedule context:\n- This automation runs every morning at 7:00 AM in [IANA_TIMEZONE].\n- Treat \"today\" and \"past 1-3 days\" in [IANA_TIMEZONE].\n\nImportant safety and access rules:\n1. First, verify that you have working access to GitHub, Linear, and Slack using the available official tools/APIs. A minimal successful read for each service is enough.\n2. If any one of GitHub, Linear, or Slack is unavailable, missing credentials, or returns an authorization error, stop immediately. Do not make partial updates. If Slack is available, send the configured Slack recipient a short message saying which service was unavailable and that no changes were made; otherwise finish with that error.\n3. Prefer official APIs/MCP tools over browser interaction. Do not browse web UIs unless no API/tool path exists.\n4. When posting to Slack or creating/updating human-readable external-service content, include a short disclosure that the content was generated by an AI agent (OpenHands) on behalf of the user.\n\nIdentity and scope:\n- GitHub user to inspect: [GITHUB_USERNAME].\n- GitHub issue scope: [GITHUB_ORG_OR_REPO_SCOPE]. Examples: visible repositories in one or more organizations, or an explicit allowlist of repositories.\n- Linear assignee: resolve by searching for [LINEAR_ASSIGNEE_QUERY]. Do not guess an ID if multiple plausible matches exist.\n- Slack recipient for the final daily plan: resolve by searching for [SLACK_RECIPIENT_QUERY], or use the current authenticated Slack user if that is the intended recipient.\n\nTask 1 — Ensure the user's open PRs are associated with GitHub issues:\n1. Find all open pull requests authored by [GITHUB_USERNAME] across the configured GitHub scope.\n2. For each PR, determine whether it is already associated with a GitHub issue. Count an association if the PR body has a clear issue reference or closing keyword (for example, #123, owner/repo#123, fixes, closes, or resolves), or if GitHub's API exposes linked/closing issues.\n3. If a PR has no associated issue:\n a. Search open issues in the same repository for an obvious matching issue using the PR title, branch name, and summary. Only treat an issue as obvious if the title/topic clearly matches; do not force weak matches.\n b. If an obvious open issue exists, use that issue.\n c. If none exists, create a new GitHub issue in the same repository summarizing the PR's purpose and linking back to the PR. Include an AI disclosure in the issue body.\n d. Update the PR description to include a non-closing association such as \"Related issue: #123\" or \"Related issue: owner/repo#123\" for cross-repo references. Preserve the existing PR description. Avoid \"Fixes\", \"Closes\", or \"Resolves\" unless the PR already used a closing keyword or the issue clearly should close when the PR merges.\n\nTask 2 — Ensure GitHub issues are represented in Linear:\n1. Find all open GitHub issues, excluding PRs, in the configured GitHub issue scope.\n2. For each issue, verify that it has a corresponding Linear issue. Match by GitHub issue URL first, then by exact repository/name/number and title if needed.\n3. If no Linear issue exists, create one in the appropriate Linear team/project using the GitHub issue title, URL, repository, labels, and a concise summary. Include an AI disclosure in the Linear issue description. Choose an appropriate priority for newly created Linear issues using this rubric:\n - Urgent: security, production outage, data loss, severe user-blocking regression, active incident.\n - High: important bug/regression, release blocker, broadly affecting users, high-value requested work.\n - Medium: normal feature/bug/task with moderate impact.\n - Low: cleanup, docs, nice-to-have, unclear/low-impact backlog.\n - No priority only if there is insufficient information.\n4. For every GitHub issue that has one or more open PRs associated with it, ensure the corresponding Linear issue is assigned to the configured Linear assignee and has a started/In Progress status. If the Linear issue is already completed or canceled, do not reopen it; mention this in the final report instead.\n5. Do not downgrade or otherwise change priorities of existing Linear issues merely because they seem wrong. If an existing priority is missing and the issue is actively in progress due to an open PR, you may set a reasonable priority. If a priority seems unclear or incorrect, flag it in the final Slack report rather than changing it.\n\nTask 3 — Check Slack context for active Linear issues:\n1. Inspect active Linear issues assigned to the configured assignee and not completed/canceled, especially urgent, high-priority, and in-progress issues.\n2. Search Slack public content and, if available in the tool configuration, private/DM-accessible content for the last 1-3 days for requests, mentions, or discussions related to those Linear issue identifiers, issue titles, linked GitHub issues/PRs, and relevant repository names.\n3. Summarize actionable Slack requests/discussions. Include links to Slack messages/threads when the Slack tooling provides them.\n4. Do not expose private Slack content beyond what is necessary for the configured recipient's own daily plan.\n\nTask 4 — Produce and send the daily plan:\n1. Review all active Linear issues assigned to the configured assignee, prioritizing Urgent then High then Medium then Low, while also considering Slack requests, open PR status, blockers, and issue age.\n2. Create a concise plan for what the recipient should work on today, focusing on the most urgent and important issues first.\n3. Include:\n - Top 3-5 recommended focus items with Linear identifiers/titles and links.\n - Any GitHub PR issue-association work performed.\n - Any GitHub issues imported into Linear.\n - Any Linear issues moved to In Progress or assigned to the configured assignee because an open PR exists.\n - Any Slack requests/discussions from the past 1-3 days relevant to active Linear issues.\n - Any issue priorities that are unclear or appear incorrect; explicitly say you did not change those priorities.\n - Any access or matching limitations.\n4. Send the report to the configured Slack recipient as a DM if possible. If DM is not possible, use the best available Slack destination for that recipient. Include the AI disclosure in the message.\n5. Finish with a short execution summary including counts of PRs checked, PRs updated, GitHub issues created, GitHub issues imported to Linear, Linear issues updated, and Slack discussions found.\n\nBe careful and conservative: avoid duplicate GitHub issues, duplicate Linear issues, weak associations, or broad destructive changes."
27
+ }
@@ -3,17 +3,24 @@
3
3
  // run: npm run build:automations
4
4
 
5
5
  import entry0 from "./catalog/github-pr-reviewer/manifest.json" with { type: "json" };
6
- import entry1 from "./catalog/github-repo-monitor/manifest.json" with { type: "json" };
7
- import entry2 from "./catalog/github-issue-to-pr/manifest.json" with { type: "json" };
8
- import entry3 from "./catalog/slack-standup-digest/manifest.json" with { type: "json" };
9
- import entry4 from "./catalog/slack-channel-monitor/manifest.json" with { type: "json" };
10
- import entry5 from "./catalog/linear-triage-assistant/manifest.json" with { type: "json" };
11
- import entry6 from "./catalog/jira-issue-to-pr/manifest.json" with { type: "json" };
12
- import entry7 from "./catalog/research-brief-writer/manifest.json" with { type: "json" };
13
- import entry8 from "./catalog/github-agents-md-maintainer/manifest.json" with { type: "json" };
14
- import entry9 from "./catalog/upstream-fork-sync/manifest.json" with { type: "json" };
15
- import entry10 from "./catalog/incident-retrospective-drafter/manifest.json" with { type: "json" };
16
- import entry11 from "./catalog/news-digest/manifest.json" with { type: "json" };
6
+ import entry1 from "./catalog/custom-automation/manifest.json" with { type: "json" };
7
+ import entry2 from "./catalog/github-repo-monitor/manifest.json" with { type: "json" };
8
+ import entry3 from "./catalog/github-issue-to-pr/manifest.json" with { type: "json" };
9
+ import entry4 from "./catalog/slack-standup-digest/manifest.json" with { type: "json" };
10
+ import entry5 from "./catalog/slack-channel-monitor/manifest.json" with { type: "json" };
11
+ import entry6 from "./catalog/linear-triage-assistant/manifest.json" with { type: "json" };
12
+ import entry7 from "./catalog/linear-issue-to-github-pr/manifest.json" with { type: "json" };
13
+ import entry8 from "./catalog/linear-issue-to-gitlab-mr/manifest.json" with { type: "json" };
14
+ import entry9 from "./catalog/linear-issue-to-bitbucket-pr/manifest.json" with { type: "json" };
15
+ import entry10 from "./catalog/jira-issue-to-pr/manifest.json" with { type: "json" };
16
+ import entry11 from "./catalog/qa-changes/manifest.json" with { type: "json" };
17
+ import entry12 from "./catalog/jira-issue-to-gitlab-mr/manifest.json" with { type: "json" };
18
+ import entry13 from "./catalog/research-brief-writer/manifest.json" with { type: "json" };
19
+ import entry14 from "./catalog/jira-issue-to-bitbucket-pr/manifest.json" with { type: "json" };
20
+ import entry15 from "./catalog/github-agents-md-maintainer/manifest.json" with { type: "json" };
21
+ import entry16 from "./catalog/upstream-fork-sync/manifest.json" with { type: "json" };
22
+ import entry17 from "./catalog/incident-retrospective-drafter/manifest.json" with { type: "json" };
23
+ import entry18 from "./catalog/news-digest/manifest.json" with { type: "json" };
17
24
 
18
25
  export const AUTOMATION_CATALOG_ENTRIES = [
19
26
  entry0,
@@ -28,4 +35,11 @@ export const AUTOMATION_CATALOG_ENTRIES = [
28
35
  entry9,
29
36
  entry10,
30
37
  entry11,
38
+ entry12,
39
+ entry13,
40
+ entry14,
41
+ entry15,
42
+ entry16,
43
+ entry17,
44
+ entry18,
31
45
  ];