Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ When editing or adding skills in this repo, follow these rules (and add new skil
- If you change top-level documentation, ensure links still resolve.
- `integrations/catalog/*.json` and `integrations/index.js` are the source of truth consumed by `@openhands/extensions`; agent-canvas and integrations-hub import this package directly, so integration marketplace fixes belong here rather than in app-local constants. When upstream MCP projects move repos, verify both `docsUrl` and the connection option (`transport`, `command`/`args`, or URL), not just links.
- For Python test runs, prefer `uv sync --group test` followed by `uv run pytest -q`; the full suite depends on `openhands-sdk`, which is not available in the base environment.
- Windows gotcha: regenerating `skills/index.js` from a working tree with CRLF-converted skill files can inject literal `\r` sequences into catalog strings. On Windows, generate the catalog from a checkout or temp clone with `core.autocrlf=false`, then copy the clean `skills/index.js` back.

- Agent-driven plugins (for example `plugins/pr-review` and `plugins/release-notes`) use `uv run --with openhands-sdk --with openhands-tools ...` and require an `LLM_API_KEY` in addition to `GITHUB_TOKEN`.
- For OpenHands Cloud API guidance, automations, and CLI integration, use `plugins/openhands`. It is the canonical unified OpenHands plugin covering the V1 Cloud API, Automations API, and CLI. The individual skills (`skills/openhands-api`, `skills/openhands-automation`) are also available standalone.
- When reviewing or editing `skills/openhands-sdk`, validate copy-paste imports against the released packages with `uv run --with openhands-tools --with openhands-workspace --with openhands-agent-server python ...`. In the current released workspace package, the exported remote workspace classes are `APIRemoteWorkspace` / `OpenHandsCloudWorkspace`; `RemoteAPIWorkspace` is not available.
Expand Down
6 changes: 4 additions & 2 deletions scripts/build-skills-catalog.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ export function buildCatalog(skillsDir) {
const skillMd = join(dirPath, "SKILL.md");
if (!existsSync(skillMd)) continue;

const raw = readFileSync(skillMd, "utf-8");
const raw = readFileSync(skillMd, "utf-8")
.replace(/\r\n/g, "\n")
.replace(/\r/g, "\n");
const parts = raw.split("---");
if (parts.length < 3) {
console.warn(`Warning: ${skillMd} missing frontmatter sections, skipping`);
Expand Down Expand Up @@ -89,7 +91,7 @@ const isMain = process.argv[1] && fileURLToPath(import.meta.url) === process.arg
if (isMain) {
const entries = buildCatalog(SKILLS_DIR);

const source = `// Auto-generated by scripts/build-skills-catalog.mjs do not edit.
const source = `// Auto-generated by scripts/build-skills-catalog.mjs - do not edit.
// Source of truth: skills/*/SKILL.md
export const SKILLS_CATALOG = ${JSON.stringify(entries, null, 2)};
export default SKILLS_CATALOG;
Expand Down
122 changes: 60 additions & 62 deletions skills/github-pr-review/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,40 @@ Bundle ALL comments into a **single review API call**. Do not post comments indi

## Posting a Review

Use the GitHub CLI (`gh`). The `GITHUB_TOKEN` is automatically available.

```bash
gh api \
-X POST \
repos/{owner}/{repo}/pulls/{pr_number}/reviews \
-f commit_id='{commit_sha}' \
-f event='COMMENT' \
-f body='Brief 1-3 sentence summary.' \
-f comments[][path]='path/to/file.py' \
-F comments[][line]=42 \
-f comments[][side]='RIGHT' \
-f comments[][body]='🟠 Important: Your comment here.' \
-f comments[][path]='another/file.js' \
-F comments[][line]=15 \
-f comments[][side]='RIGHT' \
-f comments[][body]='🟡 Suggestion: Another comment.'
Use the GitHub CLI (`gh`) with a JSON input file. The `GITHUB_TOKEN` is automatically available.

**Important**: Always use `--input` with a JSON file instead of inline `-F` flags. This avoids shell quoting issues with special characters in comment bodies and works cleanly across Windows, macOS, and Linux.

### Step 1: Create a JSON file

Write the review payload to a JSON file under the system temporary directory (for example `<system-temp>/review.json`). Use the file editor or any shell-appropriate file-writing command. Replace `<system-temp>` with an absolute path for the current OS temp directory.

```json
{
"commit_id": "{commit_sha}",
"event": "COMMENT",
"body": "Brief 1-3 sentence summary.",
"comments": [
{
"path": "path/to/file.py",
"line": 42,
"side": "RIGHT",
"body": "🟠 Important: Your comment here."
},
{
"path": "another/file.js",
"line": 15,
"side": "RIGHT",
"body": "🟡 Suggestion: Another comment."
}
]
}
```

### Step 2: Post the review

```text
gh api -X POST repos/{owner}/{repo}/pulls/{pr_number}/reviews --input <system-temp>/review.json
```

### Parameters
Expand All @@ -54,32 +71,29 @@ gh api \

For comments spanning multiple lines, add `start_line` to specify the range:

```bash
-f comments[][path]='path/to/file.py' \
-F comments[][start_line]=10 \
-F comments[][line]=12 \
-f comments[][side]='RIGHT' \
-f comments[][body]='🟡 Suggestion: Refactor this block:

```suggestion
line_one = "new"
line_two = "code"
line_three = "here"
```'
```json
{
"path": "path/to/file.py",
"start_line": 10,
"line": 12,
"side": "RIGHT",
"body": "🟡 Suggestion: Refactor this block:\n\n```suggestion\nline_one = \"new\"\nline_two = \"code\"\nline_three = \"here\"\n```"
}
```

**Important**: The suggestion must have the same number of lines as the range (e.g., lines 10-12 = 3 lines).
**`start_line`/`line` define the range that will be REPLACED.** The suggestion block may have any number of lines — it does **not** have to match the range size.

## Priority Labels

Start each comment with a priority label:
Start each comment with a priority label. **Minimize nits** — leave minor style issues to linters.

| Label | When to Use |
|-------|-------------|
| 🔴 **Critical** | Must fix: security vulnerabilities, bugs, data loss risks |
| 🟠 **Important** | Should fix: logic errors, performance issues, missing error handling |
| 🟡 **Suggestion** | Nice to have: better naming, code organization |
| 🟢 **Nit** | Optional: formatting, minor style preferences |
| 🟡 **Suggestion** | Worth considering: significant improvements to clarity or maintainability |

**Do NOT post 🟢 Nit or 🟢 Acceptable comments.** If code is fine, simply don't comment on it.

**Example:**
```
Expand Down Expand Up @@ -107,39 +121,23 @@ Avoid for: large refactors, architectural changes, ambiguous improvements.

## Finding Line Numbers

```bash
# From diff header: @@ -old_start,old_count +new_start,new_count @@
# Count from new_start for added/modified lines

grep -n "pattern" filename # Find line number
head -n 42 filename | tail -1 # Verify line content
```
Use the file editor, your code editor's line numbers, or another shell-appropriate search command. Verify the exact lines to be replaced before posting a suggestion; do not rely on POSIX-only `grep`, `sed`, or `head | tail` snippets.

## Fallback: curl

If `gh` is unavailable:

```bash
curl -X POST \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/{owner}/{repo}/pulls/{pr_number}/reviews" \
-d '{
"commit_id": "{commit_sha}",
"event": "COMMENT",
"body": "Review summary.",
"comments": [
{"path": "file.py", "line": 42, "side": "RIGHT", "body": "Comment"},
{"path": "file.py", "start_line": 10, "line": 12, "side": "RIGHT", "body": "Multi-line"}
]
}'
If `gh` is unavailable, use any HTTP client that can POST the saved JSON file. Example:

```text
curl -X POST -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github+json" -H "Content-Type: application/json" https://api.github.com/repos/{owner}/{repo}/pulls/{pr_number}/reviews --data-binary @<system-temp>/review.json
```

## Summary

1. Analyze the code and identify issues
2. Post **ONE** review with all inline comments bundled
3. Use priority labels (🔴🟠🟡🟢) on every comment
4. Use suggestion syntax for concrete code changes
5. Keep the review body brief (details go in inline comments)
6. If no issues: post a short approval message
1. Analyze the code and identify important issues (minimize nits)
2. Write review data to a JSON file under the system temporary directory (for example `<system-temp>/review.json`)
3. Post **ONE** review using `gh api --input <system-temp>/review.json`
4. Use priority labels (🔴🟠🟡) on every comment
5. Do NOT post comments for code that is acceptable — only comment when action is needed
6. Use suggestion syntax for concrete code changes, but verify the resulting code first
7. Keep the review body brief (details go in inline comments)
8. If no issues: post a short approval message with no inline comments
36 changes: 13 additions & 23 deletions skills/github-pr-review/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ Bundle ALL comments into a **single review API call**. Do not post comments indi

Use the GitHub CLI (`gh`) with a JSON input file. The `GITHUB_TOKEN` is automatically available.

**Important**: Always use `--input` with a JSON file instead of `-F` flags. This avoids shell quoting issues with special characters in comment bodies (quotes, backticks, newlines, etc.) and eliminates the need for complex heredoc scripts.
**Important**: Always use `--input` with a JSON file instead of inline `-F` flags. This avoids shell quoting issues with special characters in comment bodies (quotes, backticks, newlines, etc.) and eliminates the need for bash-only heredoc scripts.

### Step 1: Create a JSON file

```bash
cat > /tmp/review.json << 'EOF'
Write the review payload to a JSON file under the system temporary directory (for example `<system-temp>/review.json`). Use the file editor or any shell-appropriate file-writing command. Replace `<system-temp>` with an absolute path for the current OS temp directory.

```json
{
"commit_id": "{commit_sha}",
"event": "COMMENT",
Expand All @@ -42,13 +43,12 @@ cat > /tmp/review.json << 'EOF'
}
]
}
EOF
```

### Step 2: Post the review

```bash
gh api -X POST repos/{owner}/{repo}/pulls/{pr_number}/reviews --input /tmp/review.json
```text
gh api -X POST repos/{owner}/{repo}/pulls/{pr_number}/reviews --input <system-temp>/review.json
```

### Parameters
Expand Down Expand Up @@ -145,7 +145,7 @@ Writing the wrong combination of `start_line`/`line` and suggestion body is what

For every comment that contains a ` ```suggestion ``` ` block, do this check before adding it to the review JSON:

1. Read the actual file lines that will be replaced: `sed -n '<start_line>,<line>p' <path>` (or `sed -n '<line>p' <path>` for a single-line target).
1. Read the actual file lines that will be replaced using the file editor, your code editor, or another shell-appropriate file-view command.
2. Mentally apply the suggestion: drop those lines, splice in the suggestion body, and look at the result in context.
3. Confirm the resulting code matches **exactly** what your prose description promises — no extra duplicated line above/below, no original line accidentally dropped, no off-by-one.
4. If the change cannot be expressed cleanly as a contiguous replacement (e.g., it touches non-adjacent lines, or it depends on edits elsewhere in the file), do **not** use a suggestion block — describe the change in prose instead.
Expand All @@ -154,31 +154,21 @@ If you are not 100% sure the suggestion will produce the exact code you describe

## Finding Line Numbers

```bash
# From diff header: @@ -old_start,old_count +new_start,new_count @@
# Count from new_start for added/modified lines

grep -n "pattern" filename # Find line number
head -n 42 filename | tail -1 # Verify line content
```
Use the file editor, your code editor's line numbers, or another shell-appropriate search command. Verify the exact lines to be replaced before posting a suggestion; do not rely on POSIX-only `grep`, `sed`, or `head | tail` snippets.

## Fallback: curl

If `gh` is unavailable, use curl with the JSON file:
If `gh` is unavailable, use any HTTP client that can POST the saved JSON file. Example:

```bash
curl -X POST \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/{owner}/{repo}/pulls/{pr_number}/reviews" \
-d @/tmp/review.json
```text
curl -X POST -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github+json" -H "Content-Type: application/json" https://api.github.com/repos/{owner}/{repo}/pulls/{pr_number}/reviews --data-binary @<system-temp>/review.json
```

## Summary

1. Analyze the code and identify important issues (minimize nits)
2. Write review data to a JSON file (e.g., `/tmp/review.json`)
3. Post **ONE** review using `gh api --input /tmp/review.json`
2. Write review data to a JSON file under the system temporary directory (for example `<system-temp>/review.json`)
3. Post **ONE** review using `gh api --input <system-temp>/review.json`
4. Use priority labels (🔴🟠🟡) on every comment
5. Do NOT post comments for code that is acceptable — only comment when action is needed
6. Use suggestion syntax for concrete code changes, but only after verifying the resulting code matches your description (see "How Suggestions Actually Work")
Expand Down
8 changes: 8 additions & 0 deletions skills/github-pr-reviewer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ This skill is activated by:
- Uses a real cloned checkout and full PR context instead of only a truncated diff
- Posts acknowledgement and final review comments with AI disclosure
- Configurable review tone and polling schedule
- Uses reusable helper scripts for packaging and automation creation
- Keeps generated build files in the system temporary directory instead of the repository

## Prerequisites

Expand All @@ -35,6 +37,12 @@ Ask OpenHands:
After setup, apply the configured label to a pull request to queue a review. To
request another review later, remove and re-apply the label.

## Helper Scripts

- `scripts/main.py` - automation script template to customize before upload
- `scripts/package_upload.py` - packages and uploads a prepared build directory
- `scripts/create_automation.py` - creates the cron automation from the uploaded tarball

## See Also

- [SKILL.md](SKILL.md) - Full setup workflow reference
Loading
Loading