| name | agent-ops-github |
| description | Bidirectional sync between agent-ops issues and GitHub Issues |
| category | extended |
| invokes | ["agent-ops-state","agent-ops-tasks"] |
| invoked_by | [] |
| state_files | {"read":["issues/*.md","focus.md"],"write":["issues/*.md","focus.md"]} |
agent-ops-github
Bidirectional sync between agent-ops issues and GitHub Issues. Push local issues to GitHub, pull from GitHub to local, and manage the connection.
Tier: 3 (Utility)
Works with or without aoc CLI installed
Use Cases
- Push issues to GitHub — Share local issues with team or track in GitHub
- Pull issues from GitHub — Import GitHub issues as local agent-ops issues
- Sync bidirectionally — Keep local and GitHub in sync
- Import PR feedback — Get code review comments as local issues
- Monitor external repos — Track issues from dependencies
CRITICAL: No Assumptions
Before any GitHub API operation, you MUST:
- Confirm repository details — Ask user for
owner/repo format
- Verify authentication — Check GITHUB_TOKEN is set
- Confirm the operation — Summarize what will be done
- Get explicit approval — User must approve before API calls
Mandatory Confirmation
I will {push/pull/sync} issues {to/from} github.com/{owner}/{repo}:
- Operation: {describe what will happen}
- Issues affected: {count or list}
This will make API calls to GitHub. Continue? [Y/N]
Requirements
Environment
GITHUB_TOKEN environment variable (required)
- Token needs
repo scope (or public_repo for public repos)
How to Create a Token
- Go to GitHub → Settings → Developer settings → Personal access tokens
- Generate new token (classic) with
repo scope
- Add to
.env: GITHUB_TOKEN=ghp_xxxxxxxxxxxx
Issue Sync Procedure (with aoc CLI)
Check Sync Status
aoc github sync status --repo owner/repo
Push Local Issues to GitHub
aoc github sync push FEAT-0042 --repo owner/repo
aoc github sync push-all --repo owner/repo --status todo
aoc github sync push-all --repo owner/repo --dry-run
aoc github sync push FEAT-0042 --repo owner/repo --visible
Pull Issues from GitHub
aoc github sync pull 123 --repo owner/repo
aoc github sync pull 123 --repo owner/repo --no-dry-run
aoc github sync pull-all --repo owner/repo
aoc github sync pull-all --repo owner/repo --no-dry-run
How Metadata Sync Works
When pushing to GitHub:
- Title → GitHub issue title
- Description → GitHub issue body
- Acceptance criteria → Checklist in body
- Type → Label:
type:feat, type:bug, etc.
- Priority → Label:
priority:high, priority:medium, etc.
- Epic → Label:
epic:{name}
- Status → GitHub state:
todo/in_progress → open, done → closed
- Metadata → Hidden YAML comment in body (or visible
<details> block)
When pulling from GitHub:
- GitHub state → Status
- Labels → Type, priority, epic
- Body metadata → Full issue details
- Body → Description (metadata stripped)
Fetch Issues Procedure (read-only)
List Issues
aoc github issues list --repo owner/repo --state open
aoc github issues list --repo owner/repo --state all
aoc github issues search "feature request" --repo owner/repo
aoc github issues by-label bug --repo owner/repo
Get Issue with Comments
aoc github issues get 42 --repo owner/repo --comments --json
Pull Request Comments
aoc github pr list --repo owner/repo --state open
aoc github pr list --repo owner/repo --branch feature/my-branch
aoc github pr comments 123 --repo owner/repo --json
aoc github pr reviews 123 --repo owner/repo --json
aoc github pr by-branch feature/my-branch --repo owner/repo --comments
Procedure (without aoc CLI)
Python Script Approach
import os
import requests
GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN")
OWNER = "owner"
REPO = "repo"
BASE_URL = "https://api.github.com"
headers = {
"Authorization": f"Bearer {GITHUB_TOKEN}",
"Accept": "application/vnd.github+json",
"X-GitHub-Api-Version": "2022-11-28",
}
def list_issues(state="open"):
url = f"{BASE_URL}/repos/{OWNER}/{REPO}/issues"
params = {"state": state, "per_page": 100}
all_issues = []
while url:
resp = requests.get(url, headers=headers, params=params)
resp.raise_for_status()
issues = resp.json()
all_issues.extend([i for i in issues if "pull_request" not in i])
url = resp.links.get("next", {}).get("url")
params = None
return all_issues
def create_issue(title, body, labels):
url = f"{BASE_URL}/repos///issues"
data = {: title, : body, : labels}
resp = requests.post(url, headers=headers, json=data)
resp.raise_for_status()
resp.json()
GitHub Issue Body Format
When pushed to GitHub, the issue body contains:
{Description from local issue}
## Acceptance Criteria
- [ ] First criterion
- [ ] Second criterion
<!-- agent-ops-metadata
id: FEAT-0042@abc123
confidence: normal
epic: agent-ops-cli
acceptance_criteria:
- First criterion
- Second criterion
depends_on:
- FEAT-0040
-->
The metadata block is hidden in the rendered view but preserved for sync.
For visible metadata (useful for transparency), use --visible:
{Description}
<details>
<summary>Agent-Ops Metadata</summary>
yaml
id: FEAT-0042@abc123
...
</details>
Labels Convention
| Local Field | GitHub Label |
|---|
| type: FEAT | type:feat |
| type: BUG | type:bug |
| type: CHORE | type:chore |
| priority: critical | priority:critical |
| priority: high | priority:high |
| priority: medium | priority:medium |
| priority: low | priority:low |
| epic: agent-ops-cli | epic:agent-ops-cli |
| (always added) | agent-ops |
Rate Limiting
GitHub API has rate limits:
- Authenticated: 5,000 requests/hour
- Search API: 30 requests/minute
If rate limited, wait and retry. The client handles this automatically with retries.
Error Handling
| Error | Cause | Solution |
|---|
| 401 Unauthorized | Invalid/expired token | Regenerate GITHUB_TOKEN |
| 403 Forbidden | Rate limit or no access | Wait or check permissions |
| 404 Not Found | Wrong repo or issue | Verify owner/repo/number |
Integration with Other Skills
With agent-ops-branch-workflow
1. Create working branch for issue
2. Work on the issue
3. Push issue to GitHub: aoc github sync push FEAT-0042 --repo owner/repo
4. Create PR referencing the GitHub issue
With agent-ops-selective-copy
1. Complete work on feature
2. Push all done issues: aoc github sync push-all --repo owner/repo --status done
3. Create clean branch for PR
4. GitHub issue automatically closed when merged
Examples
Example 1: Push New Feature to GitHub
aoc github sync push FEAT-0042 --repo myorg/myrepo --dry-run
aoc github sync push FEAT-0042 --repo myorg/myrepo
Example 2: Sync All Active Work
aoc github sync push-all --repo myorg/myrepo --status in_progress
Example 3: Import Team Issues
aoc github sync pull-all --repo myorg/myrepo
aoc github sync pull-all --repo myorg/myrepo --no-dry-run