@openhands/extensions 0.16.0 → 0.18.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 (70) hide show
  1. package/.release-please-manifest.json +1 -1
  2. package/AGENTS.md +1 -0
  3. package/README.md +5 -2
  4. package/automations/README.md +78 -11
  5. package/automations/bundle-index.js +18 -0
  6. package/automations/catalog/github-agents-md-maintainer/manifest.json +96 -0
  7. package/automations/catalog/github-issue-to-pr/manifest.json +107 -0
  8. package/automations/catalog/github-pr-reviewer/manifest.json +24 -7
  9. package/automations/catalog/github-repo-monitor/manifest.json +29 -34
  10. package/automations/catalog/jira-issue-to-pr/manifest.json +3 -3
  11. package/automations/catalog/news-digest/manifest.json +76 -0
  12. package/automations/catalog-index.js +13 -7
  13. package/automations/catalog.schema.json +112 -3
  14. package/automations/index.d.ts +66 -1
  15. package/automations/index.js +14 -0
  16. package/automations/interface.json +6 -2
  17. package/automations/interface.schema.json +6 -2
  18. package/index.d.ts +1 -1
  19. package/index.js +1 -1
  20. package/integrations/catalog/posthog.json +41 -3
  21. package/integrations/catalog/sonarqube.json +78 -0
  22. package/integrations/catalog-index.js +65 -63
  23. package/marketplaces/openhands-extensions.json +49 -0
  24. package/package.json +1 -1
  25. package/plugins/qa-changes/action.yml +1 -1
  26. package/pyproject.toml +1 -1
  27. package/python/openhands_extensions/_version.py +1 -1
  28. package/scripts/build-automation-catalog.mjs +30 -0
  29. package/scripts/build-skills-catalog.mjs +24 -7
  30. package/skills/add-skill/SKILL.md +1 -1
  31. package/skills/github-agents-md-maintainer/.plugin/plugin.json +19 -0
  32. package/skills/github-agents-md-maintainer/README.md +59 -0
  33. package/skills/github-agents-md-maintainer/SKILL.md +271 -0
  34. package/skills/github-agents-md-maintainer/commands/agents-md-setup.md +8 -0
  35. package/skills/github-agents-md-maintainer/references/state-schema.md +113 -0
  36. package/skills/github-agents-md-maintainer/scripts/main.py +1187 -0
  37. package/skills/github-issue-to-pr/.plugin/plugin.json +19 -0
  38. package/skills/github-issue-to-pr/README.md +84 -0
  39. package/skills/github-issue-to-pr/SKILL.md +373 -0
  40. package/skills/github-issue-to-pr/commands/issue-to-pr-setup.md +8 -0
  41. package/skills/github-issue-to-pr/references/state-schema.md +139 -0
  42. package/skills/github-issue-to-pr/scripts/main.py +1305 -0
  43. package/skills/github-pr-reviewer/README.md +12 -6
  44. package/skills/github-pr-reviewer/SKILL.md +93 -31
  45. package/skills/github-pr-reviewer/commands/pr-reviewer-setup.md +1 -1
  46. package/skills/github-pr-reviewer/references/state-schema.md +68 -18
  47. package/skills/github-pr-reviewer/scripts/main.py +540 -103
  48. package/skills/github-pr-reviewer/tests/test_main.py +503 -0
  49. package/skills/index.d.ts +6 -0
  50. package/skills/index.js +56 -17
  51. package/skills/jira-issue-to-pr/scripts/main.py +4 -2
  52. package/skills/news-digest/.plugin/plugin.json +19 -0
  53. package/skills/news-digest/README.md +71 -0
  54. package/skills/news-digest/SKILL.md +284 -0
  55. package/skills/news-digest/commands/news-digest-setup.md +8 -0
  56. package/skills/news-digest/references/state-schema.md +178 -0
  57. package/skills/news-digest/scripts/main.py +1250 -0
  58. package/skills/openhands-sdk/SKILL.md +2 -0
  59. package/skills/skill-creator/SKILL.md +1 -1
  60. package/skills/slack-channel-monitor/scripts/main.py +3 -2
  61. package/tests/fixtures/automations/capabilities.json +30 -0
  62. package/tests/fixtures/automations/github-pr-reviewer.json +319 -55
  63. package/tests/fixtures/automations/github-repo-monitor.json +230 -62
  64. package/tests/test_automation_setup.py +260 -31
  65. package/tests/test_catalogs.py +46 -1
  66. package/tests/test_github_agents_md_maintainer.py +352 -0
  67. package/tests/test_github_issue_to_pr.py +539 -0
  68. package/tests/test_news_digest.py +646 -0
  69. package/tests/test_skills_catalog.py +182 -36
  70. package/tests/test_slack_channel_monitor.py +1 -1
@@ -0,0 +1,96 @@
1
+ {
2
+ "id": "github-agents-md-maintainer",
3
+ "name": "AGENTS.md Maintainer",
4
+ "category": "Documentation",
5
+ "icon": "bot",
6
+ "description": "Keep AGENTS.md current in your repositories. On a schedule, an agent reads the repository, creates or updates AGENTS.md, and opens a pull request - and stays quiet while one of its pull requests is still open.",
7
+ "requires": {
8
+ "integrations": {
9
+ "github": {
10
+ "message": "Used to read the repository, push the branch, and open the pull request."
11
+ }
12
+ },
13
+ "features": [
14
+ "customTarball"
15
+ ]
16
+ },
17
+ "popularityRank": 80,
18
+ "estimatedSetupMinutes": 3,
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
+ "setup": {
21
+ "version": "1.0",
22
+ "mode": "direct",
23
+ "form": {
24
+ "triggers": {
25
+ "cron": {
26
+ "schedule": {
27
+ "type": "cron",
28
+ "label": "Check frequency",
29
+ "help": "How often to review AGENTS.md. Work is keyed by ISO week, so a schedule more frequent than weekly only polls.",
30
+ "default": "0 9 * * 1",
31
+ "required": true
32
+ },
33
+ "timezone": {
34
+ "type": "timezone",
35
+ "label": "Timezone",
36
+ "help": "Timezone the schedule is interpreted in.",
37
+ "default": "UTC",
38
+ "required": true
39
+ }
40
+ }
41
+ },
42
+ "args": {
43
+ "repositories": {
44
+ "type": "repo-picker",
45
+ "label": "Repositories",
46
+ "help": "The repositories whose AGENTS.md is maintained. Each keeps its own state and its own weekly claim.",
47
+ "provider": "github",
48
+ "multiple": true,
49
+ "required": true
50
+ },
51
+ "branchPrefix": {
52
+ "type": "text",
53
+ "label": "Branch prefix",
54
+ "help": "Branches are named after this prefix and the ISO week, such as openhands/agents-md-2026-W34. It is also how the automation recognises its own open pull requests.",
55
+ "default": "openhands/agents-md",
56
+ "required": true,
57
+ "constraints": {
58
+ "minLength": 1,
59
+ "maxLength": 50
60
+ }
61
+ },
62
+ "pullRequestMode": {
63
+ "type": "select",
64
+ "label": "Pull request mode",
65
+ "help": "Whether the pull request is opened as a draft or ready for review.",
66
+ "default": "draft",
67
+ "required": true,
68
+ "options": [
69
+ {
70
+ "value": "draft",
71
+ "label": "Draft"
72
+ },
73
+ {
74
+ "value": "ready",
75
+ "label": "Ready for review"
76
+ }
77
+ ]
78
+ }
79
+ }
80
+ },
81
+ "bundle": {
82
+ "version": "1.0.0",
83
+ "entrypoint": "python3 main.py",
84
+ "timeout": 900,
85
+ "files": {
86
+ "main.py": "skills/github-agents-md-maintainer/scripts/main.py"
87
+ },
88
+ "config": {
89
+ "repos": "{{form.repositories}}",
90
+ "branch_prefix": "{{form.branchPrefix}}",
91
+ "pull_request_mode": "{{form.pullRequestMode}}"
92
+ }
93
+ },
94
+ "message": "This deployment cannot run the scheduled AGENTS.md automation directly. Set it up in this conversation instead: confirm the repositories to maintain, the branch prefix, whether pull requests open as drafts, and the schedule, then create the automation."
95
+ }
96
+ }
@@ -0,0 +1,107 @@
1
+ {
2
+ "id": "github-issue-to-pr",
3
+ "name": "GitHub Issue to PR Agent",
4
+ "category": "Software development",
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
+ "requires": {
7
+ "integrations": {
8
+ "github": {
9
+ "message": "Used to read labelled issues, push the branch, and open the pull request."
10
+ }
11
+ },
12
+ "features": [
13
+ "customTarball"
14
+ ]
15
+ },
16
+ "popularityRank": 95,
17
+ "estimatedSetupMinutes": 4,
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
+ "setup": {
20
+ "version": "1.0",
21
+ "mode": "direct",
22
+ "form": {
23
+ "triggers": {
24
+ "cron": {
25
+ "schedule": {
26
+ "type": "cron",
27
+ "label": "Check frequency",
28
+ "help": "How often to look for newly labelled issues.",
29
+ "default": "*/15 * * * *",
30
+ "required": true
31
+ },
32
+ "timezone": {
33
+ "type": "timezone",
34
+ "label": "Timezone",
35
+ "help": "Timezone the schedule is interpreted in.",
36
+ "default": "UTC",
37
+ "required": true
38
+ }
39
+ }
40
+ },
41
+ "args": {
42
+ "repositories": {
43
+ "type": "repo-picker",
44
+ "label": "Repositories",
45
+ "help": "The repositories whose labelled issues are implemented. Each is polled independently and keeps its own state, so issue numbers never collide between them.",
46
+ "provider": "github",
47
+ "multiple": true,
48
+ "required": true
49
+ },
50
+ "triggerLabel": {
51
+ "type": "text",
52
+ "label": "Trigger label",
53
+ "help": "Only issues carrying this label are worked on.",
54
+ "default": "openhands",
55
+ "required": true,
56
+ "constraints": {
57
+ "minLength": 1,
58
+ "maxLength": 50
59
+ }
60
+ },
61
+ "branchPrefix": {
62
+ "type": "text",
63
+ "label": "Branch prefix",
64
+ "help": "Branches are named after this prefix and the issue number, such as openhands/issue-42.",
65
+ "default": "openhands/issue",
66
+ "required": true,
67
+ "constraints": {
68
+ "minLength": 1,
69
+ "maxLength": 50
70
+ }
71
+ },
72
+ "pullRequestMode": {
73
+ "type": "select",
74
+ "label": "Pull request mode",
75
+ "help": "Whether the pull request is opened as a draft or ready for review.",
76
+ "default": "draft",
77
+ "required": true,
78
+ "options": [
79
+ {
80
+ "value": "draft",
81
+ "label": "Draft"
82
+ },
83
+ {
84
+ "value": "ready",
85
+ "label": "Ready for review"
86
+ }
87
+ ]
88
+ }
89
+ }
90
+ },
91
+ "bundle": {
92
+ "version": "1.0.0",
93
+ "entrypoint": "python3 main.py",
94
+ "timeout": 900,
95
+ "files": {
96
+ "main.py": "skills/github-issue-to-pr/scripts/main.py"
97
+ },
98
+ "config": {
99
+ "repos": "{{form.repositories}}",
100
+ "trigger_label": "{{form.triggerLabel}}",
101
+ "branch_prefix": "{{form.branchPrefix}}",
102
+ "pull_request_mode": "{{form.pullRequestMode}}"
103
+ }
104
+ },
105
+ "message": "This deployment cannot run the scheduled issue-to-PR automation directly. Set it up in this conversation instead: confirm the repositories to watch, the trigger label, the branch prefix, whether pull requests open as drafts, and the polling schedule, then create the automation."
106
+ }
107
+ }
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "id": "github-pr-reviewer",
3
+ "version": "1.0.0",
3
4
  "name": "GitHub Code Review Agent",
4
5
  "category": "Code review",
5
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.",
@@ -10,13 +11,12 @@
10
11
  }
11
12
  },
12
13
  "features": [
13
- "repoClone",
14
- "presetPrompt"
14
+ "customTarball"
15
15
  ]
16
16
  },
17
17
  "popularityRank": 100,
18
18
  "estimatedSetupMinutes": 4,
19
- "exampleImplementation": "Trigger: cron polling for open GitHub PRs with a configured label such as openhands-review\nRequired secret: GITHUB_PERSONAL_ACCESS_TOKEN\n\n1. Read repository, trigger label, review tone, and polling schedule from setup.\n2. List open PRs and find the latest matching GitHub labeled issue event for each labeled PR.\n3. Deduplicate on the label event ID so every label application queues exactly one review.\n4. Start an OpenHands conversation that clones the repo, checks out the exact PR head SHA, and inspects PR discussion, review comments, changed files, diff, and surrounding code.\n5. Post an acknowledgement with the conversation link, then post the final AI review comment only if the PR is still open and the head SHA has not changed.",
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
20
  "setup": {
21
21
  "version": "1.0",
22
22
  "mode": "direct",
@@ -40,11 +40,12 @@
40
40
  }
41
41
  },
42
42
  "args": {
43
- "repository": {
43
+ "repositories": {
44
44
  "type": "repo-picker",
45
- "label": "Repository",
46
- "help": "The repository whose pull requests will be reviewed.",
45
+ "label": "Repositories",
46
+ "help": "The repositories whose pull requests will be reviewed. Each is polled independently and keeps its own state, so pull request numbers never collide between them.",
47
47
  "provider": "github",
48
+ "multiple": true,
48
49
  "required": true
49
50
  },
50
51
  "triggerLabel": {
@@ -72,12 +73,28 @@
72
73
  {
73
74
  "value": "thorough",
74
75
  "label": "Thorough"
76
+ },
77
+ {
78
+ "value": "friendly",
79
+ "label": "Friendly"
75
80
  }
76
81
  ]
77
82
  }
78
83
  }
79
84
  },
80
- "prompt": "Review pull requests labeled '{{form.triggerLabel}}' in {{form.repository}}. Review tone: {{form.reviewTone}}.",
85
+ "bundle": {
86
+ "version": "1.0.0",
87
+ "entrypoint": "python3 main.py",
88
+ "timeout": 600,
89
+ "files": {
90
+ "main.py": "skills/github-pr-reviewer/scripts/main.py"
91
+ },
92
+ "config": {
93
+ "repos": "{{form.repositories}}",
94
+ "trigger_label": "{{form.triggerLabel}}",
95
+ "review_tone": "{{form.reviewTone}}"
96
+ }
97
+ },
81
98
  "message": "This deployment cannot run the scheduled review automation directly. Set it up in this conversation instead: confirm the repository to review, the trigger label, the review tone, and the polling schedule, then create the automation."
82
99
  }
83
100
  }
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "id": "github-repo-monitor",
3
+ "version": "1.0.0",
3
4
  "name": "GitHub repository monitor",
4
5
  "category": "Developer tools",
5
6
  "description": "Watch a repository for @OpenHands mentions in issues and PR comments, start a conversation, and post the agent's reply back to GitHub.",
@@ -11,47 +12,31 @@
11
12
  },
12
13
  "features": [
13
14
  "repoClone",
14
- "presetPrompt",
15
- "webhookDelivery"
15
+ "presetPrompt"
16
16
  ]
17
17
  },
18
18
  "popularityRank": 98,
19
19
  "estimatedSetupMinutes": 5,
20
- "exampleImplementation": "Trigger: cron, every minute (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.",
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
21
  "setup": {
22
22
  "version": "1.0",
23
23
  "mode": "direct",
24
24
  "form": {
25
25
  "triggers": {
26
- "event": {
27
- "on": {
28
- "type": "select",
29
- "label": "Respond to",
30
- "help": "Which GitHub comment event starts a conversation.",
31
- "default": "issue_comment.created",
32
- "required": true,
33
- "options": [
34
- {
35
- "value": "issue_comment.created",
36
- "label": "Comments on issues and pull requests"
37
- },
38
- {
39
- "value": "pull_request_review_comment.created",
40
- "label": "Pull request review comments only"
41
- }
42
- ]
26
+ "cron": {
27
+ "schedule": {
28
+ "type": "cron",
29
+ "label": "Check frequency",
30
+ "help": "How often to look for new comments to respond to.",
31
+ "default": "*/15 * * * *",
32
+ "required": true
43
33
  },
44
- "triggerPhrase": {
45
- "type": "text",
46
- "label": "Trigger phrase",
47
- "help": "Only comments containing this phrase start a conversation. Matched case-insensitively. Quotes and backslashes are not allowed, because the phrase becomes part of the event filter expression.",
48
- "default": "@openhands",
49
- "required": true,
50
- "constraints": {
51
- "minLength": 2,
52
- "maxLength": 50,
53
- "format": "safeExpressionLiteral"
54
- }
34
+ "timezone": {
35
+ "type": "timezone",
36
+ "label": "Timezone",
37
+ "help": "Timezone the schedule is interpreted in.",
38
+ "default": "UTC",
39
+ "required": true
55
40
  }
56
41
  }
57
42
  },
@@ -63,6 +48,17 @@
63
48
  "provider": "github",
64
49
  "required": true
65
50
  },
51
+ "triggerPhrase": {
52
+ "type": "text",
53
+ "label": "Trigger phrase",
54
+ "help": "Only comments containing this phrase start a conversation. Matched case-insensitively.",
55
+ "default": "@openhands",
56
+ "required": true,
57
+ "constraints": {
58
+ "minLength": 2,
59
+ "maxLength": 50
60
+ }
61
+ },
66
62
  "ref": {
67
63
  "type": "text",
68
64
  "label": "Base branch",
@@ -76,8 +72,7 @@
76
72
  }
77
73
  }
78
74
  },
79
- "prompt": "A comment in {{form.repository}} mentions '{{form.triggerPhrase}}'. Read the surrounding issue or pull request context from the event payload, then post a helpful reply as a comment on the same thread.",
80
- "filter": "icontains(comment.body, '{{form.triggerPhrase}}') && glob(repository.full_name, '{{form.repository}}')",
81
- "message": "This deployment cannot run the webhook-driven monitor directly. Set it up in this conversation instead: confirm the repository to watch, the comment event, and the trigger phrase, then create the automation. If webhook delivery is unavailable here, build the polling variant this skill supports."
75
+ "prompt": "Poll {{form.repository}} for any new issue or pull request comments since the last run. For every comment mentioning '{{form.triggerPhrase}}', read the surrounding issue or pull request context and post a helpful reply as a comment on the same thread.",
76
+ "message": "This deployment cannot run the scheduled monitor directly. Set it up in this conversation instead: confirm the repository to watch, the trigger phrase, and the polling schedule, then create the automation."
82
77
  }
83
78
  }
@@ -5,8 +5,8 @@
5
5
  "description": "Watch a Jira Cloud project for issues with a configurable label and automatically open a GitHub pull request for each new issue found. The target GitHub repo is read from the ticket body - no repo parameter required at deploy time.",
6
6
  "requires": {
7
7
  "integrations": {
8
- "jira": {
9
- "message": "Reads the project for issues carrying the trigger label."
8
+ "atlassian-rovo": {
9
+ "message": "Provides the Atlassian Rovo MCP connection used to access Jira data."
10
10
  },
11
11
  "github": {
12
12
  "message": "Opens a pull request on the repository named in the ticket."
@@ -15,5 +15,5 @@
15
15
  },
16
16
  "popularityRank": 85,
17
17
  "estimatedSetupMinutes": 5,
18
- "exampleImplementation": "Trigger: cron polling (e.g. every 5 minutes)\nRequired secrets: Jira API token, GitHub personal access token (repo + workflow scope)\n\n1. Collect Jira base URL, email, API token secret name, label to watch, and cron schedule from the user. No GitHub repo is needed at deploy time - each ticket must include the target repo (owner/repo) in its body.\n2. Poll POST /rest/api/3/search/jql on the Jira Cloud instance to find open issues carrying the configured label.\n3. Deduplicate against a KV-store-backed set of already-processed issue keys so re-runs never create duplicate PRs.\n4. For each new issue, start an independent OpenHands agent conversation that extracts the GitHub repo from the ticket body, clones it, creates a branch named after the Jira key, implements or scaffolds the requested change, and opens a pull request.\n5. Immediately after the conversation is created, post a Jira comment on the issue: 'I'm on it: <conversation URL>'.\n6. Persist the processed issue key immediately after dispatching so the next poll skips it."
18
+ "exampleImplementation": "Trigger: cron polling (e.g. every 5 minutes)\nRequired integrations: Atlassian Rovo MCP for Jira access and a GitHub MCP connection. The poller also needs a Jira API token and a GitHub personal access token (repo + workflow scope) as secrets for its direct API calls.\n\n1. Connect Atlassian Rovo MCP and GitHub, then collect the Jira base URL, email, API token secret name, label to watch, and cron schedule from the user. No GitHub repo is needed at deploy time - each ticket must include the target repo (owner/repo) in its body.\n2. Poll POST /rest/api/3/search/jql on the Jira Cloud instance to find open issues carrying the configured label.\n3. Deduplicate against a KV-store-backed set of already-processed issue keys so re-runs never create duplicate PRs.\n4. For each new issue, start an independent OpenHands agent conversation that extracts the GitHub repo from the ticket body, clones it, creates a branch named after the Jira key, implements or scaffolds the requested change, and opens a pull request.\n5. Immediately after the conversation is created, post a Jira comment on the issue: 'I'm on it: <conversation URL>'.\n6. Persist the processed issue key immediately after dispatching so the next poll skips it."
19
19
  }
@@ -0,0 +1,76 @@
1
+ {
2
+ "id": "news-digest",
3
+ "name": "Daily news digest",
4
+ "category": "Research",
5
+ "icon": "activity",
6
+ "description": "Read a list of public RSS and Atom feeds on a schedule, hand an agent everything new, and have it pick out what matters for your topics and write a short digest. Connects to nothing and needs no credentials.",
7
+ "requires": {
8
+ "integrations": {},
9
+ "features": [
10
+ "customTarball"
11
+ ]
12
+ },
13
+ "popularityRank": 78,
14
+ "estimatedSetupMinutes": 2,
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
+ "setup": {
17
+ "version": "1.0",
18
+ "mode": "direct",
19
+ "form": {
20
+ "triggers": {
21
+ "cron": {
22
+ "schedule": {
23
+ "type": "cron",
24
+ "label": "Digest time",
25
+ "help": "When the digest is written. Work is keyed by UTC date, so a schedule more frequent than daily only polls until there is something new.",
26
+ "default": "0 8 * * *",
27
+ "required": true
28
+ },
29
+ "timezone": {
30
+ "type": "timezone",
31
+ "label": "Timezone",
32
+ "help": "Timezone the schedule is interpreted in.",
33
+ "default": "UTC",
34
+ "required": true
35
+ }
36
+ }
37
+ },
38
+ "args": {
39
+ "feeds": {
40
+ "type": "textarea",
41
+ "label": "Feeds",
42
+ "help": "One RSS or Atom feed URL per line. They must be public: this automation signs in to nothing, so a feed behind a login will simply fail and be skipped.",
43
+ "default": "https://news.ycombinator.com/rss\nhttps://feeds.arstechnica.com/arstechnica/index\nhttps://www.theverge.com/rss/index.xml",
44
+ "required": true,
45
+ "constraints": {
46
+ "minLength": 8,
47
+ "maxLength": 4000
48
+ }
49
+ },
50
+ "topics": {
51
+ "type": "textarea",
52
+ "label": "Topics of interest",
53
+ "help": "One topic per line, or separated by commas. The agent reads every new story and decides which ones are about these, so write them the way you would explain your interests to a colleague rather than as search terms. Leave this empty to cover whatever is most significant.",
54
+ "default": "artificial intelligence, open source, developer tools",
55
+ "required": false,
56
+ "constraints": {
57
+ "maxLength": 2000
58
+ }
59
+ }
60
+ }
61
+ },
62
+ "bundle": {
63
+ "version": "1.0.0",
64
+ "entrypoint": "python3 main.py",
65
+ "timeout": 900,
66
+ "files": {
67
+ "main.py": "skills/news-digest/scripts/main.py"
68
+ },
69
+ "config": {
70
+ "feeds": "{{form.feeds}}",
71
+ "topics": "{{form.topics}}"
72
+ }
73
+ },
74
+ "message": "This deployment cannot run the scheduled news digest directly. Set it up in this conversation instead: confirm the feeds to read, the topics to watch for, and the schedule, then create the automation."
75
+ }
76
+ }
@@ -4,13 +4,16 @@
4
4
 
5
5
  import entry0 from "./catalog/github-pr-reviewer/manifest.json" with { type: "json" };
6
6
  import entry1 from "./catalog/github-repo-monitor/manifest.json" with { type: "json" };
7
- import entry2 from "./catalog/slack-standup-digest/manifest.json" with { type: "json" };
8
- import entry3 from "./catalog/slack-channel-monitor/manifest.json" with { type: "json" };
9
- import entry4 from "./catalog/linear-triage-assistant/manifest.json" with { type: "json" };
10
- import entry5 from "./catalog/jira-issue-to-pr/manifest.json" with { type: "json" };
11
- import entry6 from "./catalog/research-brief-writer/manifest.json" with { type: "json" };
12
- import entry7 from "./catalog/upstream-fork-sync/manifest.json" with { type: "json" };
13
- import entry8 from "./catalog/incident-retrospective-drafter/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" };
14
17
 
15
18
  export const AUTOMATION_CATALOG_ENTRIES = [
16
19
  entry0,
@@ -22,4 +25,7 @@ export const AUTOMATION_CATALOG_ENTRIES = [
22
25
  entry6,
23
26
  entry7,
24
27
  entry8,
28
+ entry9,
29
+ entry10,
30
+ entry11,
25
31
  ];