issue-to-patch는 동일한 GitHub 이슈를 여러 AI 코딩 모델에 맡기고, 패치 품질과
검사 통과 여부, 비용을 같은 조건에서 비교하는 로컬 우선 Python CLI입니다.
CLI 명령은 gia입니다.
각 모델이 만든 패치는 격리된 Git worktree에서 적용하고 pytest, ruff, mypy
등 지정한 검사를 실행합니다. 결과는 사람이 검토할 수 있는 Git 패치와 모델,
비용, 실패 단계가 담긴 실행 기록으로 저장할 수 있습니다.
이 도구는 다음과 같이 같은 문제를 반복 실행하고 결과를 비교해야 할 때 적합합니다.
- 팀에서 사용할 로컬·외부 코딩 모델을 실제 이슈 해결률과 비용으로 비교할 때
- 모델, 프롬프트나 설정을 변경한 뒤 기존 이슈 묶음으로 회귀 평가할 때
- 여러 GitHub 이슈의 패치 후보를 일괄 생성하고, 검사를 통과한 결과만 검토할 때
- Ollama, vLLM 등 OpenAI 호환 API 모델을 동일한 흐름으로 평가할 때
예를 들어, 해결 결과가 알려진 과거 이슈 50개를 여러 모델에 동일하게 맡기고 테스트 통과율, 실패 단계와 비용을 비교해 도입할 모델을 결정할 수 있습니다.
하나의 버그를 대화형으로 해결하거나 요구사항을 함께 구체화해야 한다면 Codex나
Claude Code를 직접 사용하는 편이 더 적합합니다. issue-to-patch는 이들 제품을
실행하는 래퍼가 아니라 OpenAI 호환 API 모델을 정해진 조건으로 평가하는 도구입니다.
- 원본 저장소를 직접 수정하지 않고 임시 worktree에서 패치를 실험합니다.
- 모델의 답변을 설명문이 아니라 사람이 검토할 수 있는
git diff로 남깁니다. pytest,ruff, 선택적mypy등 저장소별 검증 명령을 실행합니다.- 시도별 오류, 비용, 모델 경로와 대체 모델 사용 여부를 실행 기록으로 남깁니다.
- SWE-bench와 자체 이슈 모음에서 해결률과 비용 대비 성과를 비교할 수 있습니다.
flowchart LR
A["Issue 입력<br/>URL · 파일 · inline text"] --> B["관련 파일 탐색<br/>모델에 전달할 문맥 선택"]
B --> C["격리 worktree 생성<br/>원본 저장소 보존"]
C --> D["AI patch 후보 생성<br/>unified diff"]
D --> E["적용 전 검증<br/>git apply --check"]
E --> F["설정된 검사 실행<br/>pytest · ruff · mypy 등"]
F --> G{"검사 통과?"}
G -- "아니오" --> H["실패 단계와 로그 기록<br/>다음 patch 후보 생성"]
H --> D
G -- "예" --> I["검토 가능한 결과 묶음<br/>patch · 요약 · 실행 기록"]
gia solve는 원본 저장소가 아니라 임시 worktree에서 패치를 적용하고 검사를
실행합니다. --run-dir을 지정하면 성공한 실행의 결과 묶음을 다음 파일로 저장해
최종 변경 내용과 판단 근거를 함께 확인할 수 있습니다. 결과 묶음이 만들어지기
전에 실패하면 같은 디렉터리에 error.json을 저장합니다.
| 결과 파일 | 한눈에 확인할 내용 |
|---|---|
final.patch |
사람이 리뷰하고 적용할 수 있는 최종 코드 변경 |
summary.json |
해결 여부, 시도 횟수, 비용, 샌드박스와 worktree 상태 |
attempts.jsonl |
후보별 패치 적용 여부와 검사 결과, 실패 단계 |
metadata.json |
사용 모델, 모델 경로, 토큰과 대체 모델 사용 여부를 포함한 실행 정보 |
현재 gia 0.3.0 통합 테스트는 별도의 Git 저장소와 로컬 OpenAI 호환 테스트
백엔드를 만들고 전체 실행 흐름을 검증합니다. 다음 패치가 한 번의 시도로 검사를
통과해 status=resolved로 기록되는 동안 원본 저장소의 app.py는 VALUE = 1로
유지됩니다.
-VALUE = 1
+VALUE = 2통합 테스트에서는 원본 파일이 유지되는지, 격리 worktree에서 패치와 검사가
통과하는지, --run-dir에 네 개의 결과 파일이 생성되는지까지 확인합니다.
이 프로젝트는 alpha 품질의 오픈소스 인프라입니다. CLI 표면은 로컬 실험에
사용할 수 있지만, 생성된 patch는 신뢰하기 전에 반드시 사람이 검토해야 합니다.
기본 local 검사는 AI가 수정한 코드를 호스트에서 실행하므로, 신뢰하지 않는
저장소에는 --sandbox docker를 사용하세요. 대화형 터미널에서 local 검사를
시작하면 이 위험을 경고합니다.
python -m venv .venv
. .venv/bin/activate
pip install -e ".[dev,yaml]"로컬 환경을 점검합니다.
gia doctor --repo /path/to/python/repo
gia config validate --repo /path/to/python/repogia doctor는 설정된 검사 명령의 실행 파일을 확인합니다. --probe-models를
추가하면 coder와 fallback 경로 중 patch를 생성할 provider가 하나 이상 응답하는지도
검증합니다.
초기 설정 파일을 만듭니다.
gia init-config --repo /path/to/python/repo
gia init-config --repo /path/to/python/repo --preset ollamagia solve \
--repo /path/to/python/repo \
--issue https://github.com/owner/repo/issues/123 \
--sandbox local \
--max-iters 3 \
--repair-strategy replacement \
--run-dir .gia-runs/issue-123 \
--out-diff fix.patch \
--metadata-out runs.jsonlIssue 입력은 GitHub issue URL, 로컬 markdown/json 파일, inline text를 지원합니다.
GitHub issue 입력은 owner/repo#123 형식도 지원하며, 대상 저장소의 origin
remote가 GitHub라면 #123 형식도 사용할 수 있습니다. GitHub issue ref는
GitHub CLI가 있을 때 gh issue view로 가져옵니다.
검증 명령을 Docker container 안에서 실행하려면 --sandbox docker를 사용합니다.
기본값은 local mode이며, 실행 metadata에도 명시적으로 기록됩니다.
일반 Python 이미지에 프로젝트 의존성이 없다면 sandbox.docker_setup_commands로
설치 명령을 지정해야 합니다. 설치에 네트워크가 필요하면 기본값 none 대신
허용할 docker_network도 명시적으로 설정하세요.
기본적으로 gia solve는 대상 저장소에 uncommitted change가 있으면 실행을
거부합니다. 현재 HEAD 기준으로 worktree를 만들되 관련 없는 로컬 변경은
원본 저장소에 그대로 두고 싶을 때만 --allow-dirty를 사용하세요. 생성된 모든
patch는 적용 전에 git apply --check로 dry-run 검증됩니다.
--run-dir PATH를 사용하면 전체 실행 bundle을 저장합니다.
final.patch: 최종 unified diff.metadata.json: compact run metadata 전체.attempts.jsonl: check stdout/stderr를 포함한 상세 attempt 기록.summary.json: 기본적으로 stderr에 출력되는 summary와 같은 내용.
문서에서 사용하는 .gia-runs/ 아래의 untracked 실행 결과는 저장소 dirty 검사에서
제외됩니다. 다른 경로에 결과를 저장하면 .gitignore에 직접 추가해야 합니다.
디버깅 옵션:
--base-ref REF: 특정 ref에서 격리 worktree를 생성합니다.--keep-worktree never|on-failure|always: 임시 worktree를 inspection용으로 보존합니다.--repair-strategy replacement|incremental: 기본replacement는 각 후보를 원래 base ref에 독립적으로 적용하고,incremental은 이전 후보 위에 누적합니다.--check-command CMD: 설정 파일의 checks를 override합니다. 여러 번 지정할 수 있습니다.--context-max-files,--context-max-chars: issue 기반 파일 검색과 prompt 크기를 제한합니다.--skip-checks: 유효한 patch를 적용하되status=unchecked로 기록합니다. unchecked run은 CI가 resolved로 오해하지 않도록 exit code 2를 반환합니다.--quiet: stderr summary를 숨깁니다.--verbose: 진행 로그를 stderr에 출력합니다.
schema v2 metadata에는 실제 model_provider, model, model_route, 전체 token,
patch_provider, fallback_used, compact attempt 기록이 포함됩니다. leaderboard는
실제 patch 생성 provider/model을 우선 집계합니다. 상세 attempt artifact는
check stdout/stderr를 size cap과 secret redaction을 거쳐 저장합니다. metadata가
생성되기 전에 실패하면 --run-dir에 error.json을 쓰며, --error-out PATH로
명시적인 error artifact 경로를 지정할 수 있습니다.
검사 실행 파일이 없거나 Docker daemon에 연결할 수 없는 환경 오류는 patch를 다시
생성해도 해결되지 않으므로 즉시 중단합니다. 동일한 patch가 반복되면 추가 비용을
막기 위해 status=duplicate_patch로 종료합니다. triage 모델이 실패해 결정론적 파일
선택으로 전환한 경우에는 원인을 metadata의 triage_fallback_used와 triage_error에
기록합니다.
대상 저장소에 .gia.yaml을 만듭니다.
providers:
triage:
base_url: http://localhost:11434/v1
model: qwen3:4b
role: triage
timeout_seconds: 60
max_retries: 1
max_tokens: 1500
coder:
base_url: http://localhost:8000/v1
model: Qwen/Qwen3-Coder-30B-A3B-Instruct
role: coder
timeout_seconds: 120
max_retries: 1
max_tokens: 12000
# fallback:
# base_url: https://api.example.com/v1
# api_key_env: EXTERNAL_API_KEY
# model: fallback-coder
# role: fallback
router:
triage_model: triage
coder_model: coder
fallback_model: null
checks:
commands:
- python -m pytest
- ruff check .
mypy_enabled: false
sandbox:
default: local
docker_image: python:3.11
docker_workdir: /workspace
docker_network: none
docker_read_only: false
docker_env: []
docker_user: null
docker_setup_commands: []
docker_tmpfs: [/tmp]외부 fallback provider는 opt-in입니다. 로컬 모델 stack 밖의 네트워크 fallback을
명시적으로 원할 때까지 fallback_model: null을 유지하세요.
사용 가능한 config preset:
local: triage는 Ollama, coding은 vLLM 사용.ollama: 두 역할 모두 Ollama-compatible local model 사용.vllm: 두 역할 모두 vLLM OpenAI-compatible server 사용.openai-compatible: generic external OpenAI-compatible provider template.
gia bench swebench --dataset lite --cases cases.jsonl --limit 10 --predictions preds.jsonl
gia bench korean --cases korean_cases.jsonl --out runs.jsonl
gia bench korean --cases korean_cases.jsonl --out runs.jsonl --solve --limit 10
gia bench korean --cases korean_cases.jsonl --out runs.jsonl --solve --resume --workers 4
gia bench swebench --dataset lite --cases cases.jsonl --predictions preds.jsonl \
--evaluate-command 'python -m swebench.harness.run_evaluation --predictions_path {predictions}'
gia leaderboard --runs runs.jsonl --sort resolved_per_dollarSWE-bench 명령은 공식 harness shape와 호환되는 prediction JSONL을 작성합니다.
필드는 instance_id, model_name_or_path, model_patch입니다. 이 명령은 공식
Docker evaluation harness를 대체하지 않습니다.
--evaluate-command는 {predictions}와 {dataset}을 확장해 설치된 공식 harness를
shell 없이 호출합니다.
gia bench korean --solve는 case에 repo와 issue, issue_file,
issue_text 중 하나가 포함되어 있을 때 각 case를 local solver로 실행합니다.
--resume은 기존 case_id를 건너뛰고, --workers는 독립 case를 병렬 실행합니다.
python -m pytest
ruff check .
ruff format --check .
mypy src
python -m build
twine check dist/*CONTRIBUTING.md와 docs/usage.md를 참고하세요.
v* 형식의 tag release는 wheel/sdist artifact를 build하고 GitHub Release에
첨부합니다.