skills/github-repo-monitor/SKILL.md
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.
npx skillsauth add openhands/skills github-repo-monitorInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Create a cron automation that polls a single GitHub repository on a
configurable schedule (default: every minute).
Windows PowerShell equivalents for the setup, packaging, upload, and API-check shell snippets are in references/windows.md.
When a comment on an issue or PR contains the trigger phrase
(default: @OpenHands) it:
On every subsequent run:
Local mode only. This automation targets the local OpenHands setup (
dev:automationstack). A cloud/webhook variant is out of scope here.
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:
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.
| Secret name | Default | Purpose |
|---|---|---|
| OPENHANDS_URL | http://localhost:8000 | Base URL used to build conversation links in GitHub comments |
Follow these steps in order.
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.
Ask the user: "Which GitHub repository should be monitored?
(Format: owner/repo, e.g. microsoft/vscode)"
Validate access and write permissions:
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}\")
"
message: Not Found or message: Bad credentials →
inform the user and ask them to check the repo name and token.permissions.push is false →
inform the user the token does not have write access and comments will fail.REPO = "{owner}/{repo}".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".
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.
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"] |
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.
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:
mkdir -p /tmp/github-monitor-build
# (write the customised main.py to /tmp/github-monitor-build/main.py)
Validate syntax before packaging:
python3 -m py_compile /tmp/github-monitor-build/main.py && echo "Syntax OK"
Fix any syntax errors before proceeding.
Determine the Automation backend URL and auth from the <RUNTIME_SERVICES>
block in your system context:
url_from_agent as OPENHANDS_HOSTX-Session-API-Key: $OPENHANDS_AUTOMATION_API_KEYIf no Automation backend is listed in <RUNTIME_SERVICES>, stop and tell
the user to start the full automation stack.
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"
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.
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}.jsonFrom an allowed GitHub login, post a comment containing
{phrase}on any issue or PR in{owner}/{repo}to test it. OpenHands will acknowledge with a comment and a link to the new conversation.
Each cron run executes main.py, which:
references/state-schema.md).last_poll timestamp:
GET /repos/{owner}/{repo}/issues/comments?since=… for issue_commentGET /repos/{owner}/{repo}/pulls/comments?since=… for pr_review_comment[bot]) to avoid feedback loops.ALLOWED_GITHUB_LOGINS.status ∈ {idle, finished, error, stuck} and enough time has passed
since creation (debounce), fetches the agent's final response and posts
it as a GitHub comment. Marks the conversation closed.references/state-schema.md - State JSON schema, field definitions,
and conversation lifecycle diagram.references/github-api.md - GitHub API endpoint reference, token
scopes, rate limits, and common error codes.scripts/main.py - The complete automation script. Customise the four
constants at the top (REPO, TRIGGER_PHRASE, EVENT_TYPES,
DEFAULT_OPENHANDS_URL) before packaging.| Symptom | Likely cause | Fix |
|---|---|---|
| Bot doesn't respond to comments | GITHUB_PERSONAL_ACCESS_TOKEN missing or wrong scopes | Verify token with curl /user; check scopes in Step 1 |
| "Bad credentials" in run logs | Token expired | Rotate token and update the secret in Settings |
| 404 on repo access | Repo name wrong or token has no access | Re-check owner/repo spelling; add token as collaborator |
| Comments posted but no conversation created | Agent server URL wrong | Check OPENHANDS_URL secret and AGENT_SERVER_URL env var |
| Same comment processed twice | processed_comment_ids cleared | State file was deleted; harmless but duplicate comment may appear |
| Summary never posted | Conversation stuck in running | Open the conversation in the OpenHands UI; agent may need input |
| No events detected after first run | last_poll in the future | Delete the state file to reset; it will be recreated on next run |
tools
Iterate on a GitHub pull request — drive it through CI, code review, and QA until it is merge-ready. Poll verification layers with `gh` CLI, diagnose and fix CI failures, address review feedback, retry flaky checks, push fixes, and repeat. The agent is the orchestration loop.
development
Guides technical explanations toward flowing, direct, conversational prose. This skill should be used for engineering chat, design discussion, architecture analysis, code-review explanations, and technical recommendations that should be concise without becoming fragmented or vague.
tools
This skill should be used when the user asks to "set up a Jira automation to create pull requests", "poll Jira for create-pr issues", "automatically create GitHub PRs from Jira tickets", "deploy a Jira issue-to-PR automation", "create a Jira to GitHub PR workflow", or mentions automating GitHub PR creation from a Jira label. Deploys 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 repository is read from the body of the Jira ticket - no repo parameter is required at deploy time.
tools
This skill should be used when the user asks to "create an automation", "schedule a task", "set up a cron job", "webhook integration", "event-triggered automation", or mentions automations, scheduled tasks, cron scheduling, or webhook events in OpenHands Cloud.