@openhands/extensions 0.28.0 → 0.30.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 (89) hide show
  1. package/.agents/skills/custom-codereview-guide.md +44 -1
  2. package/.claude-plugin/marketplace.json +7 -5
  3. package/.codex-plugin/marketplace.json +7 -5
  4. package/.github/workflows/build-vscode-app.yml +3 -3
  5. package/.github/workflows/check-extensions.yml +1 -1
  6. package/.github/workflows/tests.yml +1 -1
  7. package/.plugin/marketplace.json +7 -5
  8. package/.release-please-manifest.json +1 -1
  9. package/AGENTS.md +7 -2
  10. package/README.md +3 -3
  11. package/apps/vscode/README.md +8 -6
  12. package/apps/vscode/canvas-extension.json +11 -3
  13. package/apps/vscode/extension.js +60 -12
  14. package/apps/vscode/scripts/package.mjs +20 -74
  15. package/automations/bundle-index.js +9 -7
  16. package/automations/catalog/github-issue-to-pr/manifest.json +1 -1
  17. package/automations/catalog/github-issue-triage/manifest.json +4 -3
  18. package/automations/catalog/github-pr-reviewer/manifest.json +5 -4
  19. package/automations/catalog/gitlab-issue-to-mr/manifest.json +3 -3
  20. package/automations/catalog/jira-issue-to-bitbucket-pr/manifest.json +4 -4
  21. package/automations/catalog/jira-issue-to-gitlab-mr/manifest.json +5 -5
  22. package/automations/catalog/jira-issue-to-pr/manifest.json +1 -1
  23. package/integrations/catalog/atlassian-rovo.json +4 -3
  24. package/integrations/catalog/bitbucket.json +16 -1
  25. package/integrations/catalog/github.json +1 -0
  26. package/integrations/catalog/gitlab.json +1 -1
  27. package/marketplaces/openhands-extensions.json +7 -5
  28. package/package.json +1 -1
  29. package/plugins/openhands/skills/openhands-automation/references/custom-automation.md +76 -8
  30. package/plugins/pr-review/README.md +1 -0
  31. package/plugins/pr-review/scripts/prompt.py +44 -11
  32. package/plugins/runtime-api-configs/SKILL.md +1 -1
  33. package/plugins/vulnerability-remediation/skills/github/scripts/agent_conversation.py +224 -8
  34. package/pyproject.toml +1 -1
  35. package/python/openhands_extensions/_version.py +1 -1
  36. package/skills/canvas-extension-api/SKILL.md +4 -1
  37. package/skills/canvas-extension-api/references/backend-safety.md +3 -3
  38. package/skills/canvas-extension-api/references/native-design.md +250 -0
  39. package/skills/canvas-extension-api/references/v1-contract.md +7 -4
  40. package/skills/canvas-extension-api/scripts/validate-extension.mjs +17 -1
  41. package/skills/canvas-extension-api/scripts/validate-extension.test.mjs +49 -0
  42. package/skills/github/scripts/agent_conversation.py +224 -8
  43. package/skills/github-issue-to-pr/scripts/agent_conversation.py +224 -8
  44. package/skills/github-issue-triage/README.md +73 -14
  45. package/skills/github-issue-triage/SKILL.md +26 -46
  46. package/skills/github-issue-triage/scripts/agent_conversation.py +224 -8
  47. package/skills/github-issue-triage/scripts/triage_publication.py +293 -0
  48. package/skills/github-issue-triage/scripts/worker.py +153 -103
  49. package/skills/github-pr-reviewer/README.md +103 -1
  50. package/skills/github-pr-reviewer/SKILL.md +35 -8
  51. package/skills/github-pr-reviewer/references/state-schema.md +8 -0
  52. package/skills/github-pr-reviewer/scripts/agent_conversation.py +224 -8
  53. package/skills/github-pr-reviewer/scripts/main.py +163 -39
  54. package/skills/github-pr-reviewer/scripts/publication.py +193 -0
  55. package/skills/github-pr-reviewer/scripts/worker.py +297 -8
  56. package/skills/github-pr-reviewer/tests/test_main.py +73 -5
  57. package/skills/gitlab-issue-to-mr/README.md +10 -3
  58. package/skills/gitlab-issue-to-mr/SKILL.md +43 -9
  59. package/skills/gitlab-issue-to-mr/references/state-schema.md +4 -0
  60. package/skills/gitlab-issue-to-mr/scripts/main.py +359 -25
  61. package/skills/index.js +10 -10
  62. package/skills/jira-issue-to-pr/.claude-plugin/plugin.json +4 -1
  63. package/skills/jira-issue-to-pr/.codex-plugin/plugin.json +4 -1
  64. package/skills/jira-issue-to-pr/.plugin/plugin.json +4 -1
  65. package/skills/jira-issue-to-pr/README.md +18 -11
  66. package/skills/jira-issue-to-pr/SKILL.md +72 -23
  67. package/skills/jira-issue-to-pr/references/setup.md +43 -12
  68. package/skills/jira-issue-to-pr/scripts/main.py +136 -26
  69. package/skills/openhands-automation/references/custom-automation.md +76 -8
  70. package/skills/slack-channel-monitor/README.md +6 -1
  71. package/skills/slack-channel-monitor/SKILL.md +6 -3
  72. package/skills/slack-channel-monitor/scripts/main.py +36 -4
  73. package/skills/ticket-to-code-change/.claude-plugin/plugin.json +1 -2
  74. package/skills/ticket-to-code-change/.codex-plugin/plugin.json +1 -2
  75. package/skills/ticket-to-code-change/.plugin/plugin.json +1 -2
  76. package/skills/ticket-to-code-change/SKILL.md +5 -3
  77. package/skills/ticket-to-code-change/commands/ticket-to-code-change-setup.md +1 -1
  78. package/tests/fixtures/automations/github-pr-reviewer.json +9 -9
  79. package/tests/test_agent_conversation_dispatch.py +173 -6
  80. package/tests/test_automation_llm_provenance.py +1209 -0
  81. package/tests/test_github_review_publication.py +422 -0
  82. package/tests/test_github_reviewer_delivery.py +174 -21
  83. package/tests/test_github_triage_delivery.py +411 -238
  84. package/tests/test_gitlab_issue_to_mr.py +284 -0
  85. package/tests/test_jira_issue_to_pr.py +200 -6
  86. package/tests/test_pr_review_prompt_injection.py +353 -0
  87. package/tests/test_slack_channel_monitor.py +32 -1
  88. package/tests/test_vscode_app.py +8 -2
  89. package/tests/vscode-app.test.mjs +8 -2
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "jira-issue-to-pr",
3
3
  "version": "1.0.0",
4
- "description": "Deploy a cron-based OpenHands automation that watches a Jira Cloud project for issues labeled with a configurable label (default: create-pr) and spawns an agent conversation to create 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.",
4
+ "description": "Deploy a cron-based OpenHands automation that opens a GitHub pull request, a GitLab merge request or a Bitbucket pull request for each Jira issue carrying a configurable label (default: create-pr). The target repository is read from the ticket body - no repo parameter required at deploy time.",
5
5
  "author": {
6
6
  "name": "OpenHands",
7
7
  "email": "contact@all-hands.dev"
@@ -13,7 +13,10 @@
13
13
  "jira",
14
14
  "atlassian",
15
15
  "github",
16
+ "gitlab",
17
+ "bitbucket",
16
18
  "pull-request",
19
+ "merge-request",
17
20
  "automation"
18
21
  ]
19
22
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "jira-issue-to-pr",
3
3
  "version": "1.0.0",
4
- "description": "Deploy a cron-based OpenHands automation that watches a Jira Cloud project for issues labeled with a configurable label (default: create-pr) and spawns an agent conversation to create 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.",
4
+ "description": "Deploy a cron-based OpenHands automation that opens a GitHub pull request, a GitLab merge request or a Bitbucket pull request for each Jira issue carrying a configurable label (default: create-pr). The target repository is read from the ticket body - no repo parameter required at deploy time.",
5
5
  "author": {
6
6
  "name": "OpenHands",
7
7
  "email": "contact@all-hands.dev"
@@ -13,7 +13,10 @@
13
13
  "jira",
14
14
  "atlassian",
15
15
  "github",
16
+ "gitlab",
17
+ "bitbucket",
16
18
  "pull-request",
19
+ "merge-request",
17
20
  "automation"
18
21
  ]
19
22
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "jira-issue-to-pr",
3
3
  "version": "1.0.0",
4
- "description": "Deploy a cron-based OpenHands automation that watches a Jira Cloud project for issues labeled with a configurable label (default: create-pr) and spawns an agent conversation to create 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.",
4
+ "description": "Deploy a cron-based OpenHands automation that opens a GitHub pull request, a GitLab merge request or a Bitbucket pull request for each Jira issue carrying a configurable label (default: create-pr). The target repository is read from the ticket body - no repo parameter required at deploy time.",
5
5
  "author": {
6
6
  "name": "OpenHands",
7
7
  "email": "contact@all-hands.dev"
@@ -13,7 +13,10 @@
13
13
  "jira",
14
14
  "atlassian",
15
15
  "github",
16
+ "gitlab",
17
+ "bitbucket",
16
18
  "pull-request",
19
+ "merge-request",
17
20
  "automation"
18
21
  ]
19
22
  }
@@ -1,10 +1,12 @@
1
- # Jira Issue to GitHub PR
1
+ # Jira Issue to Pull Request (GitHub, GitLab, Bitbucket)
2
2
 
3
3
  Deploy a cron-based OpenHands automation that polls a Jira Cloud project for
4
4
  open issues carrying a configurable label (default: `create-pr`) and, for each
5
- new issue, starts an OpenHands agent conversation that clones the GitHub
6
- repository named in the ticket body, creates a branch, implements the requested
7
- change, and opens a pull request. Once the conversation starts, it posts a
5
+ new issue, starts an OpenHands agent conversation that clones the repository
6
+ named in the ticket body on the configured git provider (GitHub by default,
7
+ GitLab or Bitbucket with `git_provider`), creates a branch, implements the
8
+ requested change, and opens a pull request (a merge request on GitLab). Once the
9
+ conversation starts, it posts a
8
10
  comment on the Jira ticket: "I'm on it: `<conversation URL>`".
9
11
 
10
12
  ## Triggers
@@ -16,12 +18,16 @@ This skill is activated by keywords:
16
18
  - `automatically create GitHub PRs from Jira tickets`
17
19
  - `deploy a Jira issue-to-PR automation`
18
20
  - `create a Jira to GitHub PR workflow`
21
+ - `set up the Jira issue to GitLab MR automation`
22
+ - `set up the Jira issue to Bitbucket PR automation`
19
23
  - `automate GitHub PR creation from a Jira label`
20
24
 
21
25
  ## How It Works
22
26
 
23
- 1. **Poll** - every N minutes, the script calls `POST /rest/api/3/search/jql`
24
- on the Jira Cloud instance to find open issues with the configured label.
27
+ 1. **Poll** - every N minutes, the script searches the Jira Cloud instance for
28
+ open issues with the configured label: through the user's connected
29
+ Atlassian Rovo MCP server on OpenHands Cloud and Enterprise, or with
30
+ `POST /rest/api/3/search/jql` and an API token.
25
31
  2. **Deduplicate** - on the first run the script records a `first_run_at`
26
32
  baseline timestamp in the KV store; issues whose `updated` timestamp
27
33
  predates that baseline are skipped (no backfill blast on first deploy).
@@ -32,7 +38,8 @@ This skill is activated by keywords:
32
38
  conversation with a PR-creation prompt: `POST /api/conversations` on the
33
39
  agent server when running locally, `POST /api/v1/app-conversations` on
34
40
  OpenHands Cloud and Enterprise. The prompt instructs the agent to extract the
35
- target GitHub repository (`owner/repo`) from the ticket body. On Cloud the
41
+ target repository (`owner/repo` on GitHub; `group/project` or a URL on
42
+ GitLab; `workspace/repo` on Bitbucket) from the ticket body. On Cloud the
36
43
  next poll confirms the conversation came up and starts it again when it did
37
44
  not.
38
45
  4. **Comment** - immediately after the conversation is created, the script
@@ -52,13 +59,13 @@ OpenHands and Jira. See "Event-Based Alternative" in `SKILL.md`.
52
59
 
53
60
  | Requirement | Details |
54
61
  |---|---|
55
- | **Jira API token** | Stored as an OpenHands secret (see `references/setup.md`) |
56
- | **GitHub token** | Stored as an OpenHands secret with `repo` + `workflow` scope so the spawned conversation can push branches and open PRs |
62
+ | **Jira access** | OpenHands Cloud and Enterprise: the user's connected Atlassian Rovo MCP server, with no API token. Local, or without that connection: a Jira API token stored as an OpenHands secret (see `references/setup.md`) |
63
+ | **Git provider access** | OpenHands Cloud and Enterprise: the connected GitHub, GitLab or Bitbucket integration named by `git_provider`, or a connected MCP server (GitHub's, GitLab's, or Atlassian Rovo for Bitbucket). Local: that provider's token stored as an OpenHands secret so the spawned conversation can push branches and open the request |
57
64
  | **Jira label** | The label to watch for (default: `create-pr`) must exist in the Jira project |
58
- | **GitHub repo** | The target repository must exist and the GitHub token must have write access |
65
+ | **Target repository** | Must exist on the configured provider; the connected integration or token must have write access |
59
66
 
60
67
  ## Quick Start
61
68
 
62
69
  See `SKILL.md` for the full step-by-step deployment guide, and
63
- `references/setup.md` for Jira API token creation, GitHub token scopes, cron
70
+ `references/setup.md` for Jira API token creation, git provider tokens, cron
64
71
  schedule reference, and troubleshooting.
@@ -4,25 +4,31 @@ description: >
4
4
  This skill should be used when the user asks to "set up a Jira automation to create pull requests",
5
5
  "poll Jira for create-pr issues", "automatically create GitHub PRs from Jira tickets",
6
6
  "deploy a Jira issue-to-PR automation", "create a Jira to GitHub PR workflow",
7
- or mentions automating GitHub PR creation from a Jira label.
7
+ "set up the Jira issue to GitLab MR automation", "set up the Jira issue to Bitbucket PR automation",
8
+ "open GitLab merge requests from Jira tickets", "open Bitbucket pull requests from Jira tickets",
9
+ or mentions automating pull request or merge request creation from a Jira label.
8
10
  Deploys a cron-based OpenHands automation that watches a Jira Cloud project for issues
9
11
  labeled with a configurable label (default: "create-pr") and spawns an agent conversation
10
- to create a GitHub pull request for each new issue found. The target GitHub repository
11
- is read from the body of the Jira ticket - no repo parameter is required at deploy time.
12
+ that opens a pull request on GitHub (the default), a merge request on GitLab, or a pull
13
+ request on Bitbucket for each new issue found, chosen with git_provider. The target
14
+ repository is read from the body of the Jira ticket - no repo parameter is required at deploy time.
12
15
  ---
13
16
 
14
- # Jira → GitHub PR Automation
17
+ # Jira → Pull Request Automation (GitHub, GitLab, Bitbucket)
15
18
 
16
19
  Deploys a cron automation that polls a Jira Cloud instance for open issues carrying a
17
20
  configurable label and, for each new issue, starts an OpenHands agent conversation that
18
- clones the GitHub repository specified in the ticket body, creates a branch, implements
19
- or placeholders the requested change, and opens a pull request. Once the conversation
21
+ clones the repository specified in the ticket body on the configured git provider (GitHub
22
+ by default, GitLab or Bitbucket with `git_provider`), creates a branch, implements or
23
+ placeholders the requested change, and opens a pull request (a merge request on GitLab).
24
+ Once the conversation
20
25
  starts, it also posts a comment on the Jira ticket: "I'm on it: &lt;conversation URL&gt;".
21
26
 
22
27
  ## How It Works
23
28
 
24
- 1. **Poll** - every N minutes, `POST /rest/api/3/search/jql` on the Jira Cloud instance
25
- to find open issues with the configured label.
29
+ 1. **Poll** - every N minutes, search the Jira Cloud instance for open issues with the
30
+ configured label: through the user's connected Atlassian Rovo MCP server on OpenHands
31
+ Cloud and Enterprise, or with `POST /rest/api/3/search/jql` and an API token.
26
32
  2. **Deduplicate** - on the very first run the script records a `first_run_at` baseline
27
33
  timestamp in the KV store; any issue whose `updated` timestamp predates that baseline
28
34
  is skipped (no backfill blast on first deploy). Using `updated` rather than `created`
@@ -33,7 +39,8 @@ starts, it also posts a comment on the Jira ticket: "I'm on it: &lt;conversation
33
39
  3. **Dispatch** - for each new issue, start an independent agent conversation with a
34
40
  PR-creation prompt: `POST /api/conversations` on the agent server when running locally,
35
41
  or `POST /api/v1/app-conversations` on OpenHands Cloud. The prompt instructs the agent
36
- to extract the target GitHub repository (`owner/repo`) from the ticket body.
42
+ to extract the target repository (`owner/repo` on GitHub; `group/project` or a URL on GitLab;
43
+ `workspace/repo` on Bitbucket) from the ticket body.
37
44
  4. **Comment** - immediately after the conversation is created, post a Jira comment on the
38
45
  issue: `I'm on it: <conversation URL>`.
39
46
  5. **Persist** - record the processed issue key so re-runs never duplicate work.
@@ -47,11 +54,11 @@ Before deploying, ensure the following are in place:
47
54
 
48
55
  | Requirement | Details |
49
56
  |---|---|
50
- | **Jira API token** | Stored as an OpenHands secret (see [Jira API token setup](#jira-api-token)) |
51
- | **GitHub access** | Local: a GitHub token stored as an OpenHands secret with `repo` + `workflow` scope so the spawned conversation can push branches and open PRs. OpenHands Cloud: the spawned conversation uses the user's connected GitHub integration (native integration recommended, or the GitHub MCP server) |
57
+ | **Jira access** | OpenHands Cloud and Enterprise: the user's connected Atlassian Rovo MCP server, with no API token. Local, or without that connection: a Jira API token stored as an OpenHands secret (see [Jira API token setup](#jira-api-token)) |
58
+ | **Git provider access** | OpenHands Cloud and Enterprise: the user's connected GitHub, GitLab or Bitbucket integration, whichever `git_provider` names. A connected MCP server also works - GitHub's (with the saved access token), GitLab's, or Atlassian Rovo for Bitbucket - with a private repository read through the tools rather than cloned. Local: a token for that provider stored as an OpenHands secret (`GITHUB_TOKEN` with `repo` + `workflow`, `GITLAB_TOKEN` with `api`, `BITBUCKET_TOKEN`) so the spawned conversation can push branches and open the request |
52
59
  | **KV store** (OpenHands Cloud only) | The automation service must have its KV store enabled (`kvStore` in `GET /api/automation/v1/capabilities`); each cloud run starts in a fresh sandbox, so processed issues are remembered there |
53
60
  | **Jira label** | The label to watch for (default: `create-pr`) must exist in the Jira project |
54
- | **GitHub repo** | The target repository must exist and the GitHub token must have write access |
61
+ | **Target repository** | Must exist on the configured provider; the connected integration or token must have write access |
55
62
 
56
63
  ## Deploying the Automation
57
64
 
@@ -72,24 +79,53 @@ Set `OPENHANDS_HOST` and `AUTH_HEADER` for the curl commands below:
72
79
 
73
80
  ### Step 1 - Collect parameters
74
81
 
75
- Gather the following from the user before proceeding:
82
+ First decide how the poller reaches Jira:
83
+
84
+ - **Connected Atlassian Rovo MCP server** - on OpenHands Cloud and Enterprise, when the
85
+ user has connected it. OpenHands calls Jira for the poller through that connection, so
86
+ do not ask for a Jira email or an API token and do not create a secret.
87
+ - **Jira API token** - on a local Agent Canvas, or when the Rovo server is not connected.
88
+
89
+ Then pick `git_provider` from the automation the user asked for: `github` for *Jira issue to
90
+ GitHub PR* (the default, so it can be left out), `gitlab` for *Jira issue to GitLab MR*,
91
+ `bitbucket` for *Jira issue to Bitbucket PR*. It changes only what the conversation is told;
92
+ the conversation pushes with the user's connected integration for that provider, or delivers
93
+ through the connected MCP server's tools when it has no token.
94
+
95
+ Then gather the parameters for that route, plus the shared ones, before proceeding:
76
96
 
77
97
  | Parameter | Example | Notes |
78
98
  |---|---|---|
79
- | `jira_base_url` | `https://acme.atlassian.net` | No trailing slash |
80
- | `jira_email` | `alice@acme.com` | Atlassian account email for Basic auth |
81
- | `jira_token_secret` | `JIRA_CLOUD_KEY` | Name of the OpenHands secret holding the API token |
99
+ | `jira_mcp_server` | `atlassian-rovo` | Rovo connection only. The name the server is stored under: the key in `agent_settings.mcp_config` of `GET ${OPENHANDS_HOST}/api/v1/settings` whose `url` is on `mcp.atlassian.com`. Look it up; do not ask the user |
100
+ | `jira_cloud_id` | `1324a887-45db-1bf4-1e99-ef0ff456d421` | Rovo connection only. The `id` of the Jira site, from the Rovo tool `getAccessibleAtlassianResources`. Ask which site only when it lists several |
101
+ | `jira_base_url` | `https://acme.atlassian.net` | API token only. No trailing slash |
102
+ | `jira_email` | `alice@acme.com` | API token only. Atlassian account email for Basic auth |
103
+ | `jira_token_secret` | `JIRA_CLOUD_KEY` | API token only. Name of the OpenHands secret holding the API token |
82
104
  | `jira_label` | `create-pr` | Label to watch for (optional, defaults to `create-pr`) |
105
+ | `git_provider` | `gitlab` | `github` (default), `gitlab` or `bitbucket` - the provider the ticket names its repository on (optional) |
83
106
  | `max_new_per_run` | `5` | Max conversations dispatched per cron firing (optional, defaults to `5`) |
84
107
  | `cron_schedule` | `*/5 * * * *` | Polling frequency in cron syntax |
85
108
 
86
- > **Note**: The GitHub repository is not configured here. Each Jira ticket body must include
87
- > a reference to the target GitHub repo in `owner/repo` format (e.g. `acme-org/backend`).
88
- > The spawned agent extracts it from the ticket text.
109
+ > **Note**: The repository is not configured here. Each Jira ticket body must name it:
110
+ > `owner/repo` on GitHub, `group/subgroup/project` or a full URL on GitLab (self-managed
111
+ > hosts included), `workspace/repo` on bitbucket.org. The spawned agent extracts it from
112
+ > the ticket text.
89
113
 
90
114
  ### Step 2 - Create config.json
91
115
 
92
- Create `config.json` next to `scripts/main.py` when packaging:
116
+ Create `config.json` next to `scripts/main.py` when packaging. With the connected
117
+ Atlassian Rovo MCP server:
118
+
119
+ ```json
120
+ {
121
+ "jira_mcp_server": "atlassian-rovo",
122
+ "jira_cloud_id": "1324a887-45db-1bf4-1e99-ef0ff456d421",
123
+ "jira_label": "create-pr",
124
+ "max_new_per_run": 5
125
+ }
126
+ ```
127
+
128
+ With a Jira API token:
93
129
 
94
130
  ```json
95
131
  {
@@ -101,6 +137,9 @@ Create `config.json` next to `scripts/main.py` when packaging:
101
137
  }
102
138
  ```
103
139
 
140
+ For the GitLab and Bitbucket templates add `"git_provider": "gitlab"` or
141
+ `"git_provider": "bitbucket"` to either example; it is `github` when omitted.
142
+
104
143
  ### Step 3 - Package the tarball
105
144
 
106
145
  Copy `scripts/main.py` from this skill and package it with the `config.json`:
@@ -143,7 +182,8 @@ curl -s -X POST "${OPENHANDS_HOST}/api/automation/v1" \
143
182
  }" | python3 -m json.tool
144
183
  ```
145
184
 
146
- Save the returned `id` - use it for updates and monitoring.
185
+ Save the returned `id` - use it for updates and monitoring. Name the automation after the
186
+ template the user picked, for example `Jira issue-to-MR Poller` for GitLab.
147
187
 
148
188
  ### Step 6 - Verify with a test dispatch
149
189
 
@@ -158,6 +198,14 @@ curl -s "${OPENHANDS_HOST}/api/automation/v1/<AUTOMATION_ID>/runs?limit=1" \
158
198
  | python3 -c "import sys,json; r=json.load(sys.stdin)['runs'][0]; print(r['status'], r.get('error_detail'))"
159
199
  ```
160
200
 
201
+ With the Rovo connection, a run that fails on `/api/v1/mcp/servers/<name>/call-tool` says why:
202
+
203
+ - `404` with `No connected MCP server is named ...` - `jira_mcp_server` is not the name the
204
+ server is stored under, or the user switched the server off.
205
+ - `404` with `Not Found` - this deployment cannot call a connected MCP server for a run yet.
206
+ Set the automation up with a Jira API token instead.
207
+ - `502` - the server could not be reached, or the user has to reconnect it in the settings.
208
+
161
209
  ## Event-Based Alternative
162
210
 
163
211
  Where Jira can reach the deployment over the internet (OpenHands Cloud and Enterprise),
@@ -287,7 +335,8 @@ The automation script lives at `scripts/main.py`. Key behaviors:
287
335
  - **First-run baseline** - on the very first execution the script writes `first_run_at` (UTC timestamp) into the KV store and exits without dispatching; issues whose `updated` timestamp predates that baseline are skipped on all subsequent runs. Using `updated` (not `created`) means an old issue that has its label applied after deployment is correctly treated as new.
288
336
  - **Per-run cap** - `max_new_per_run` (default 5) limits how many conversations are started per cron firing; any remaining new issues are dispatched on the next run.
289
337
  - **KV store** - persists `{"processed_keys": [...], "first_run_at": "..."}` between runs; falls back to a local file in local dev environments where `AUTOMATION_KV_TOKEN` is absent (on OpenHands Cloud the run fails instead, since its sandbox does not persist).
290
- - **Jira API** - uses `POST /rest/api/3/search/jql` (the current non-deprecated endpoint).
338
+ - **Jira access** - with `jira_mcp_server` set, searches and comments through the user's connected Atlassian Rovo MCP server (`POST /api/v1/mcp/servers/<name>/call-tool` on OpenHands Cloud, tools `searchJiraIssuesUsingJql` and `addOrEditJiraIssueComment`, or `addCommentToJiraIssue` on a server that still offers the v1 tools), so the run reads no Jira credential. Otherwise uses the Jira REST API with the token secret: `POST /rest/api/3/search/jql` (the current non-deprecated endpoint).
339
+ - **Git provider** - `git_provider` selects the prompt's wording (GitHub pull request, GitLab merge request, Bitbucket pull request), the repository formats the agent looks for, and how it delivers without a token (GitLab's MCP tools, Rovo's Bitbucket tools); nothing else differs between the three templates.
291
340
  - **Conversation dispatch** - locally, calls `POST /api/conversations` on the agent server with the current user's LLM/agent settings forwarded to the new conversation; on OpenHands Cloud, calls `POST /api/v1/app-conversations`, which runs each conversation in its own sandbox with the user's settings, secrets and connected git provider.
292
341
  - **Start confirmation** (OpenHands Cloud only) - the API answers a start request before the conversation exists, so the next run checks each one. A start that failed is made again, up to three times, and after that the failure is posted on the Jira issue.
293
342
  - **Error transparency** - captures Jira HTTP response bodies in error messages for fast diagnosis.
@@ -324,4 +373,4 @@ that issue again.
324
373
 
325
374
  ## Additional Resources
326
375
 
327
- - **`references/setup.md`** - Jira API token creation, GitHub token scopes, cron schedule reference, and troubleshooting guide.
376
+ - **`references/setup.md`** - Jira API token creation, git provider tokens, cron schedule reference, and troubleshooting guide.
@@ -2,6 +2,9 @@
2
2
 
3
3
  ## Jira API Token
4
4
 
5
+ The poller needs this token only when it does not reach Jira through a connected
6
+ Atlassian Rovo MCP server (see Step 1 in `SKILL.md`).
7
+
5
8
  ### Create a token
6
9
 
7
10
  1. Log in to [id.atlassian.com](https://id.atlassian.com/manage-profile/security/api-tokens).
@@ -38,11 +41,19 @@ The Jira Cloud REST API v3 requires this for all authenticated requests.
38
41
 
39
42
  ---
40
43
 
41
- ## GitHub Token
44
+ ## Git Provider Access
42
45
 
43
46
  The spawned agent conversation clones the target repository, pushes a new branch, and
44
- opens a pull request. The GitHub token must be stored as an OpenHands secret and must
45
- have the following scopes:
47
+ opens the pull or merge request. On OpenHands Cloud and Enterprise it uses the connected
48
+ integration for the provider named by `git_provider` (GitHub, GitLab or Bitbucket). With
49
+ only an MCP connection (GitHub's with its saved token, GitLab's, or Atlassian Rovo for
50
+ Bitbucket) it commits through the tools instead, and reads a private repository through
51
+ them rather than cloning it. On a local Agent Canvas a token for the provider must be
52
+ stored as an OpenHands secret.
53
+
54
+ ### GitHub
55
+
56
+ The GitHub token must have the following scopes:
46
57
 
47
58
  | Scope | Required for |
48
59
  |---|---|
@@ -57,20 +68,39 @@ inherits the user's configured secrets automatically through the agent server.
57
68
  Navigate to **Settings → Secrets** and store the token under the name `GITHUB_TOKEN`
58
69
  (or whatever name is expected by the agent's GitHub skill).
59
70
 
71
+ ### GitLab
72
+
73
+ Store a personal access token with the `api` scope and at least the Developer role on the
74
+ target projects under the name `GITLAB_TOKEN`.
75
+
76
+ Calling GitLab MCP directly, to commit without a token, needs GitLab 19.4 or later, where its
77
+ branch, commit and repository tools first appear. On OpenHands Cloud and Enterprise the token
78
+ of the user's GitLab sign-in or connected integration reaches the conversation as
79
+ `GITLAB_TOKEN`, so on an older GitLab sign in with GitLab or connect it under Settings ->
80
+ Integrations, and store this secret only if neither is possible.
81
+
82
+ ### Bitbucket
83
+
84
+ Store the token under the name `BITBUCKET_TOKEN`; the `bitbucket` skill describes the token
85
+ type and permissions.
86
+
60
87
  ---
61
88
 
62
89
  ## config.json Field Reference
63
90
 
64
91
  | Field | Required | Default | Description |
65
92
  |---|---|---|---|
66
- | `jira_base_url` | ✅ | - | Full URL of your Atlassian instance, e.g. `https://acme.atlassian.net` |
67
- | `jira_email` | ✅ | - | Email address of the Atlassian account that owns the API token |
93
+ | `jira_mcp_server` | ❌ | - | Name the connected Atlassian Rovo MCP server is stored under. When set, the poller reaches Jira through it (OpenHands Cloud and Enterprise only) and the three fields after `jira_cloud_id` are not used |
94
+ | `jira_cloud_id` | with `jira_mcp_server` | - | Atlassian cloud id of the Jira site |
95
+ | `jira_base_url` | without `jira_mcp_server` | - | Full URL of your Atlassian instance, e.g. `https://acme.atlassian.net` |
96
+ | `jira_email` | without `jira_mcp_server` | - | Email address of the Atlassian account that owns the API token |
68
97
  | `jira_token_secret` | ❌ | `"JIRA_CLOUD_KEY"` | Name of the OpenHands secret holding the Jira API token |
69
98
  | `jira_label` | ❌ | `"create-pr"` | Jira issue label to watch for |
99
+ | `git_provider` | ❌ | `"github"` | `github`, `gitlab` or `bitbucket` - the provider the ticket names its repository on; changes only the prompt |
70
100
 
71
- > **GitHub repo**: not a config field. The target repository is read from the body of each
72
- > Jira ticket. Ticket authors must include the repo in `owner/repo` format or as a full
73
- > GitHub URL (e.g. `https://github.com/acme-org/backend`).
101
+ > **Repository**: not a config field. The target repository is read from the body of each
102
+ > Jira ticket: `owner/repo` or a GitHub URL on GitHub, `group/subgroup/project` or a full
103
+ > URL on GitLab, `workspace/repo` on bitbucket.org.
74
104
 
75
105
  ---
76
106
 
@@ -142,11 +172,12 @@ The response is `SearchAndReconcileResults`; the script reads the `issues` array
142
172
  - The Jira project has issues with the label but all are in a Done status category.
143
173
  The JQL filter is `statusCategory != Done` - reopen or create a fresh issue.
144
174
 
145
- ### Conversation started but no PR appears
175
+ ### Conversation started but no PR or MR appears
146
176
 
147
177
  - The spawned conversation inherits the user's agent/LLM settings. Check the conversation
148
178
  in the OpenHands UI (it appears in the conversations list under the automation run).
149
- - The GitHub token may lack `repo` scope to push or open PRs.
179
+ - The connected integration or token may lack the scope to push or open the request
180
+ (GitHub `repo`, GitLab `api` with the Developer role).
150
181
  - The target repo's default branch may be protected; the token must have bypass permission,
151
182
  or the PR should be created against a different base branch.
152
183
 
@@ -166,13 +197,13 @@ The response is `SearchAndReconcileResults`; the script reads the `issues` array
166
197
 
167
198
  ## Multiple Deployments
168
199
 
169
- To watch multiple Jira projects or multiple GitHub repos, deploy separate automations —
200
+ To watch multiple Jira projects or multiple repositories, deploy separate automations —
170
201
  one per `config.json`. Each automation has its own KV-store namespace (keyed by
171
202
  automation ID), so processed-key sets do not cross-contaminate.
172
203
 
173
204
  Example: two automations, one per project:
174
205
 
175
- | Automation name | `jira_base_url` | `jira_label` | GitHub repo (in ticket body) |
206
+ | Automation name | `jira_base_url` | `jira_label` | Repository (in ticket body) |
176
207
  |---|---|---|---|
177
208
  | `Jira issue-to-PR - frontend` | `https://acme.atlassian.net` | `create-pr` | `acme/frontend` (written by ticket author) |
178
209
  | `Jira issue-to-PR - backend` | `https://acme.atlassian.net` | `create-pr-backend` | `acme/backend` (written by ticket author) |