An autonomous agent that discovers trendy GitHub repos, learns contribution guidelines, fixes issues, tests in Docker, and opens PRs. Uses Cursor CLI as the primary AI engine. All repo execution (clone, npm test, etc.) runs inside Docker for safety.
- Host: Runs discovery (GitHub API), Docker commands, and writes bootstrap/config. Never executes repo code.
- Docker: Cursor CLI, gh, git. Clone, fix, test, and PR creation happen inside the container.
Superpowers adds shared agent skills (TDD, planning, debugging workflows). In Cursor Agent chat you can run /add-plugin superpowers or install Superpowers from the marketplace.
For a local install (same layout Cursor expects under ~/.cursor/plugins/local), clone the repo and reload the editor:
# Windows (PowerShell)
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.cursor\plugins\local" | Out-Null
git clone --depth 1 https://github.com/obra/superpowers.git "$env:USERPROFILE\.cursor\plugins\local\superpowers"# macOS / Linux
mkdir -p ~/.cursor/plugins/local
git clone --depth 1 https://github.com/obra/superpowers.git ~/.cursor/plugins/local/superpowersThen Developer: Reload Window so rules/skills load. Update with git pull inside that clone.
- Docker (the agent image runs as user
dev, UID 1000, so test stacks that refuse root—e.g. embedded Postgres—work afterdocker build; rebuild if you still use an older root-based image) - Python 3.10+
- Cursor CLI (installed in the image)
CURSOR_API_KEY(from Cursor settings)GITHUB_TOKENwithreposcope (for discovery and PR creation)
# Clone and enter project
cd iynx
# Create venv and install deps
python -m venv .venv
.venv\Scripts\activate # Windows
# source .venv/bin/activate # Linux/macOS
pip install -r requirements.txt
# Run unit tests (no Docker)
pytest tests/ -v
# With coverage (threshold in pyproject.toml)
pytest tests/ -v --cov=src --cov-report=term-missing
# Lint / format (Ruff)
ruff check src tests run.py
ruff format src tests run.py
# Copy env template and fill in secrets
copy .env.example .env
# Edit .env with CURSOR_API_KEY and GITHUB_TOKEN
# Build Docker image
docker build -t iynx-agent:latest .# Load env
set -a && source .env && set +a # Linux/macOS
# Or on Windows: $env:CURSOR_API_KEY="..."; $env:GITHUB_TOKEN="..."
# Run the agent (discovers repos, fixes one issue, opens PR)
python run.py
# While Docker runs (clone, Cursor, tests, `gh`), lines from the container are streamed
# to the console as `INFO` log lines prefixed with `[docker]`.
# Inside the container, scripts also emit `[iynx-docker] …` timestamp lines at each phase
# (clone, bootstrap, cursor-agent, PR) so you can follow progress; disable with IYNX_DOCKER_TRACE=0.
# Cursor phases use `--output-format stream-json` and `--stream-partial-output` by default
# so agent/tool progress appears as NDJSON lines (see env table to switch to `text` if logs are too noisy).
# Target one repo (and optional issue number). Without argv[2], the agent lists open issues and picks one it can handle (Phase 2).
python run.py obra/superpowers
python run.py obra/superpowers 849
# Or: IYNX_TARGET_REPO=obra/superpowers IYNX_TARGET_ISSUE=849 python run.pyWhile python run.py runs, the orchestrator writes structured lifecycle events so another process (or a Cursor agent watching the repo) can tell what finished or failed without parsing Docker prose.
- Default file:
.iynx-run-progress.jsonlat the project root (gitignored). Each line is one JSON object (ts,run_id,phase,status,repo,issue,detail,exit_code). - Human logs: Lines like
[iynx] phase=phase3_implement status=started repo=owner/name issue=42mirror the same steps in the console. - Override path: set
IYNX_PROGRESS_JSONLto a file path. Set it to empty,0, orfalseto disable file output (logs still include[iynx]lines).
Follow the log (PowerShell): Get-Content .iynx-run-progress.jsonl -Wait
Follow the log (Unix): tail -f .iynx-run-progress.jsonl
phase |
Meaning |
|---|---|
discovery |
Repo list after filters (or skipped if none) |
target_resolve |
Explicit owner/repo from argv/env |
preflight |
Open-issue checks before clone |
clone / bootstrap |
Docker clone and host bootstrap |
phase1_context … phase4_pr_draft |
Cursor phases |
verify_tests |
Optional post-fix test re-run (skipped if disabled in orchestrator) |
pr_create |
gh fork / push / pr create |
workflow |
Host/Docker timeout or unexpected error |
run_complete |
Final row: detail is pr_created or no_pr; exit_code matches process |
status |
Meaning |
|---|---|
started |
Step began |
completed |
Step succeeded |
failed |
Step failed |
skipped |
Step not applicable (e.g. no repos, verify disabled) |
Process exit codes: 0 = PR created; 1 = fatal config (e.g. missing CURSOR_API_KEY); 2 = run finished without a PR (discovery empty, preflight/phase/PR failure, etc.).
Count your PRs that match an optional label and a head branch regex (default fix/issue-<n>), across all repositories, using the GitHub API. Requires GITHUB_TOKEN. A label comes from --label, IYNX_STATS_LABEL, or IYNX_PR_LABEL—or use --no-label to match author + branch only (for PRs that never had a label).
# With label (filter in GitHub search)
python stats.py --format json --label your-label
python stats.py --format card --label your-label
# No label: only author + branch head (e.g. fix/issue-123 branches without the label)
python stats.py --no-label
# alias: --format shareUse IYNX_PR_LABEL when running the agent so new PRs get the same label and show up in label-based stats. GitHub Search returns at most 1,000 items per open/closed query; if you have more matches, counts can be incomplete (a warning is printed). Private repos need a token with repo scope.
If counts stay at zero: (1) With a label filter, PRs must have that exact label—older PRs opened before IYNX_PR_LABEL was set won’t have it; use --no-label instead. (2) By default only head branches matching ^fix/issue-\d+$ count; use python stats.py --branch-regex ".*" to include any branch, or python stats.py -v for search/skip diagnostics on stderr.
Exit codes: 0 success; 1 config/usage; 2 GitHub HTTP/network error after retries.
After maintainers comment on an open PR, dump review threads into a local markdown file for an agent (or you) to implement fixes. Uses gh only (no direct GitHub REST in this tool). It does not run git commit or git push — you (or the agent) must commit fixes and git push origin <pr-head-branch> so the PR updates. Install and authenticate GitHub CLI on the host.
Default output: <contribution-repo>/.iynx/pr-review-feedback.md — only if that path is gitignored in the target repo; otherwise pass --output or set IYNX_PR_REVIEW_FEEDBACK_PATH. Do not commit that file.
# From inside the contribution clone (branch can be set with gh pr checkout)
cd workspace/owner-repo
python ../pr_review.py https://github.com/owner/repo/pull/42
# Or explicit repo + number (from any cwd; use --output if not in a git repo)
python pr_review.py --repo owner/repo --pr 42 -o /tmp/pr-review-feedback.md
# PowerShell example with explicit output
python pr_review.py "https://github.com/owner/repo/pull/42" --output "$env:TEMP\pr-review-feedback.md"Clone / checkout (normalize first): from the contribution repo, run git fetch and gh pr checkout <N> (same PR as your branch). If you have no clone yet, clone the head repository from gh pr view <url> --json headRepository,baseRepository, add upstream when the PR is from a fork, then gh pr checkout.
Exit codes: 0 file written; 1 usage or local validation (e.g. default path not gitignored); 2 gh/GitHub error.
See skills/issue-fix-workflow.md § PR review follow-up and docs/superpowers/specs/2026-03-24-pr-review-followup-design.md.
| Variable | Required | Description |
|---|---|---|
CURSOR_API_KEY |
Yes | Cursor CLI API key |
GITHUB_TOKEN |
Yes* | GitHub token (repo scope) for discovery and PRs |
IYNX_PR_LABEL |
No | If set, passed to gh pr create --label so PRs are tagged for stats.py filtering |
IYNX_STATS_LABEL |
No | Override label when running python stats.py (defaults to IYNX_PR_LABEL) |
IYNX_STATS_NO_LABEL |
No | If 1/true, same as python stats.py --no-label (author + branch only; no label in search) |
IYNX_STATS_BRANCH_REGEX |
No | Override branch regex for stats.py (default matches fix/issue-<n>) |
IYNX_STATS_AUTHOR |
No | GitHub login for stats.py (default: token’s user) |
IYNX_PR_REVIEW_FEEDBACK_PATH |
No | Output path for python pr_review.py when --output is omitted (same effect as --output; use to write without a local clone). For the default .iynx/pr-review-feedback.md path, you still need a repo root and a gitignored target unless you set this to a path outside the repo |
IYNX_PROGRESS_JSONL |
No | Path to JSONL progress file; empty/0/false disables the file |
IYNX_DOCKER_TTY |
No | If 1 (default), docker run -t for streamed steps so Cursor CLI output is line-buffered to the host; set 0 if -t fails (e.g. some CI) |
IYNX_DOCKER_TRACE |
No | If 1 (default), every Docker shell step prints [iynx-docker] timestamp lines (clone, bootstrap, cursor-agent, verify, PR) so docker logs / host [docker] lines show clear phases; set 0 to silence |
IYNX_DOCKER_XTRACE |
No | If 1, runs those shells with set -x (very noisy; for deep debugging only) |
IYNX_CURSOR_OUTPUT_FORMAT |
No | Cursor --print format: stream-json (default, NDJSON as the agent runs), json, or text (final answer only; quiet logs) |
IYNX_CURSOR_STREAM_PARTIAL |
No | With stream-json, if 1 (default) passes --stream-partial-output for smaller text deltas; set 0 to disable |
IYNX_DOCKER_RUN_TIMEOUT |
No | Max seconds per docker run (clone, each Cursor phase, etc.); default 3600. Raise for huge pnpm install / long agent runs; lower to fail fast |
IYNX_CURSOR_PERMISSIVE |
No | If 1 (default), passes --yolo, --approve-mcps, and --sandbox disabled to cursor-agent so headless runs do not stall on approvals (see Cursor CLI parameters). Set 0 for stricter behavior; phases that used --force still append it when permissive is off |
IYNX_CURSOR_MODEL |
No | Overrides the default Cursor model (composer-2 in code) |
IYNX_CURSOR_EXTRA_ARGS |
No | Extra cursor-agent flags (space-separated, POSIX-quoted), appended after built-in flags |
Discovery rules (stars, age, pool size, CONTRIBUTING requirement, optional post-fix test re-run) live as constants in src/orchestrator.py — edit there to tune behavior; the Cursor model default can be overridden with IYNX_CURSOR_MODEL.
*Without GITHUB_TOKEN, discovery is rate-limited (60 req/hr) and PR creation will fail.
iynx/
├── Dockerfile # Cursor CLI + gh + git + jq + Node.js 22; `USER dev` (UID 1000)
├── docker-compose.yml # Optional local dev
├── src/
│ ├── orchestrator.py # Main loop
│ ├── discovery.py # GitHub Search API
│ ├── github_repo_checks.py # CONTRIBUTING + author PR checks
│ ├── bootstrap.py # Generate .cursor-agent per repo
│ ├── workflow_progress.py # JSONL progress for agents
│ ├── pr_stats.py # GitHub PR stats CLI (label + branch filter)
│ ├── pr_review_followup.py # PR review → markdown (`gh` only)
│ └── pr.py # Fork + push + gh pr create
├── stats.py # Entry: PR statistics (`python stats.py`)
├── pr_review.py # Entry: PR review feedback file (`python pr_review.py`)
├── skills/
│ └── issue-fix-workflow.md
├── tests/ # pytest (discovery + GitHub checks)
├── workspace/ # Mount point (gitignored)
├── .env.example
└── README.md
- Discovery: Search GitHub (defaults in
orchestrator.py: e.g. stars, repo age, pool size), then keep repos that have a CONTRIBUTING file and none of your prior PRs to that repo. - Pick one repo: One repo is chosen uniformly at random from the filtered list (so repeated runs are not stuck on the same top search hit).
- Issue preflight (host, GitHub API): Require at least one open issue (PRs excluded). If none, skip without cloning. This only checks that the list is non-empty.
- Clone:
git cloneinside Docker intoworkspace/owner-repo/. - Bootstrap: Generate
iynx.cursor-agentfrom repo structure (Node/Python/Rust). - Phase 1: Cursor writes
.iynx/summary.mdand.iynx/context.json(test_command,lint_command) from the contribution guide. - Phase 2 (issue selection): Cursor lists open issues (
gh issue list), picks one it can handle (or declines), and writes.iynx/chosen-issue.json. The host validates the pick against the API. Override: pass issue number as argv[2] orIYNX_TARGET_ISSUEto skip this phase. - Phase 3 (implement): Cursor implements the fix for the selected issue, runs tests, does not commit
.iynx/. - Verify (optional): If
VERIFY_TESTS_AFTER_FIXis enabled inorchestrator.py, Docker re-runstest_commandfromcontext.json. - Phase 4 (PR draft): Cursor writes
.iynx/pr-draft.json(title,body). - PR: Host writes
.iynx/pr-body.md;gh repo fork, push,gh pr create --body-file ….
See CONTRIBUTING.md for setup, tests, and PR guidelines.
Report security issues as described in SECURITY.md.
- Never run
npm install,pytest, or any repo scripts on the host. - All clone, fix, and test execution happens inside the Docker container.
- The host only performs HTTP (discovery), Docker commands, and file writes.
