Skip to content

Repository files navigation

issue-to-patch

English README

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 · 요약 · 실행 기록"]
Loading

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.pyVALUE = 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/repo

gia doctor는 설정된 검사 명령의 실행 파일을 확인합니다. --probe-models를 추가하면 coder와 fallback 경로 중 patch를 생성할 provider가 하나 이상 응답하는지도 검증합니다.

초기 설정 파일을 만듭니다.

gia init-config --repo /path/to/python/repo
gia init-config --repo /path/to/python/repo --preset ollama

Issue 해결

gia 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.jsonl

Issue 입력은 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-direrror.json을 쓰며, --error-out PATH로 명시적인 error artifact 경로를 지정할 수 있습니다.

검사 실행 파일이 없거나 Docker daemon에 연결할 수 없는 환경 오류는 patch를 다시 생성해도 해결되지 않으므로 즉시 중단합니다. 동일한 patch가 반복되면 추가 비용을 막기 위해 status=duplicate_patch로 종료합니다. triage 모델이 실패해 결정론적 파일 선택으로 전환한 경우에는 원인을 metadata의 triage_fallback_usedtriage_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.

Benchmark

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_dollar

SWE-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에 repoissue, 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.mddocs/usage.md를 참고하세요.

v* 형식의 tag release는 wheel/sdist artifact를 build하고 GitHub Release에 첨부합니다.

About

Local-first Python CLI agent that turns GitHub issues into tested git patches.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages