@openhands/extensions 0.5.0 → 0.7.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 (135) hide show
  1. package/.github/workflows/pypi-publish.yml +104 -0
  2. package/.github/workflows/tests.yml +6 -0
  3. package/.release-please-manifest.json +1 -1
  4. package/AGENTS.md +1 -1
  5. package/README.md +34 -4
  6. package/integrations/README.md +25 -9
  7. package/integrations/catalog/airtable.json +16 -10
  8. package/integrations/catalog/apify.json +0 -2
  9. package/integrations/catalog/asana.json +33 -0
  10. package/integrations/catalog/atlassian.json +5 -8
  11. package/integrations/catalog/bitbucket.json +34 -0
  12. package/integrations/catalog/box.json +34 -0
  13. package/integrations/catalog/brave-search.json +1 -2
  14. package/integrations/catalog/browser-mcp.json +0 -3
  15. package/integrations/catalog/canva.json +31 -0
  16. package/integrations/catalog/clickhouse.json +1 -2
  17. package/integrations/catalog/cloudflare-bindings.json +5 -8
  18. package/integrations/catalog/cloudflare-browser-rendering.json +5 -8
  19. package/integrations/catalog/cloudflare-builds.json +6 -9
  20. package/integrations/catalog/cloudflare-docs.json +4 -7
  21. package/integrations/catalog/cloudflare-observability.json +5 -8
  22. package/integrations/catalog/confluence.json +33 -0
  23. package/integrations/catalog/datadog.json +34 -0
  24. package/integrations/catalog/deepwiki.json +3 -7
  25. package/integrations/catalog/discord.json +34 -0
  26. package/integrations/catalog/elevenlabs.json +27 -28
  27. package/integrations/catalog/everything.json +0 -2
  28. package/integrations/catalog/exa.json +0 -2
  29. package/integrations/catalog/fetch.json +0 -2
  30. package/integrations/catalog/figma.json +35 -9
  31. package/integrations/catalog/filesystem.json +0 -3
  32. package/integrations/catalog/firecrawl.json +0 -2
  33. package/integrations/catalog/git.json +0 -3
  34. package/integrations/catalog/github.json +34 -10
  35. package/integrations/catalog/gmail.json +33 -0
  36. package/integrations/catalog/google-calendar.json +33 -0
  37. package/integrations/catalog/google-docs.json +33 -0
  38. package/integrations/catalog/google-drive.json +33 -0
  39. package/integrations/catalog/google-sheets.json +33 -0
  40. package/integrations/catalog/hubspot.json +34 -0
  41. package/integrations/catalog/huggingface.json +1 -2
  42. package/integrations/catalog/intercom.json +34 -0
  43. package/integrations/catalog/jira.json +33 -0
  44. package/integrations/catalog/kagi.json +2 -3
  45. package/integrations/catalog/linear.json +24 -16
  46. package/integrations/catalog/memory.json +0 -2
  47. package/integrations/catalog/microsoft-outlook.json +33 -0
  48. package/integrations/catalog/microsoft-teams.json +33 -0
  49. package/integrations/catalog/miro.json +42 -0
  50. package/integrations/catalog/monday.json +42 -0
  51. package/integrations/catalog/mongodb.json +1 -2
  52. package/integrations/catalog/neon.json +0 -2
  53. package/integrations/catalog/netlify.json +33 -0
  54. package/integrations/catalog/notion.json +30 -10
  55. package/integrations/catalog/obsidian.json +1 -3
  56. package/integrations/catalog/okta.json +33 -0
  57. package/integrations/catalog/onedrive.json +33 -0
  58. package/integrations/catalog/ordinal.json +33 -0
  59. package/integrations/catalog/paypal.json +5 -8
  60. package/integrations/catalog/playwright.json +0 -2
  61. package/integrations/catalog/posthog.json +38 -0
  62. package/integrations/catalog/quickbooks.json +86 -0
  63. package/integrations/catalog/redis.json +1 -3
  64. package/integrations/catalog/resend.json +1 -2
  65. package/integrations/catalog/salesforce.json +44 -0
  66. package/integrations/catalog/sentry.json +47 -14
  67. package/integrations/catalog/sequential-thinking.json +0 -2
  68. package/integrations/catalog/sharepoint.json +33 -0
  69. package/integrations/catalog/slack.json +49 -10
  70. package/integrations/catalog/stripe.json +39 -14
  71. package/integrations/catalog/supabase.json +31 -9
  72. package/integrations/catalog/tavily.json +0 -2
  73. package/integrations/catalog/time.json +0 -2
  74. package/integrations/catalog/trello.json +34 -0
  75. package/integrations/catalog/vercel.json +33 -0
  76. package/integrations/catalog/webflow.json +34 -0
  77. package/integrations/catalog/xero.json +33 -0
  78. package/integrations/catalog/zoom.json +33 -0
  79. package/integrations/catalog-index.js +151 -0
  80. package/integrations/catalog.schema.json +255 -0
  81. package/integrations/index.d.ts +49 -69
  82. package/integrations/index.js +36 -206
  83. package/marketplaces/openhands-extensions.json +40 -2
  84. package/package.json +4 -7
  85. package/plugins/cobol-modernization/README.md +3 -3
  86. package/plugins/cobol-modernization/skills/{cobol-modernization-overview → cobol-modernization}/SKILL.md +1 -1
  87. package/plugins/magic-test/skills/magic-word/SKILL.md +1 -0
  88. package/plugins/migration-scoring/README.md +1 -1
  89. package/plugins/pr-review/scripts/prompt.py +1 -1
  90. package/pyproject.toml +18 -3
  91. package/python/openhands_extensions/__init__.py +24 -0
  92. package/python/openhands_extensions/_version.py +25 -0
  93. package/python/openhands_extensions/integrations.py +92 -0
  94. package/release-please-config.json +2 -1
  95. package/scripts/build-integration-catalog.mjs +45 -0
  96. package/skills/agent-canvas-environment/.plugin/plugin.json +19 -0
  97. package/skills/agent-canvas-environment/README.md +5 -0
  98. package/skills/agent-canvas-environment/SKILL.md +202 -0
  99. package/skills/bitbucket/README.md +23 -40
  100. package/skills/bitbucket/SKILL.md +43 -31
  101. package/skills/bitbucket-cloud/.plugin/plugin.json +18 -0
  102. package/skills/bitbucket-cloud/README.md +15 -0
  103. package/skills/bitbucket-cloud/SKILL.md +46 -0
  104. package/skills/bitbucket-data-center/.plugin/plugin.json +19 -0
  105. package/skills/bitbucket-data-center/README.md +20 -0
  106. package/skills/bitbucket-data-center/SKILL.md +53 -0
  107. package/skills/code-review/SKILL.md +1 -1
  108. package/skills/code-review/references/supply-chain-security.md +2 -2
  109. package/skills/github-pr-reviewer/references/state-schema.md +18 -4
  110. package/skills/github-pr-reviewer/scripts/main.py +66 -12
  111. package/skills/github-repo-monitor/references/state-schema.md +11 -4
  112. package/skills/github-repo-monitor/scripts/main.py +67 -19
  113. package/skills/github-repo-monitor/tests/test_main.py +67 -8
  114. package/skills/index.js +34 -8
  115. package/skills/openhands-api/README.md +5 -1
  116. package/skills/openhands-api/SKILL.md +74 -5
  117. package/skills/openhands-automation/SKILL.md +3 -1
  118. package/skills/openhands-automation/references/custom-automation.md +166 -0
  119. package/skills/openhands-sdk/SKILL.md +8 -3
  120. package/skills/slack-channel-monitor/README.md +3 -3
  121. package/skills/slack-channel-monitor/SKILL.md +3 -2
  122. package/skills/slack-channel-monitor/references/state-schema.md +11 -4
  123. package/skills/slack-channel-monitor/scripts/main.py +111 -41
  124. package/tests/test_catalog_schema.py +47 -0
  125. package/tests/test_catalogs.py +47 -3
  126. package/tests/test_integration_catalog_in_sync.py +252 -0
  127. package/tests/test_slack_channel_monitor.py +142 -0
  128. package/tests/test_version_alignment.py +64 -0
  129. package/integrations/logos.d.ts +0 -5
  130. package/integrations/logos.js +0 -94
  131. package/integrations/oauth-provider-catalog.js +0 -553
  132. package/integrations/oauth-provider-registration-defaults.js +0 -610
  133. /package/plugins/cobol-modernization/skills/{mainfraime-removal → mainframe-removal}/SKILL.md +0 -0
  134. /package/plugins/cobol-modernization/skills/{mainfraime-removal → mainframe-removal}/references/cics-transformation-examples.md +0 -0
  135. /package/plugins/migration-scoring/skills/{migration-scoring-overview → migration-scoring}/SKILL.md +0 -0
@@ -0,0 +1,5 @@
1
+ # agent-canvas-environment
2
+
3
+ Guidance for working inside a local Agent Canvas environment, including local agent-server auth, safe workspace hygiene, and delegation to new local conversations.
4
+
5
+ See: [SKILL.md](./SKILL.md)
@@ -0,0 +1,202 @@
1
+ ---
2
+ name: agent-canvas-environment
3
+ description: Work effectively inside a local Agent Canvas environment, including local agent-server auth, frontend/backend port discovery, safe workspace hygiene, and delegating work to a new local conversation through POST /api/conversations.
4
+ triggers:
5
+ - agent canvas
6
+ - agent-canvas
7
+ - local conversation
8
+ - delegate local conversation
9
+ - session api key
10
+ - X-Session-API-Key
11
+ - localhost:8001
12
+ ---
13
+
14
+ # Agent Canvas Environment
15
+
16
+ Use this skill when running inside or alongside a local Agent Canvas stack, especially when the user asks to inspect the local backend, create or monitor local conversations, or delegate work to another local conversation.
17
+
18
+ ## Core rules
19
+
20
+ - Treat the local Agent Canvas backend as an agent-server API, usually `http://localhost:8001`.
21
+ - Treat the local UI as a separate frontend, usually `http://localhost:8000`.
22
+ - Do not print session API keys. Pass them directly in `X-Session-API-Key`.
23
+ - Trust any runtime-services block or explicit user-provided host over default ports.
24
+ - Before mutating a repository, check `git status -sb`. If a worktree has unrelated changes, use a separate worktree or clone.
25
+ - When delegating, write a self-contained prompt. The new conversation does not inherit the current chat context.
26
+
27
+ ## Find the session key
28
+
29
+ Use the first available value, without echoing it:
30
+
31
+ ```bash
32
+ KEY="${SESSION_API_KEY:-${OH_SESSION_API_KEYS_0:-${LOCAL_BACKEND_API_KEY:-}}}"
33
+ if [ -z "$KEY" ] && [ -f "$HOME/.openhands/agent-canvas/api-key.txt" ]; then
34
+ KEY="$(tr -d '\n' < "$HOME/.openhands/agent-canvas/api-key.txt")"
35
+ fi
36
+ test -n "$KEY" || { echo "No Agent Canvas session API key found" >&2; exit 1; }
37
+ ```
38
+
39
+ Validate backend access:
40
+
41
+ ```bash
42
+ curl -sS -o /tmp/agent-canvas-conversations.json -w '%{http_code}\n' \
43
+ -H "X-Session-API-Key: $KEY" \
44
+ http://localhost:8001/api/conversations/search
45
+ ```
46
+
47
+ HTTP `200` means the backend and key work.
48
+
49
+ ## Delegate to a local conversation
50
+
51
+ Use `POST /api/conversations` with:
52
+
53
+ - the **encrypted** `agent_settings` from `GET /api/settings` (with `X-Expose-Secrets: encrypted`), which carries the real Fernet-encrypted `llm.api_key`, the existing `agent_context`, and the agent kind — so you never handle plaintext credentials and you don't drop the caller's skill/context config
54
+ - `secrets_encrypted: true` so the agent-server decrypts that `api_key` server-side
55
+ - the exec tool set merged into `agent_settings.tools` (and `task_tool_set` when you enable sub-agents)
56
+ - `tool_module_qualnames` for any non-SDK tools (e.g. `canvas_ui`)
57
+ - `agent_context.load_public_skills`/`load_user_skills`/`load_project_skills` set to `true` if the delegated agent should inherit bundled/user/project skills
58
+ - a fresh absolute workspace directory
59
+ - `initial_message.run: true`
60
+ - `worktree: false` when the workspace is already isolated
61
+
62
+ ### Credential handling — important
63
+
64
+ `GET /api/settings` (default) **masks** every credential — `llm.api_key` comes back as the literal string `"**********"`. If you forward that verbatim, the new conversation authenticates with the placeholder and fails immediately with `LLMAuthenticationError` (`You must provide an API key`).
65
+
66
+ The supported way to obtain forwardable credentials is the **`X-Expose-Secrets: encrypted`** request header. With it, `/api/settings` returns the real `llm.api_key` as a **Fernet-encrypted token** (starts with `gAAAAA`) intended to be sent back to the server with `secrets_encrypted: true`; the agent-server's `decrypt_incoming_llm_secrets` decrypts it server-side. Do **not** read `~/.openhands/profiles/*.json` directly — that is brittle (the caller may not share the backend's home directory, `active_profile` may be null, the profile store may live elsewhere).
67
+
68
+ Two working approaches:
69
+
70
+ 1. **`agent_profile_id` (simplest, but no tools)** — send only `agent_profile_id: "<uuid>"` (from `GET /api/agent-profiles` → the profile whose `id` equals `active_agent_profile_id` from `/api/settings`). The server resolves the LLM key + agent kind from the profile. Mutually exclusive with `agent`/`agent_settings`, and the `openhands` agent-profile schema forbids `tools`/`include_default_tools`, so the conversation gets **zero exec tools** this way. Use only when the task needs no tools.
71
+
72
+ 2. **Encrypted `agent_settings` (full tools, preserves context)** — start from the encrypted `/api/settings` `agent_settings` payload, drop `schema_version` and `mcp_config` (to avoid MCP-connection failures at creation time), merge in the exec tool set and `load_*_skills` flags, and send with `secrets_encrypted: true`. This is the pattern for real delegated work.
73
+
74
+ Template (full tools, preserves context):
75
+
76
+ ```bash
77
+ set -euo pipefail
78
+
79
+ BASE="${AGENT_CANVAS_BACKEND:-http://localhost:8001}"
80
+ KEY="${SESSION_API_KEY:-${OH_SESSION_API_KEYS_0:-${LOCAL_BACKEND_API_KEY:-}}}"
81
+ if [ -z "$KEY" ] && [ -f "$HOME/.openhands/agent-canvas/api-key.txt" ]; then
82
+ KEY="$(tr -d '\n' < "$HOME/.openhands/agent-canvas/api-key.txt")"
83
+ fi
84
+ test -n "$KEY" || { echo "No Agent Canvas session API key found" >&2; exit 1; }
85
+
86
+ WORKDIR="${WORKDIR:-$HOME/workspace/delegated/$(date +%Y%m%d-%H%M%S)}"
87
+ mkdir -p "$WORKDIR"
88
+
89
+ # Fetch the agent_settings with ENCRYPTED secrets exposed. This returns the
90
+ # real llm.api_key as a Fernet token (gAAAAA...) plus the existing
91
+ # agent_context/agent kind, so we preserve the caller's config and never
92
+ # handle plaintext credentials.
93
+ SETTINGS_JSON="$(curl -sS -H "X-Session-API-Key: $KEY" -H "X-Expose-Secrets: encrypted" "$BASE/api/settings")"
94
+
95
+ PROMPT='Write a complete, task-specific prompt here. Include repo, branch, constraints, validation, and expected report.'
96
+
97
+ PAYLOAD="$(jq -n --argjson settings "$SETTINGS_JSON" --arg prompt "$PROMPT" --arg workdir "$WORKDIR" '
98
+ # Start from the encrypted agent_settings so llm.api_key (Fernet token),
99
+ # agent_kind, and agent_context are preserved. Drop schema_version and
100
+ # mcp_config (MCP servers can fail to connect at creation time; the profile
101
+ # can be re-resolved later if needed).
102
+ def base_agent_settings:
103
+ ($settings.agent_settings // {})
104
+ | del(.schema_version)
105
+ | del(.mcp_config);
106
+
107
+ # Merge the exec tool set into the existing tools list. Include task_tool_set
108
+ # when sub-agents are enabled — enable_sub_agents alone does not expose the
109
+ # delegation tool; Agent Canvas adds task_tool_set for that.
110
+ def with_tools:
111
+ .tools = ((.tools // []) + [
112
+ {name: "terminal", params: {}},
113
+ {name: "file_editor", params: {}},
114
+ {name: "task_tracker", params: {}},
115
+ {name: "browser_tool_set", params: {}},
116
+ {name: "canvas_ui", params: {}}
117
+ ] + (if .enable_sub_agents then [{name: "task_tool_set", params: {}}] else [] end)
118
+ | unique_by(.name));
119
+
120
+ # Preserve the existing agent_context and enable skill loading for the
121
+ # delegated agent (defaults are false, so set these explicitly).
122
+ def with_skill_loading:
123
+ .agent_context = ((.agent_context // {}) + {
124
+ load_public_skills: true,
125
+ load_user_skills: true,
126
+ load_project_skills: true
127
+ });
128
+
129
+ ($settings.conversation_settings // {}) as $conv |
130
+ {
131
+ secrets_encrypted: true,
132
+ agent_settings: (base_agent_settings | with_tools | with_skill_loading),
133
+ tool_module_qualnames: { canvas_ui: "canvas_ui_tool" },
134
+ workspace: {kind: "LocalWorkspace", working_dir: $workdir},
135
+ confirmation_policy: {kind: "NeverConfirm"},
136
+ # Delegated tasks usually need more than the SDK default of 80 iterations;
137
+ # default to the caller's conversation_settings value (1000 in Agent Canvas)
138
+ # so long-running tasks aren't cut off prematurely. Override per-task if needed.
139
+ max_iterations: (($conv.max_iterations // 1000) | if . == null then 1000 else . end),
140
+ stuck_detection: true,
141
+ autotitle: true,
142
+ worktree: false,
143
+ initial_message: {
144
+ role: "user",
145
+ content: [{type: "text", text: $prompt}],
146
+ run: true
147
+ }
148
+ }
149
+ ')"
150
+
151
+ curl -sS -X POST "$BASE/api/conversations" \
152
+ -H "Content-Type: application/json" \
153
+ -H "X-Session-API-Key: $KEY" \
154
+ --data-binary "$PAYLOAD" | jq '{id, title, execution_status, workspace}'
155
+ ```
156
+
157
+ Verify the new conversation actually has tools and is running (not errored):
158
+
159
+ ```bash
160
+ CID="<conversation_id>"
161
+ curl -sS -H "X-Session-API-Key: $KEY" "$BASE/api/conversations/$CID" \
162
+ | jq '{execution_status, tools: [.agent.tools[]?.name]}'
163
+ curl -sS -H "X-Session-API-Key: $KEY" "$BASE/api/conversations/$CID/events/search?limit=20" \
164
+ | jq '[.events[]? | select(.kind=="ConversationErrorEvent") | .code] // []'
165
+ ```
166
+
167
+ `execution_status` should be `running`/`idle`/`finished` (not `error`), `tools` should list the exec tools, and there should be no `ConversationErrorEvent`.
168
+
169
+ If MCP servers configured in the profile are unreachable, conversation creation can fail with `MCP Connection Failure`; the template drops `mcp_config` from the forwarded `agent_settings` to avoid that.
170
+
171
+ Report both links:
172
+
173
+ - UI: `http://localhost:8000/conversations/<conversation_id>`
174
+ - API: `http://localhost:8001/api/conversations/<conversation_id>`
175
+
176
+ ## Monitor a delegated conversation
177
+
178
+ ```bash
179
+ CID="<conversation_id>"
180
+ curl -sS -H "X-Session-API-Key: $KEY" "$BASE/api/conversations/$CID" \
181
+ | jq '{id, title, execution_status, updated_at, workspace, agent_kind: .agent.kind, current_model_id, current_model_name}'
182
+
183
+ curl -sS -H "X-Session-API-Key: $KEY" "$BASE/api/conversations/$CID/events/search?limit=20" \
184
+ | jq '.events // .items // .'
185
+ ```
186
+
187
+ Terminal statuses commonly include `idle`, `running`, `finished`, `error`, `stuck`, and `stopped`.
188
+
189
+ ## Prompt checklist for delegation
190
+
191
+ Include:
192
+
193
+ - repository owner/name and local path if relevant
194
+ - branch, PR, issue, or Linear ticket identifiers
195
+ - current status and known blockers
196
+ - exact files or subsystems in scope
197
+ - dirty-worktree warnings and paths not to touch
198
+ - whether to push, open a PR, or only report
199
+ - checks/tests to run
200
+ - expected final report format
201
+
202
+ Do not rely on the new conversation knowing anything from the current thread.
@@ -1,6 +1,7 @@
1
1
  # Bitbucket
2
2
 
3
- Interact with Bitbucket repositories and pull requests using the BITBUCKET_TOKEN environment variable. Use when working with code hosted on Bitbucket or managing Bitbucket resources via API.
3
+ Bitbucket integration **hub** skill. It detects whether the repository is on Bitbucket
4
+ Cloud or Bitbucket Data Center and directs the agent to the matching detailed skill.
4
5
 
5
6
  ## Triggers
6
7
 
@@ -9,42 +10,24 @@ This skill is activated by the following keywords:
9
10
  - `bitbucket`
10
11
  - `git`
11
12
 
12
- ## Details
13
-
14
- You have access to an environment variable, `BITBUCKET_TOKEN`, which allows you to interact with
15
- the Bitbucket API.
16
-
17
- <IMPORTANT>
18
- You can use `curl` with the `BITBUCKET_TOKEN` to interact with Bitbucket's API.
19
- ALWAYS use the Bitbucket API for operations instead of a web browser.
20
- ALWAYS use the `create_bitbucket_pr` tool to open a pull request
21
- </IMPORTANT>
22
-
23
- Only rewrite the Bitbucket remote if a push actually fails with authentication errors and the user has asked you to push. Do not proactively rewrite `origin`. OpenHands commonly stores `BITBUCKET_TOKEN` in the same unencoded `user:token` form used by commands such as `curl --user "$BITBUCKET_TOKEN" ...`, so keep it in that form unless you truly need to embed it in a Git remote URL.
24
-
25
- If you need a non-interactive HTTPS remote URL, split `BITBUCKET_TOKEN` on the first `:` and URL-encode each part before calling `git remote set-url`. This avoids breaking usernames or emails that contain reserved URL characters such as `@`:
26
-
27
- ```bash
28
- BB_USER="${BITBUCKET_TOKEN%%:*}" && \
29
- BB_PASS="${BITBUCKET_TOKEN#*:}" && \
30
- ENCODED_USER=$(python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' "$BB_USER") && \
31
- ENCODED_PASS=$(python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' "$BB_PASS") && \
32
- git remote set-url origin "https://${ENCODED_USER}:${ENCODED_PASS}@bitbucket.org/username/repo.git"
33
- ```
34
-
35
- Atlassian's Bitbucket Cloud docs recommend avoiding long-lived credentials in the remote URL when possible. Their API token examples use either `https://{bitbucket_username}:{api_token}@...` or `https://x-bitbucket-api-token-auth:{api_token}@...`; OpenHands users should only construct those URLs on demand, with proper URL encoding.
36
-
37
- Here are some instructions for pushing, but ONLY do this if the user asks you to:
38
- * NEVER push directly to the `main` or `master` branch
39
- * Git config (username and email) is pre-set. Do not modify.
40
- * You may already be on a branch starting with `openhands-workspace`. Create a new branch with a better name before pushing.
41
- * Use the `create_bitbucket_pr` tool to create a pull request, if you haven't already
42
- * Once you've created your own branch or a pull request, continue to update it. Do NOT create a new one unless you are explicitly asked to. Update the PR title and description as necessary, but don't change the branch name.
43
- * Use the main branch as the base branch, unless the user requests otherwise
44
- * After opening or updating a pull request, send the user a short message with a link to the pull request.
45
- * Do NOT mark a pull request as ready to review unless the user explicitly says so
46
- * Do all of the above in as few steps as possible. E.g. you could push changes with one step by running the following bash commands:
47
- ```bash
48
- git remote -v && git branch # to find the current org, repo and branch
49
- git checkout -b create-widget && git add . && git commit -m "Create widget" && git push -u origin create-widget
50
- ```
13
+ ## Why a hub skill?
14
+
15
+ Bitbucket ships as two products that behave differently — **Bitbucket Cloud**
16
+ (`bitbucket.org`) and **Bitbucket Data Center** (self-hosted Bitbucket Server). They use
17
+ different token environment variables, REST APIs, repository identifiers, git remote URL
18
+ formats, and pull request tools.
19
+
20
+ This hub triggers broadly (on `git`/`bitbucket`) so it loads for any Bitbucket task — even
21
+ when the words "data center" never appear. It then:
22
+
23
+ 1. **Detects** the environment by checking which token variable is present
24
+ (`BITBUCKET_DATA_CENTER_TOKEN` → Data Center, else `BITBUCKET_TOKEN` → Cloud). The check
25
+ is case-insensitive so it is robust to env-var casing differences.
26
+ 2. **Hands off** to the matching detailed skill via the `invoke_skill` tool:
27
+ - Bitbucket Cloud → [`bitbucket-cloud`](../bitbucket-cloud/)
28
+ - Bitbucket Data Center → [`bitbucket-data-center`](../bitbucket-data-center/)
29
+
30
+ The hub also carries a small quick-reference table as a fallback in case the detailed skill
31
+ cannot be loaded.
32
+
33
+ See [`SKILL.md`](SKILL.md) for the full content.
@@ -1,45 +1,57 @@
1
1
  ---
2
2
  name: bitbucket
3
- description: Interact with Bitbucket repositories and pull requests using the BITBUCKET_TOKEN environment variable. Use when working with code hosted on Bitbucket or managing Bitbucket resources via API.
3
+ description: Bitbucket integration hub. Detects whether the repository is on Bitbucket Cloud or Bitbucket Data Center and directs you to the matching detailed skill (bitbucket-cloud or bitbucket-data-center). Use for any Bitbucket repository or pull request task.
4
4
  triggers:
5
5
  - bitbucket
6
6
  - git
7
7
  ---
8
8
 
9
- You have access to an environment variable, `BITBUCKET_TOKEN`, which allows you to interact with
10
- the Bitbucket API.
9
+ You are working with **Bitbucket**, which ships as two distinct products that behave
10
+ differently:
11
11
 
12
- <IMPORTANT>
13
- You can use `curl` with the `BITBUCKET_TOKEN` to interact with Bitbucket's API.
14
- ALWAYS use the Bitbucket API for operations instead of a web browser.
15
- ALWAYS use the `create_bitbucket_pr` tool to open a pull request
16
- </IMPORTANT>
12
+ - **Bitbucket Cloud** (`bitbucket.org`) — authenticates with the `BITBUCKET_TOKEN`
13
+ environment variable.
14
+ - **Bitbucket Data Center** (self-hosted Bitbucket Server) — authenticates with the
15
+ `BITBUCKET_DATA_CENTER_TOKEN` environment variable.
17
16
 
18
- Only rewrite the Bitbucket remote if a push actually fails with authentication errors and the user has asked you to push. Do not proactively rewrite `origin`. OpenHands OSS commonly stores `BITBUCKET_TOKEN` in the same unencoded `user:token` form used by commands such as `curl --user "$BITBUCKET_TOKEN" ...`, so keep it in that form unless you truly need to embed it in a Git remote URL.
17
+ They use different REST APIs, repository identifiers, git remote URL formats, and pull
18
+ request tools, so you must first determine which one you are on, then load the matching
19
+ detailed skill for full instructions.
19
20
 
20
- If you need a non-interactive HTTPS remote URL, split `BITBUCKET_TOKEN` on the first `:` and URL-encode each part before calling `git remote set-url`. This avoids breaking usernames or emails that contain reserved URL characters such as `@`:
21
+ ## Step 1 — Detect which Bitbucket you are on
22
+
23
+ Check which token environment variable is present. Environment variable names are
24
+ case-sensitive, so look for it case-insensitively:
21
25
 
22
26
  ```bash
23
- BB_USER="${BITBUCKET_TOKEN%%:*}" && \
24
- BB_PASS="${BITBUCKET_TOKEN#*:}" && \
25
- ENCODED_USER=$(python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' "$BB_USER") && \
26
- ENCODED_PASS=$(python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' "$BB_PASS") && \
27
- git remote set-url origin "https://${ENCODED_USER}:${ENCODED_PASS}@bitbucket.org/username/repo.git"
27
+ env | grep -i 'bitbucket' || echo "no bitbucket token found"
28
28
  ```
29
29
 
30
- Atlassian's Bitbucket Cloud docs recommend avoiding long-lived credentials in the remote URL when possible. Their API token examples use either `https://{bitbucket_username}:{api_token}@...` or `https://x-bitbucket-api-token-auth:{api_token}@...`; OpenHands users should only construct those URLs on demand, with proper URL encoding.
31
-
32
- Here are some instructions for pushing, but ONLY do this if the user asks you to:
33
- * NEVER push directly to the `main` or `master` branch
34
- * Git config (username and email) is pre-set. Do not modify.
35
- * You may already be on a branch starting with `openhands-workspace`. Create a new branch with a better name before pushing.
36
- * Use the `create_bitbucket_pr` tool to create a pull request, if you haven't already
37
- * Once you've created your own branch or a pull request, continue to update it. Do NOT create a new one unless you are explicitly asked to. Update the PR title and description as necessary, but don't change the branch name.
38
- * Use the main branch as the base branch, unless the user requests otherwise
39
- * After opening or updating a pull request, send the user a short message with a link to the pull request.
40
- * Do NOT mark a pull request as ready to review unless the user explicitly says so
41
- * Do all of the above in as few steps as possible. E.g. you could push changes with one step by running the following bash commands:
42
- ```bash
43
- git remote -v && git branch # to find the current org, repo and branch
44
- git checkout -b create-widget && git add . && git commit -m "Create widget" && git push -u origin create-widget
45
- ```
30
+ - If a **`BITBUCKET_DATA_CENTER_TOKEN`** variable is set (in any letter case) → you are on
31
+ **Bitbucket Data Center**.
32
+ - Otherwise, if a **`BITBUCKET_TOKEN`** variable is set → you are on **Bitbucket Cloud**.
33
+ - If neither is set, ask the user how they authenticate to Bitbucket before proceeding.
34
+
35
+ When you reference the token later, use the exact variable name (and letter case) that
36
+ actually exists in the environment.
37
+
38
+ ## Step 2 — Load the detailed skill
39
+
40
+ Once you know the environment, use the `invoke_skill` tool to load the matching skill for
41
+ full instructions on API calls, authenticated git remotes, and opening pull requests:
42
+
43
+ - Bitbucket Cloud → invoke the **`bitbucket-cloud`** skill.
44
+ - Bitbucket Data Center → invoke the **`bitbucket-data-center`** skill.
45
+
46
+ ## Quick reference (fallback)
47
+
48
+ If you are unable to load the detailed skill, these are the essentials. Always use the
49
+ Bitbucket API (not a web browser) and always use the listed PR tool to open a pull request.
50
+
51
+ | | Bitbucket Cloud | Bitbucket Data Center |
52
+ |---|---|---|
53
+ | Token env var | `BITBUCKET_TOKEN` | `BITBUCKET_DATA_CENTER_TOKEN` |
54
+ | Host | `bitbucket.org` | self-hosted domain |
55
+ | REST API base | `https://api.bitbucket.org/2.0` | `https://<host>/rest/api/1.0` |
56
+ | Repository identifier | `workspace/repo_slug` | `PROJECT/repo_slug` (project key) |
57
+ | Pull request tool | `create_bitbucket_pr` | `create_bitbucket_data_center_pr` |
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "bitbucket-cloud",
3
+ "version": "1.0.0",
4
+ "description": "Bitbucket Cloud (bitbucket.org) specifics — authenticate with BITBUCKET_TOKEN, use the REST API v2, workspace/repo_slug repositories, and the create_bitbucket_pr tool. Loaded on demand by the bitbucket skill once a Cloud environment is detected.",
5
+ "author": {
6
+ "name": "OpenHands",
7
+ "email": "contact@all-hands.dev"
8
+ },
9
+ "homepage": "https://github.com/OpenHands/extensions",
10
+ "repository": "https://github.com/OpenHands/extensions",
11
+ "license": "MIT",
12
+ "keywords": [
13
+ "bitbucket",
14
+ "bitbucket-cloud",
15
+ "git",
16
+ "pull-request"
17
+ ]
18
+ }
@@ -0,0 +1,15 @@
1
+ # Bitbucket Cloud
2
+
3
+ Bitbucket Cloud (`bitbucket.org`) specifics — `BITBUCKET_TOKEN` auth, REST API v2,
4
+ `workspace/repo_slug` repositories, and the `create_bitbucket_pr` tool.
5
+
6
+ ## Triggers
7
+
8
+ This skill has no auto-injection triggers. It is **invoke-only**: it is loaded on demand
9
+ via the `invoke_skill` tool, normally by the [`bitbucket`](../bitbucket/) hub skill after
10
+ it detects a Bitbucket Cloud environment (i.e. `BITBUCKET_TOKEN` is set).
11
+
12
+ ## Details
13
+
14
+ See [`SKILL.md`](SKILL.md) for the full content, including authenticated git remote
15
+ construction and pull request instructions.
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: bitbucket-cloud
3
+ description: Bitbucket Cloud (bitbucket.org) specifics — authenticate with BITBUCKET_TOKEN, use the REST API v2, workspace/repo_slug repositories, and the create_bitbucket_pr tool. Loaded on demand by the bitbucket skill once a Cloud environment is detected.
4
+ ---
5
+
6
+ You are working with **Bitbucket Cloud** (`bitbucket.org`). You have access to an
7
+ environment variable, `BITBUCKET_TOKEN`, which allows you to interact with the Bitbucket
8
+ Cloud API.
9
+
10
+ - REST API base URL: `https://api.bitbucket.org/2.0`
11
+ - Repository identifier format: `workspace/repo_slug`
12
+
13
+ <IMPORTANT>
14
+ You can use `curl` with the `BITBUCKET_TOKEN` to interact with Bitbucket's API.
15
+ ALWAYS use the Bitbucket API for operations instead of a web browser.
16
+ ALWAYS use the `create_bitbucket_pr` tool to open a pull request
17
+ </IMPORTANT>
18
+
19
+ Only rewrite the Bitbucket remote if a push actually fails with authentication errors and the user has asked you to push. Do not proactively rewrite `origin`. OpenHands OSS commonly stores `BITBUCKET_TOKEN` in the same unencoded `user:token` form used by commands such as `curl --user "$BITBUCKET_TOKEN" ...`, so keep it in that form unless you truly need to embed it in a Git remote URL.
20
+
21
+ If you need a non-interactive HTTPS remote URL, split `BITBUCKET_TOKEN` on the first `:` and URL-encode each part before calling `git remote set-url`. This avoids breaking usernames or emails that contain reserved URL characters such as `@`:
22
+
23
+ ```bash
24
+ BB_USER="${BITBUCKET_TOKEN%%:*}" && \
25
+ BB_PASS="${BITBUCKET_TOKEN#*:}" && \
26
+ ENCODED_USER=$(python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' "$BB_USER") && \
27
+ ENCODED_PASS=$(python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' "$BB_PASS") && \
28
+ git remote set-url origin "https://${ENCODED_USER}:${ENCODED_PASS}@bitbucket.org/username/repo.git"
29
+ ```
30
+
31
+ Atlassian's Bitbucket Cloud docs recommend avoiding long-lived credentials in the remote URL when possible. Their API token examples use either `https://{bitbucket_username}:{api_token}@...` or `https://x-bitbucket-api-token-auth:{api_token}@...`; OpenHands users should only construct those URLs on demand, with proper URL encoding.
32
+
33
+ Here are some instructions for pushing, but ONLY do this if the user asks you to:
34
+ * NEVER push directly to the `main` or `master` branch
35
+ * Git config (username and email) is pre-set. Do not modify.
36
+ * You may already be on a branch starting with `openhands-workspace`. Create a new branch with a better name before pushing.
37
+ * Use the `create_bitbucket_pr` tool to create a pull request, if you haven't already
38
+ * Once you've created your own branch or a pull request, continue to update it. Do NOT create a new one unless you are explicitly asked to. Update the PR title and description as necessary, but don't change the branch name.
39
+ * Use the main branch as the base branch, unless the user requests otherwise
40
+ * After opening or updating a pull request, send the user a short message with a link to the pull request.
41
+ * Do NOT mark a pull request as ready to review unless the user explicitly says so
42
+ * Do all of the above in as few steps as possible. E.g. you could push changes with one step by running the following bash commands:
43
+ ```bash
44
+ git remote -v && git branch # to find the current org, repo and branch
45
+ git checkout -b create-widget && git add . && git commit -m "Create widget" && git push -u origin create-widget
46
+ ```
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "bitbucket-data-center",
3
+ "version": "1.0.0",
4
+ "description": "Bitbucket Data Center (self-hosted Bitbucket Server) specifics — authenticate with BITBUCKET_DATA_CENTER_TOKEN, use the REST API 1.0, PROJECT/repo_slug repositories, scm/ git remotes, and the create_bitbucket_data_center_pr tool. Loaded on demand by the bitbucket skill once a Data Center environment is detected.",
5
+ "author": {
6
+ "name": "OpenHands",
7
+ "email": "contact@all-hands.dev"
8
+ },
9
+ "homepage": "https://github.com/OpenHands/extensions",
10
+ "repository": "https://github.com/OpenHands/extensions",
11
+ "license": "MIT",
12
+ "keywords": [
13
+ "bitbucket",
14
+ "bitbucket-data-center",
15
+ "bitbucket-server",
16
+ "git",
17
+ "pull-request"
18
+ ]
19
+ }
@@ -0,0 +1,20 @@
1
+ # Bitbucket Data Center
2
+
3
+ Bitbucket Data Center (self-hosted Bitbucket Server) specifics — `BITBUCKET_DATA_CENTER_TOKEN`
4
+ auth, REST API 1.0, `PROJECT/repo_slug` repositories, `scm/` git remotes, and the
5
+ `create_bitbucket_data_center_pr` tool.
6
+
7
+ ## Triggers
8
+
9
+ This skill has no auto-injection triggers. It is **invoke-only**: it is loaded on demand
10
+ via the `invoke_skill` tool, normally by the [`bitbucket`](../bitbucket/) hub skill after
11
+ it detects a Bitbucket Data Center environment (i.e. `BITBUCKET_DATA_CENTER_TOKEN` is set).
12
+
13
+ ## Details
14
+
15
+ See [`SKILL.md`](SKILL.md) for the full content, including authenticated `scm/` git remote
16
+ construction and pull request instructions. Note the key differences from Bitbucket Cloud:
17
+ the REST API is version `1.0` under `https://{domain}/rest/api/1.0`, repositories are
18
+ addressed as `PROJECT/repo_slug` (project key), git remotes use the
19
+ `scm/{project}/{repo}.git` path, and pull requests are opened with
20
+ `create_bitbucket_data_center_pr`.
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: bitbucket-data-center
3
+ description: Bitbucket Data Center (self-hosted Bitbucket Server) specifics — authenticate with BITBUCKET_DATA_CENTER_TOKEN, use the REST API 1.0, PROJECT/repo_slug repositories, scm/ git remotes, and the create_bitbucket_data_center_pr tool. Loaded on demand by the bitbucket skill once a Data Center environment is detected.
4
+ ---
5
+
6
+ You are working with **Bitbucket Data Center** (self-hosted Bitbucket Server). You have
7
+ access to an environment variable, `BITBUCKET_DATA_CENTER_TOKEN`, which contains a basic
8
+ auth token in the format `username:your-token` that allows you to interact with the git
9
+ repository and the REST API.
10
+
11
+ > Environment variable names are case-sensitive. If `BITBUCKET_DATA_CENTER_TOKEN` is not
12
+ > present, use whichever case variant actually exists (for example
13
+ > `bitbucket_data_center_token`). Run `env | grep -i 'bitbucket_data_center'` to find it.
14
+
15
+ - REST API base URL: `https://{domain}/rest/api/1.0`
16
+ - Repository identifier format: `PROJECT/repo_slug` (project key, slash, repo slug)
17
+
18
+ You can use this token to interact with the Bitbucket Data Center REST API:
19
+ ```bash
20
+ curl -u "${BITBUCKET_DATA_CENTER_TOKEN}" https://{domain}/rest/api/1.0/...
21
+ ```
22
+
23
+ <IMPORTANT>
24
+ ALWAYS use the Bitbucket Data Center API for operations instead of a web browser.
25
+ ALWAYS use the `create_bitbucket_data_center_pr` tool to open a pull request
26
+ </IMPORTANT>
27
+
28
+ If you encounter authentication issues when pushing to Bitbucket Data Center (such as password prompts or permission errors), the old token may have expired. In such case, update the remote URL to include the current token: `git remote set-url origin https://${BITBUCKET_DATA_CENTER_TOKEN}@{domain}/scm/{project_lower}/{repo}.git`
29
+
30
+ The token is a `username:token` pair, so if the username or token contains characters that are reserved in URLs (such as `@`), split on the first `:` and URL-encode each part before embedding it in a remote:
31
+
32
+ ```bash
33
+ BB_USER="${BITBUCKET_DATA_CENTER_TOKEN%%:*}" && \
34
+ BB_PASS="${BITBUCKET_DATA_CENTER_TOKEN#*:}" && \
35
+ ENCODED_USER=$(python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' "$BB_USER") && \
36
+ ENCODED_PASS=$(python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' "$BB_PASS") && \
37
+ git remote set-url origin "https://${ENCODED_USER}:${ENCODED_PASS}@{domain}/scm/{project_lower}/{repo}.git"
38
+ ```
39
+
40
+ Here are some instructions for pushing, but ONLY do this if the user asks you to:
41
+ * NEVER push directly to the `main` or `master` branch
42
+ * Git config (username and email) is pre-set. Do not modify.
43
+ * You may already be on a branch starting with `openhands-workspace`. Create a new branch with a better name before pushing.
44
+ * Use the `create_bitbucket_data_center_pr` tool to create a pull request, if you haven't already
45
+ * Once you've created your own branch or a pull request, continue to update it. Do NOT create a new one unless you are explicitly asked to. Update the PR title and description as necessary, but don't change the branch name.
46
+ * Use the main branch as the base branch, unless the user requests otherwise
47
+ * After opening or updating a pull request, send the user a short message with a link to the pull request.
48
+ * Do NOT mark a pull request as ready to review unless the user explicitly says so
49
+ * Do all of the above in as few steps as possible. E.g. you could push changes with one step by running the following bash commands:
50
+ ```bash
51
+ git remote -v && git branch # to find the current org, repo and branch
52
+ git checkout -b create-widget && git add . && git commit -m "Create widget" && git push -u origin create-widget
53
+ ```
@@ -115,7 +115,7 @@ Require:
115
115
  8. **Dependency Changes**
116
116
  If dependency lock changes have downgraded a dependency, comment pointing that out to make sure it was intentional.
117
117
 
118
- When a PR adds a new dependency or bumps an existing one, review the upstream release for supply chain risk. If any target version was published less than 7 days ago, do **NOT** approve the PR yet — leave a blocking review comment and wait until the version is at least 7 days old. Read `references/supply-chain-security.md` for the full verification checklist including risk-based scrutiny tiers, concrete commands for checking release provenance, and escalation guidance.
118
+ When a PR adds a new dependency or bumps an existing one, review the upstream release for supply chain risk. If any target version was published less than 7 days ago, do **NOT** approve the PR yet — leave a blocking review comment and wait until the version is at least 7 days old. First-party packages maintained by the same organization as the reviewed repository are intentionally excluded from the 7-day waiting rule, but still scrutinize them for supply-chain risk using the checklist. Read `references/supply-chain-security.md` for the full verification checklist including risk-based scrutiny tiers, concrete commands for checking release provenance, and escalation guidance.
119
119
 
120
120
  9. **Risk and Safety Evaluation**
121
121
  Read `references/risk-evaluation.md` for the full risk evaluation framework including risk levels (🟢 Low / 🟡 Medium / 🔴 High), risk factors, escalation guidance, and repo-specific risk rules.
@@ -7,7 +7,7 @@ When a PR adds a new dependency or bumps an existing one, review the upstream re
7
7
  Release recency is the primary risk signal - even widely-used, established packages can be compromised (e.g., LiteLLM was a popular package with high download counts when it was hijacked). Check when the target version was published before choosing a tier.
8
8
 
9
9
  **Apply full scrutiny** (all checks below) when:
10
- - The target version was published less than 7 days ago - regardless of package popularity or age. For PyPI: visit `https://pypi.org/project/<package>/<version>/` and check the "Released" date. For npm: run `npm view <package>@<version> time`. Recent releases have not had time for community vetting, and this is exactly the window supply chain attackers exploit. Do **NOT** approve the PR while the target version is still younger than 7 days; wait until it ages out, then complete the rest of the checklist.
10
+ - The target version was published less than 7 days ago - regardless of package popularity or age, except first-party packages maintained by the same organization as the reviewed repository. First-party packages are intentionally excluded from the 7-day waiting rule: do not block solely on freshness, but still scrutinize them for supply-chain risk using this checklist. For PyPI: visit `https://pypi.org/project/<package>/<version>/` and check the "Released" date. For npm: run `npm view <package>@<version> time`. Recent releases have not had time for community vetting, and this is exactly the window supply chain attackers exploit.
11
11
  - Adding a dependency not previously used in this project
12
12
  - Upgrading a package that was first published less than 6 months ago (check oldest version at `https://pypi.org/project/<package>/#history` or `npm view <package> time | head -3`) or has low weekly downloads (for PyPI: check `https://pypistats.org/packages/<package>` for weekly downloads; for npm: see weekly downloads on the package page at `https://www.npmjs.com/package/<package>`; use <10k on PyPI / <1k on npm as thresholds)
13
13
  - The dependency includes native code, install hooks, or system-level access
@@ -28,4 +28,4 @@ Release recency is the primary risk signal - even widely-used, established packa
28
28
 
29
29
  ## Escalation Guidance
30
30
 
31
- Escalate to 🔴 High Risk if any high-severity signal is present: yanked/retracted versions, source-to-package divergence, or new install-time behavior (post-install scripts, `.pth` files). For medium-severity signals (brand-new release with no adoption signal, missing release notes), escalate only when combined with other signals from this checklist (medium or high severity) or when the package is under full scrutiny. If a dependency is under full scrutiny solely because the target version is newer than 7 days, do **NOT** approve until it is at least 7 days old; after that, re-evaluate it using the rest of this checklist. For dependencies under standard scrutiny, brand-new publication alone is not sufficient to escalate - established packages with frequent release cycles routinely publish new versions.
31
+ Escalate to 🔴 High Risk if any high-severity signal is present: yanked/retracted versions, source-to-package divergence, or new install-time behavior (post-install scripts, `.pth` files). For medium-severity signals (brand-new release with no adoption signal, missing release notes), escalate only when combined with other signals from this checklist (medium or high severity) or when the package is under full scrutiny. If a dependency is under full scrutiny solely because the target version is newer than 7 days, do **NOT** approve until it is at least 7 days old unless it is first-party; after that, re-evaluate it using the rest of this checklist. For first-party packages, do not block solely on freshness, but still document the supply-chain risk review. For dependencies under standard scrutiny, brand-new publication alone is not sufficient to escalate - established packages with frequent release cycles routinely publish new versions.
@@ -1,12 +1,19 @@
1
- # State File Schema
1
+ # State Schema
2
2
 
3
- The automation maintains a JSON state file that persists across polling runs.
3
+ The automation maintains a JSON state document that persists across polling runs.
4
4
  It is the source of truth for which trigger-label events have queued reviews
5
5
  and which conversations are still active.
6
6
 
7
7
  ---
8
8
 
9
- ## File Location
9
+ ## Storage
10
+
11
+ **Primary (cloud):** The state is stored in the automation service's built-in KV
12
+ store under the key `"state"`. The KV store is available when `AUTOMATION_KV_TOKEN`
13
+ is injected into the run environment. Each automation has its own isolated namespace.
14
+
15
+ **Fallback (local/dev):** When the KV store is not available, the state is written
16
+ to a local JSON file at:
10
17
 
11
18
  ```
12
19
  {WORKSPACE_BASE_ROOT}/automation-state/github_pr_reviewer_label_event_{automation_id}.json
@@ -116,8 +123,15 @@ Trigger label applied on GitHub
116
123
  ## Resetting State
117
124
 
118
125
  To force the automation to reconsider previous label events, delete the state
119
- file:
126
+ from the KV store (cloud) or the fallback file (local).
127
+
128
+ **Cloud (KV store):**
129
+ ```bash
130
+ curl -X DELETE "${OPENHANDS_HOST}/api/automation/v1/kv/state" \
131
+ -H "Authorization: Bearer ${AUTOMATION_KV_TOKEN}"
132
+ ```
120
133
 
134
+ **Local (file fallback):**
121
135
  ```bash
122
136
  rm ~/.openhands/workspaces/automation-state/github_pr_reviewer_label_event_<id>.json
123
137
  ```