Claude
Skills
Sign in
Back

github-repo-monitor

Included with Lifetime
$97 forever

This skill should be used when the user asks to "monitor a GitHub repository", "watch GitHub for issues or PRs", "respond to @OpenHands mentions on GitHub", "set up an OpenHands GitHub integration", "trigger OpenHands from a GitHub comment", or "poll a GitHub repo for a trigger phrase". Guides the user through creating a cron automation that polls a single repository and starts an OpenHands conversation whenever a configurable trigger phrase is detected in an issue or PR comment.

Generalscripts

What this skill does


# GitHub Repository Monitor

Create a cron automation that polls a single GitHub repository on a
configurable schedule (default: every minute).

When a comment on an issue or PR contains the **trigger phrase**
(default: `@OpenHands`) it:

1. Posts a GitHub comment acknowledging the request with a conversation link.
2. Creates an OpenHands conversation pre-loaded with the issue/PR title, body,
   labels, and recent comment history for full context.
3. Posts a summary GitHub comment when the conversation finishes.

On every subsequent run:
- New trigger comments on an already-tracked issue/PR are forwarded to the
  running conversation (or re-open a previously closed one).
- When a conversation goes idle/finished/error the agent's final response
  is posted back as a GitHub comment.

> **Local mode only.** This automation targets the local OpenHands setup
> (`dev:automation` stack). A cloud/webhook variant is out of scope here.

---

## Prerequisites

### Required secret

Verify that the following secret is set in **OpenHands Settings → Secrets**
before proceeding:

| Secret name | Token type | Minimum permissions |
|---|---|---|
| `GITHUB_PERSONAL_ACCESS_TOKEN` | Classic PAT | `repo` (private repos) or `public_repo` (public repos) |
| `GITHUB_PERSONAL_ACCESS_TOKEN` | Fine-grained PAT | Issues: Read and Write |

Check with:
```bash
curl -s https://api.github.com/user \
  -H "Authorization: Bearer $GITHUB_PERSONAL_ACCESS_TOKEN" \
  -H "Accept: application/vnd.github+json" \
  | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('login') or d.get('message'))"
```

If the token is missing, inform the user and stop — the automation cannot
function without GitHub credentials.

### Optional secret

| Secret name | Default | Purpose |
|---|---|---|
| `OPENHANDS_URL` | `http://localhost:8000` | Base URL used to build conversation links in GitHub comments |

---

## Setup Workflow

Follow these steps in order.

### Step 1  -  Verify GITHUB_PERSONAL_ACCESS_TOKEN

Fetch the secret and run the `curl` check above.

- If the secret is absent: tell the user
  *"GITHUB_PERSONAL_ACCESS_TOKEN is not set. Please add it in OpenHands Settings → Secrets
  (classic PAT with `repo` or `public_repo` scope, or a fine-grained PAT
  with Issues: Read and Write)."* Then stop.

- If the API returns a non-200 or `{"message": "Bad credentials"}`:
  tell the user the token is invalid and ask them to update it.

### Step 2  -  Collect repository

Ask the user: *"Which GitHub repository should be monitored?
(Format: `owner/repo`, e.g. `microsoft/vscode`)"*

Validate access and write permissions:

```bash
curl -s "https://api.github.com/repos/{owner}/{repo}" \
  -H "Authorization: Bearer $GITHUB_PERSONAL_ACCESS_TOKEN" \
  -H "Accept: application/vnd.github+json" \
  | python3 -c "
import json, sys
d = json.load(sys.stdin)
if 'message' in d:
    print('ERROR:', d['message'])
else:
    perms = d.get('permissions', {})
    print(f\"Accessible. Private: {d.get('private')}. Permissions: {perms}\")
"
```

- If `message: Not Found` or `message: Bad credentials` →
  inform the user and ask them to check the repo name and token.
- If the repo is private and `permissions.push` is `false` →
  inform the user the token does not have write access and comments will fail.
- If the check passes, record `REPO = "{owner}/{repo}"`.

### Step 3  -  Collect trigger phrase

Ask the user: *"What trigger phrase should OpenHands respond to?
(Press Enter to use the default: `@OpenHands`)"*

Accepted values: any non-empty string unlikely to appear by accident.

Record as `TRIGGER_PHRASE`. Default: `"@openhands"`.

### Step 4  -  Collect allowed GitHub logins

Ask the user: *"Which GitHub users may trigger this automation?
Press Enter to allow only the authenticated `GITHUB_PERSONAL_ACCESS_TOKEN` owner.
You may also provide comma-separated GitHub logins, or `*` to allow any
non-bot commenter on the monitored repository."*

Map the answer to `ALLOWED_GITHUB_LOGINS`:

| User answer | `ALLOWED_GITHUB_LOGINS` value |
|---|---|
| Empty/default | `["<TOKEN_OWNER>"]` |
| `enyst,tofarr` | `["enyst", "tofarr"]` |
| `*` | `["*"]` |

Default to token-owner-only unless the user explicitly chooses a broader
allowlist. Record as `ALLOWED_GITHUB_LOGINS`.

### Step 5  -  Collect event types

Ask the user: *"Which event types should be monitored?
Choose one or more:*
  *1. Issue and PR comments (default)*
  *2. PR inline review comments*
  *3. Both*
*(Press Enter to accept the default: issue and PR comments.)"*

Map the choice to the `EVENT_TYPES` list:

| Choice | `EVENT_TYPES` value |
|---|---|
| 1 (default) | `["issue_comment"]` |
| 2 | `["pr_review_comment"]` |
| 3 | `["issue_comment", "pr_review_comment"]` |

### Step 6  -  Collect cron schedule

Ask the user: *"How often should the automation poll GitHub?
(Press Enter for the default: every minute.
Use a cron expression for a different interval, e.g.:
`*/5 * * * *` = every 5 minutes,
`0 * * * *` = every hour)"*

Default: `* * * * *` (every minute).

Record as `CRON_SCHEDULE`.

### Step 7  -  Generate the automation script

Read `scripts/main.py` from this skill's directory. Apply exactly five
constant substitutions near the top of the file:

| Placeholder | Replace with |
|---|---|
| `REPO = "owner/repo"` | `REPO = "{owner_repo}"` |
| `TRIGGER_PHRASE = "@openhands"` | `TRIGGER_PHRASE = "{trigger_phrase_lower}"` |
| `EVENT_TYPES = ["issue_comment"]` | `EVENT_TYPES = {event_types_list}` |
| `ALLOWED_GITHUB_LOGINS = ["<TOKEN_OWNER>"]` | `ALLOWED_GITHUB_LOGINS = {allowed_logins_list}` |
| `DEFAULT_OPENHANDS_URL = "http://localhost:8000"` | `DEFAULT_OPENHANDS_URL = "{url}"` (keep default if the user has no preference) |

Write the customised script to a temporary build directory:
```bash
mkdir -p /tmp/github-monitor-build
# (write the customised main.py to /tmp/github-monitor-build/main.py)
```

Validate syntax before packaging:
```bash
python3 -m py_compile /tmp/github-monitor-build/main.py && echo "Syntax OK"
```

Fix any syntax errors before proceeding.

### Step 8  -  Package and upload

Determine the Automation backend URL and auth from the `<RUNTIME_SERVICES>`
block in your system context:
- Use the **Automation backend** `url_from_agent` as `OPENHANDS_HOST`
- Auth: `X-Session-API-Key: $OPENHANDS_AUTOMATION_API_KEY`

If no Automation backend is listed in `<RUNTIME_SERVICES>`, stop and tell
the user to start the full automation stack.

```bash
tar -czf /tmp/github-monitor.tar.gz -C /tmp/github-monitor-build .

# OPENHANDS_HOST: read from <RUNTIME_SERVICES> Automation backend url_from_agent
OPENHANDS_HOST="<automation-url-from-runtime-services>"

TARBALL_PATH=$(curl -s -X POST \
  "${OPENHANDS_HOST}/api/automation/v1/uploads?name=github-repo-monitor" \
  -H "X-Session-API-Key: $OPENHANDS_AUTOMATION_API_KEY" \
  -H "Content-Type: application/gzip" \
  --data-binary @/tmp/github-monitor.tar.gz \
  | python3 -c "import json,sys; print(json.load(sys.stdin)['tarball_path'])")

echo "Uploaded: $TARBALL_PATH"
```

### Step 9  -  Create the automation

```bash
curl -s -X POST "${OPENHANDS_HOST}/api/automation/v1" \
  -H "X-Session-API-Key: $OPENHANDS_AUTOMATION_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"name\": \"GitHub Monitor: {owner}/{repo}\",
    \"trigger\": {\"type\": \"cron\", \"schedule\": \"{cron_schedule}\"},
    \"tarball_path\": \"$TARBALL_PATH\",
    \"entrypoint\": \"python3 main.py\",
    \"timeout\": 55
  }" | python3 -m json.tool
```

Record the returned `id`.

### Step 10  -  Confirm

Tell the user:

> ✅ **GitHub Repository Monitor** is running!
>
> - Automation ID: `{id}`
> - Repository: `{owner}/{repo}`
> - Trigger phrase: `{phrase}`
> - Event types: `{event_types}`
> - Allowed GitHub logins: `{allowed_logins}`
> - Polling schedule: `{cron_schedule}`
> - State file: `~/.openhands/workspaces/automation-state/github_poller_{id}.json`
>
> From an allowed GitHub login, post a comment containing `{phrase}` on any
> issue or PR in `
Files: 8
Size: 78.9 KB
Complexity: 74/100
Category: General

Related in General