PatchPool is a local-worker MVP for turning an approved, public GitHub issue into a verified, AI-assisted Draft pull request. The worker runs on your own computer: GitHub and Codex credentials stay in your local tools, and the coordinator is deliberately absent from this MVP.
- Node.js 24 or newer
- Git
- GitHub CLI (
gh) - The Codex CLI, signed in with the ChatGPT subscription flow (not an API key)
Authenticate before running the worker:
gh auth login
gh auth status
codex login
codex login status
If GitHub SSH is required for cloning/pushing, select SSH during gh auth login or run gh config set git_protocol ssh, then verify with
ssh -T git@github.com. Configure a Git author identity locally with
git config --global user.name and git config --global user.email; PatchPool
does not store that identity or any credential.
From a checkout:
npm install
node bin/patchpool.js doctor --json
doctor checks GitHub CLI authentication and Codex ChatGPT authentication. It
also checks Node.js 24+, the local Git author identity, read-only access to the
state database, and that Git signing is disabled for worker commits. It does
not claim an issue, mutate state, transmit credentials to PatchPool, or accept
an OpenAI API key for this workflow.
Only a canonical owner/name public repository may be registered. The checked-
in .patchpool.json is the repository policy for this MVP:
{"verifyCommand":["npm","test"],"requiredIssueLabel":"patchpool-ready","timeoutMinutes":30}The 30-minute policy timeout bounds both the Codex implementation and the registered verification command. Clone, push, and pull-request operations have their own bounded adapter deadlines.
Register from the repository root with the checked-in config. The CLI loads and validates this file, checks GitHub for the canonical repository's public and non-archived status, and stores the approved policy snapshot:
node bin/patchpool.js repo add --repo K-saint25/PatchPool --config .patchpool.json
node bin/patchpool.js repo list --json
If --config is omitted, the CLI automatically loads .patchpool.json from
the current working directory. Registration is immutable in the current store:
to change an approved policy, use repo add --config .patchpool.json again for
explicit reapproval (and re-register any legacy approved-config record), or use
a new local state database after review. repo list is read-only: a missing
state database returns [], while legacy, future, malformed, or otherwise
incompatible state is rejected without creating or modifying it.
By default, run claims an eligible, open, unassigned issue, clones it into a
temporary worktree, asks the locally authenticated Codex CLI to edit only that
worktree, and runs the registered verification command. It does not commit,
push, or open a pull request:
node bin/patchpool.js run --repo K-saint25/PatchPool --issue <issue-number> --keep-workspace
Omit --issue to select the first eligible issue. --keep-workspace preserves
the temporary directory for inspection. A remote write requires an explicit
--publish:
node bin/patchpool.js run --repo K-saint25/PatchPool --issue <issue-number> --publish
Codex chooses its normal default model unless you opt into a specific model
locally. Set PATCHPOOL_CODEX_MODEL to a model slug before starting the worker:
$env:PATCHPOOL_CODEX_MODEL = 'gpt-5.6-luna'
node bin/patchpool.js run --repo K-saint25/PatchPool --issue <issue-number>On macOS or Linux, prefix the command with
PATCHPOOL_CODEX_MODEL=gpt-5.6-luna. The choice is entirely user-controlled;
PatchPool does not automatically fall back to another model or retry a model
failure because the worktree may already contain partial edits.
Publishing commits with hooks disabled, verifies the remote, pushes a unique
patchpool/issue-<number>-<claim-id> branch, and creates and verifies a Draft
PR in the canonical repository. The PR body identifies the implementation as
AI-assisted and asks for human review.
After registering this repository and creating an owner-controlled issue with
the patchpool-ready label, the intended self-dogfood command is the guarded
end-to-end path:
node bin/patchpool.js e2e --repo K-saint25/PatchPool --publish
e2e accepts exactly K-saint25/PatchPool and requires --publish; it selects
the eligible owner-controlled issue and runs the full push-plus-Draft-PR flow.
Use a small documentation issue that is not already fixed. Inspect a normal
dry-run first; only then use the guarded command.
- State database:
.patchpool.sqlitein the current working directory, unlessPATCHPOOL_DBnames another path. SQLite may also create adjacent-waland-shmfiles. - Temporary worktrees: the operating system temporary directory, normally
%TEMP%on Windows or/tmpon Unix-like systems. They are removed after a successful run unless--keep-workspaceis used. - Claim states:
claimed → running → verified → committed → pushed → pr_opened. Pre-push failures are persisted asfailedwith an error code and timestamps. After a remote side effect may exist, the worker retainspushedorpr_openedso a retry can reconcile it safely.
Inspect the local claim history as JSON without changing claim or lease state:
node bin/patchpool.js claim list --json
Rows are ordered by claim id ascending. The output includes repository and
workflow status fields, but omits execution lease tokens and arbitrary claim
metadata. If the state database does not exist, the command returns []
without creating it. It never migrates a database; legacy, future, malformed,
or otherwise incompatible state is rejected without modification.
The SQLite claim and execution lease coordinate workers sharing one state DB on one computer only. They are not a distributed lock or a service scheduler.
The worker persists each external side effect. Keep the same PATCHPOOL_DB and
the same worker identity (PATCHPOOL_WORKER_ID, when set) when retrying. A
dry-run that reached verified, or a normal crash before completion, can be
inspected before retrying:
node bin/patchpool.js claim list --json
Use the matching claim's state, workspace, branch, commitSha, prUrl,
and errorCode to decide whether to inspect or retry it. Then rerun with the
same worker identity and an explicit matching issue number:
node bin/patchpool.js run --repo K-saint25/PatchPool --issue <issue-number>
For an active pushed or pr_opened claim, this exact command does not need a
new --publish flag and does not re-evaluate issue eligibility. It only
reconciles the recorded branch with an existing or new Draft PR after the
approved repository, approval generation, worker identity, lease, branch, and
commit metadata have been revalidated. New claims still require the normal
issue eligibility checks and an explicit --publish before any remote write.
For the guarded self-dogfood path, rerun the same e2e --repo K-saint25/PatchPool --issue <issue-number> --publish command. A verification or
Codex failure is safe to inspect and retry after fixing the cause. A dead owner
can be recovered after its execution lease expires, then the same command can
be rerun.
A dry-run intentionally leaves its verified claim active as a fail-safe. For
manual recovery:
- Stop the worker and its entire process tree. If termination cannot be
confirmed, wait until the process tree is confirmed stopped; do not start
another worker. On Windows,
taskkillis PID-based and has a small PID-reuse residual, so unconfirmed termination remains pending. - For a
pushedor ambiguous result, inspect the GitHub branch and Draft PR first. Then rerun the same command so the workflow reconciles the recorded remote side effect instead of creating a duplicate. - For an expired owner lease, confirm the owner process is dead, keep the same
PATCHPOOL_DBand worker identity, and rerun after lease expiry. Never overwrite a live lease. - For a legacy ownerless lease, stop every worker, resolve
PATCHPOOL_DB, and back up the database plus adjacent-wal/-shmfiles. Only when you can prove the run was never published and has no remote side effect may you move that state database aside, choose a new state path, and re-register withrepo add --config .patchpool.json. If there is any uncertainty or a branch/PR may exist, do not edit or delete the database; contact a maintainer for recovery.
PatchPool never stores or sends GitHub/Codex credentials. Issue text is untrusted input to the Codex prompt; the worker restricts the Codex sandbox to workspace writes, rejects suspicious secret files, and uses argv-based subprocesses without a shell. Only explicitly registered canonical public repositories are eligible. Remote writes are limited to a unique branch and a Draft PR, which a human maintainer must review.
Contributors must disclose material AI assistance in pull requests and include test evidence. See SECURITY.md for private vulnerability reporting and CONTRIBUTING.md for the contribution workflow.
Licensed under the Apache License 2.0.