A private, outbound-only GitHub issue automation system for a personal VM. It polls GitHub on a systemd timer, routes tasks by label, runs the appropriate coding toolchain, and opens a pull request with the results.
This repository is built around a simple rule: no inbound traffic.
That means:
- no public webhook endpoint
- no tunnel to manage
- no exposed port on the VM
- no extra infrastructure beyond GitHub, systemd, and the tools you already use
The VM only makes outbound requests to GitHub and model providers.
- Create a GitHub issue.
- Add the waiting label
overnight-task. - Add one routing label:
task-codetask-e2e
- The poller wakes up on the timer and looks for the oldest waiting issue.
- It replaces the waiting state with
processingand launches the pipeline. - The pipeline creates a branch, generates a plan, runs the selected tool, pushes changes, and opens a PR.
- The PR is marked
ready-for-revieworneeds-human-review.
task-code— use Aider for normal code-change taskstask-e2e— use a custom end-to-end or MCP-capable runner viaE2E_RUNNER_CMD
overnight-task— queued and waitingprocessing— currently running on the VMready-for-review— PR is ready for human reviewneeds-human-review— pipeline finished but needs follow-up
- install.sh — installs dependencies, the poller, and the systemd timer
- setup.sh — compatibility wrapper that delegates to install.sh
- poller/poller.js — outbound GitHub poller that claims work by label
- pipeline/run_pipeline.sh — small entrypoint that coordinates the full pipeline flow
- pipeline/lib — readable helper scripts for planning, execution, repo prep, and publishing
- systemd/pipeline-poller.service.template — oneshot service run by the timer
- systemd/pipeline-poller.timer.template — recurring scheduler
- Makefile — daily operational commands
- .env.example — sample configuration values
- Ubuntu or another Linux machine with systemd
- Node.js latest LTS (installer configures this automatically)
- Python 3 with venv support
- GitHub CLI installed and authenticated (
gh auth login) - Ollama installed locally or installable by the install script
- Optional: Anthropic API key (only if you want Anthropic planner mode)
Use .env.example only if you want to pre-seed defaults. In normal usage, install first, then run rabin configure inside each target repository.
- None required for
install.shbootstrap rabin configureauto-detectsGITHUB_REPOfrom the current git repositoryrabin configureauto-usesGITHUB_TOKENfromgh auth token
OLLAMA_MODEL— defaults toqwen2.5-coder:7bOLLAMA_AUTO_PULL—trueby default, auto-download missing configured Ollama modelsOLLAMA_FALLBACK_MODEL— model used automatically if configured model cannot be prepared (defaultqwen2.5-coder:7b)WORK_DIR— install location on the VMREPO_DIR— where target repositories are cloned, default$HOME/projectsREPO_PATH_OVERRIDE— optional explicit local checkout path for a repo profileVENV_DIR— Python virtual environment pathPOLL_INTERVAL_MINUTES— timer frequency, default5OLLAMA_PLANNER_MODEL— planner model for local plan generationPLAN_MODEL_PROVIDER—auto,ollama,anthropic, orclaude(autonow prefers Claude terminal first, then Anthropic API, then Ollama)AIDER_MODEL— defaultollama/<OLLAMA_MODEL>AIDER_EDITOR_MODEL— optional separate editor model for AiderAIDER_ARCHITECT— set1to enable Aider architect modeAIDER_TRACE—falseby default so the server does not keep code-heavy aider trace logs unless you opt inAIDER_TRACE_DIR— optional explicit path for aider traces if you turn tracing onOLLAMA_API_BASE— defaults tohttp://127.0.0.1:11434for local Ollama accessGIT_COMMIT_NAME— git author name used by pipeline when repo identity is unsetGIT_COMMIT_EMAIL— git author email used by pipeline when repo identity is unsetPIPELINE_STATE_DIR— leave empty to use a per-project local folder under$HOME/.local/state/rabin/<project>/historyPIPELINE_DB_PATH— optional sqlite index path; defaults to$HOME/.local/state/rabin/<project>/issues.dbPIPELINE_REPO_STATE_SUBDIR— legacy repo-local subdirectory if you explicitly want in-repo state files- Installer links
aiderto~/.local/bin/aiderfor direct shell use TARGET_BRANCH— optional base branch to work againstPIPELINE_BRANCH_MODE—issue-branch(default) ordirect-targetSKIP_PR_CREATE—auto(default),true, orfalse
TRIGGER_LABEL— defaultovernight-taskPROCESSING_LABEL— defaultprocessingTASK_LABEL_CODE— defaulttask-codeTASK_LABEL_E2E— defaulttask-e2e
If you want task-e2e issues to use a dedicated command, set:
E2E_RUNNER_CMD
Example uses include Claude Code, browser automation, Playwright flows, or MCP-backed tasks.
-
Export the required environment variables.
-
Run bootstrap installer:
bash install.sh
Or run directly via curl (like Claude Code style):
curl -fsSL https://raw.githubusercontent.com/GittRabin/autonomous-coding-pipeline/main/install.sh | bashIf you are using a fork or branch, set these before curl:
export INSTALL_REPO="yourname/autonomous-coding-pipeline" export INSTALL_REF="main" curl -fsSL "https://raw.githubusercontent.com/${INSTALL_REPO}/${INSTALL_REF}/install.sh" | bash
-
Authenticate GitHub CLI (if not already authenticated):
gh auth login
-
For the normal single-repo path, the installer now auto-enables the default profile when it can detect your repo and GitHub auth.
For multi-project or custom setup, run:
rabin configure
-
Confirm timers are active:
rabin status --all
-
View logs if needed:
rabin logs
After setup, you can run operations from anywhere using the global rabin command.
rabin --helpAvailable commands:
rabin configurerabin profilesrabin showrabin enablerabin disablerabin statusrabin logsrabin restartrabin run-nowrabin urgentrabin uninstall
If you manage multiple target repositories on one VM, use profile files and enable multiple timer instances.
Create profiles:
cd /home/ubuntu/projects/repo-a && rabin configure
cd /home/ubuntu/projects/repo-b && rabin configurerabin configure reuses your existing gh login by default (gh auth token) when --github-token is not provided.
It also initializes required pipeline labels by default (overnight-task, processing, task-code, task-e2e, ready-for-review, needs-human-review).
When run inside a git repo, rabin configure captures that checkout path and the pipeline reuses it (instead of cloning another copy).
Shortcut for current checked-out branch (direct commits, no PR by default):
rabin configure --currentFor branch targeting, you can configure direct commits to a specific branch (no extra task branch):
rabin configure --target-branch dev --branch-mode direct-target --skip-pr-create trueDefault behavior remains issue-branch, which creates task/issue-<number> and opens a PR.
List and inspect profiles:
rabin profiles
rabin show project-aEnable all project instances (parallel polling):
rabin enable project-a
rabin enable project-b
rabin status --allIf you want to disable one project:
rabin disable project-bCreate a GitHub issue and apply:
overnight-task- either
task-codeortask-e2e
Use:
rabin run-now project-a
Use:
rabin status project-arabin logs project-a
If you only configured one project, omitting the profile now targets that saved profile automatically. When using systemctl directly, replace default with the profile name shown by rabin profiles.
rabin status --all— list all active pipeline timersrabin update— update rabin CLI and rerun bootstrap installerrabin status <profile>— inspect one profile service and timerrabin logs <profile>— follow one profile logsrabin run-now <profile>— force immediate poll for one profilerabin urgent <profile>— urgent immediate poll for one profilerabin urgent --all— urgent immediate poll for all profilesrabin disable <profile>— disable one project timerrabin uninstall <profile>— remove one profile runtime filesrabin uninstall --all— stop all timers and clear all runtime env files
- This design is optimized for low-volume personal automation, not high-throughput job scheduling.
- Start latency depends on the polling interval.
- Issues should keep routing labels separate from state labels for clarity.
- If no supported test runner is detected, the PR is still created and flagged for review.