콘텐츠로 이동

GitHub 저장소에서 프로젝트 채우기

에이전트를 GitHub 저장소로 향하게 하면 곧바로 쓸 수 있는 보드가 돌아옵니다. 모든 이슈가 스토리가 되고, 그 이력이 말하는 상태로 놓이며, 체크리스트와 라벨과 마일스톤이 함께 넘어옵니다. 그다음 같은 에이전트가 스토리를 집어 들고, 자기 것으로 삼고, 상태 기계를 따라 옮기고, 자신이 연 풀 리퀘스트를 연결합니다.

이 페이지는 그 루프를 처음부터 끝까지 다룹니다. 채우기 단계에는 두 갈래가 있습니다. East Agile의 오픈소스 임포터 GitHub-to-EAT는 명령 하나로 끝내고(3단계), 임포트 API는 같은 일을 호출 단위로 합니다(4단계와 5단계). 잡 핸들이 필요한 에이전트가 모는 쪽이 후자입니다. 그 이후는 전부 API 위에서 돌아갑니다. 나머지를 에이전트가 감독 없이 해낼 수 있다는 것이 요점이기 때문입니다.

이것은 별도의 「AI 임포트」가 아닙니다. 채우기 단계는 프로젝트 설정 → 가져오기 / 내보내기에서 손으로 실행할 수 있는 바로 그 GitHub 임포터이며, 운영 안내 → 다른 트래커에서 가져오기에 설명되어 있습니다. 에이전트는 당신이 부를 엔드포인트를 그대로 부릅니다. 이 페이지가 더하는 것은 그 주변 전부입니다. 누가 키를 쥐는지, 쓰기 전에 임포트를 어떻게 확인하는지, 보드가 생긴 뒤 에이전트가 그것으로 무엇을 하는지.

Import / Export 탭의 GitHub 소스: 소유자와 저장소 입력, 토큰은 비워 두고, 풀 리퀘스트와 마일스톤 선택

  • 프로젝트 — 그리고 그것을 만들 세션이나 ea_user_… 키.
  • 에이전트 키 — 그 프로젝트로 범위가 한정된 ea_agent_… 키. 어떤 역할이 필요한지는 루프의 어디까지를 에이전트에게 맡길지에 달려 있습니다. 2단계를 보세요. API 가이드 → 두 종류의 키도 참고하세요.
  • GitHub 개인 액세스 토큰 — 저장소 이슈에 대한 읽기 권한이 있는 것. 모든 임포트는 인증을 거칩니다. 조회가 GitHub의 GraphQL API에서 이뤄지고 GraphQL은 토큰 없는 요청을 거부하기 때문입니다. 생략할 수 있는 경우는 Tracker가 당신을 대신해 조회할 때뿐입니다. 즉 공개 저장소이고, 공유 대체 토큰을 가진 배포이며(호스팅되는 eastagiletracker.com 은 하나를 갖고 있고, 자체 호스팅 설치는 운영자가 GITHUB_IMPORT_PAT 를 설정하기 전까지 없습니다), GitHub-to-EAT의 --engine direct아닐 때입니다. 토큰과 요청 한도를 보세요.
  • Node.js 22+ — 3단계의 GitHub-to-EAT 경로에만 필요합니다. API 경로는 curl 말고는 아무것도 필요하지 않습니다.

프로젝트는 에이전트 키보다 먼저 있어야 하고, 사람이 만들어야 합니다. 에이전트 키는 발급 시점에 한 프로젝트에 묶이며 스스로 프로젝트를 만들 수 없습니다. UI에서 만들거나, 자신의 ea_user_… 키로 만드세요.

Terminal window
curl -X POST https://eastagiletracker.com/api/v1/projects \
-H "X-TrackerToken: $TRACKER_USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "hello-world", "iteration_length_weeks": 1}'

응답에는 아래의 모든 호출이 필요로 하는 project_id가 담겨 있습니다.

프로젝트 소유자는 프로젝트 설정 → 에이전트에서 에이전트 키를 만듭니다. 고른 역할이 이 페이지의 어디까지를 에이전트가 혼자 할 수 있는지 결정하며, 합리적인 답은 둘입니다.

  • owner — 키 하나로 임포트를 포함한 루프 전체를 돕니다. 임포트가 프로젝트의 형태를 통째로 다시 쓰기 때문에 임포트는 소유자 전용입니다. owner 역할의 에이전트를 발급하려면 당신 자신이 프로젝트 소유자여야 합니다. 에이전트의 역할은 결코 만든 사람의 역할을 넘지 못합니다.
  • member — 최소 권한. 에이전트는 스토리를 맡고, 옮기고, 댓글을 달고, 풀 리퀘스트를 연결하지만 임포트는 하지 못합니다. 임포트는 당신이 자신의 키로 직접 실행하고(5단계), 그 뒤 보드를 에이전트에게 넘깁니다.

어느 쪽이든 기본값으로 두지 마세요. 새 에이전트 키는 달리 말하지 않으면 viewer이고, viewer는 보드를 읽을 수는 있어도 스토리를 맡거나 옮기지 못합니다. 그것이 이 루프의 대부분입니다.

에이전트 키가 여기서 중요한 이유는 접근 권한을 넘어섭니다. 에이전트 키는 한 프로젝트 안의 이름 있는 참여자로 행동하므로, 그것이 만든 모든 스토리, 그것이 한 모든 상태 변경, 그것이 쓴 모든 댓글이 이력에서 그 에이전트에게 귀속됩니다. 당신 자신의 작업과 뒤섞이지 않고 구분됩니다.

Terminal window
export TRACKER_TOKEN="ea_agent_xxxxx"

무엇보다 먼저 에이전트가 /meta를 읽게 하세요.

Terminal window
curl https://eastagiletracker.com/api/v1/meta \
-H "X-TrackerToken: $TRACKER_TOKEN"

그러면 에이전트가 그러지 않았다면 짐작해야 했을 두 질문에 답이 나옵니다. 키가 어느 프로젝트에 묶여 있는지(auth.project_id)와, 스토리 유형별로 어떤 상태 이동이 허용되는지(transitions)입니다. feature는 unstarted → started → finished → delivered → accepted를 지나고, chore는 unstarted → started → accepted뿐입니다. 지도를 읽는 편이 하드코딩보다 낫습니다.

GitHub-to-EAT는 East Agile 자체의 오픈소스 임포터입니다. MIT 라이선스의 명령줄 도구로, 채우기 단계 전체 — 아래 4단계와 5단계 — 를 명령 하나로 처리합니다. 터미널 앞에 사람이 있을 때 손을 뻗으세요. 에이전트가 감독 없이 몰면서 폴링할 잡 핸들을 원할 때는 그 아래의 API로 손을 뻗으세요.

Node.js 22+가 필요하고 자체 런타임 의존성은 없습니다. 아직 npm에 게시되지 않았으니 저장소에서 설치하세요.

Terminal window
git clone git@github.com:EastAgile/GitHub-to-EAT.git
cd GitHub-to-EAT
npm install --global .

그다음 2단계에서 발급한 키와 1단계에서 만든 프로젝트를 가리키게 하세요.

Terminal window
export EAT_AGENT_KEY="ea_agent_xxxxx"
github-to-eat --project $PROJECT_ID --repo octocat/hello-world

먼저 매핑 범례 — 선택한 각 유형이 정확히 어떻게 안착하는지 — 를 출력하고, 무엇이든 쓰기 전에 확인을 요청합니다. 터미널 밖, 파이프 안, CI나 에이전트 안에서는 그 프롬프트를 보여줄 곳이 없으므로, 쓰기를 할 실행은 --yes를 넘겨야 합니다. 그것 없이는 도구가 당신의 답을 짐작하는 대신 2로 종료하고 아무것도 쓰지 않습니다. 다시 실행해도 안전합니다. 이미 가져온 것은 건너뛰고 결코 중복되지 않습니다.

플래그하는 일
--dry-run사전 점검 후 수행했을 계획 — 몇 개의 스토리를 가져오고, 이미 있어서 몇 개를 건너뛸지 — 을 출력하고 아무것도 쓰지 않습니다. --yes가 필요 없습니다.
--include가져올 유형을 쉼표로 구분해 지정합니다: issues,prs,milestones,releases,deps. 기본값은 issues이며 모든 선택은 이를 포함해야 합니다. 6단계 표와 같은 옵트인입니다.
--token당신의 GitHub 개인 액세스 토큰(환경이나 .envGITHUB_TOKEN도 인정됩니다). 그 저장소에 대해 repo, 또는 세분화된 Issues: Read가 필요합니다. 비공개 저장소, 공유 대체 토큰이 없는 서버, 그리고 --engine direct에서는 항상 필수입니다. 호스팅 서비스의 기본 엔진에서 생략하면 Tracker가 자체 공유 예산을 씁니다 — 토큰과 요청 한도를 보세요.
--engine기본값 server/import/json 호출 하나를 보내고 조회·매핑·쓰기를 Tracker에 맡깁니다. direct는 같은 파이프라인을 당신의 머신에서 실행하고 대신 공개 API로 씁니다. 즉 GitHub를 직접 읽으므로 언제나 토큰이 필요하며, 없으면 2로 종료합니다.
--states, --milestones, --story-type, --no-comments, --no-tasks한 번의 실행에 한해 매핑을 좁히거나 덮어씁니다. 아무것도 저장되지 않습니다. 각각이 --engine direct를 함의합니다.

EAT_API_BASEEAT_APP_BASE를 설정하면 자체 호스팅이나 로컬 Tracker를 가리킬 수 있습니다. 둘 다 기본값은 호스팅 서비스입니다. README에 전체 플래그 레퍼런스, 종료 코드, 문제 해결이 있습니다.

아래는 모두 같은 임포트를 호출 단위로 몬 것이며, 에이전트가 실행할 때 당신이 원하는 형태입니다.

임포트는 소유자 전용입니다. owner 역할의 에이전트 키를 쓰거나, 에이전트를 member로 두었다면 당신 자신의 키를 쓰세요. 무엇이든 쓰게 하기 전에 먼저 dry_run으로 실행하세요.

Terminal window
curl -X POST https://eastagiletracker.com/api/v1/projects/$PROJECT_ID/import/json \
-H "X-TrackerToken: $TRACKER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"source": "github",
"owner": "octocat",
"repo": "hello-world",
"include_pull_requests": true,
"include_milestones": true,
"dry_run": true
}'

드라이런은 GitHub에서 가져오고, 해석하고, 중복을 제거하는 일을 실제와 똑같이 하고, 같은 개수 — imported, skipped, errors, unmatched — 를 보고한 다음 트랜잭션 전체를 롤백합니다. 아무것도 남지 않고 임포트 완료 이벤트도 감사 로그에 닿지 않습니다. 마일스톤을 포함하려 했다는 사실이나 저장소가 생각보다 크다는 사실을, 아직 아무 비용도 들지 않을 때 알아내는 가장 값싼 방법입니다.

/import/json에 대한 모든 호출은 드라이런을 포함해 비동기입니다: 엔드포인트는 결과가 아니라 잡 핸들과 함께 202를 돌려주고, 개수는 잡을 폴링할 때(5단계) 잡에 실려 도착합니다. 드라이런의 잡도 실제 잡처럼 done에 이르며, 차이는 아무것도 쓰이지 않았다는 것뿐입니다.

dry_run을 빼고 다시 보내세요. 앞서와 마찬가지로 엔드포인트는 잡 핸들과 함께 202를 돌려줍니다:

{ "import_id": "…", "status": "pending" }

종료 상태에 이를 때까지 잡을 폴링하세요.

Terminal window
curl https://eastagiletracker.com/api/v1/projects/$PROJECT_ID/imports/$IMPORT_ID \
-H "X-TrackerToken: $TRACKER_TOKEN"

상태는 pending → fetching → writing → done | failed로 흐릅니다. 종료 상태는 마지막 둘뿐입니다. done은 결과 개수를, failed는 오류 메시지와 분기할 수 있는 안정적인 기계 코드를 담습니다. 조회가 페이지를 넘기는 동안 progress_currentprogress_total이 몇 페이지째인지 알려줍니다. 사람이 지켜본다면 보여줄 만합니다.

토큰. "token": "github_pat_…"을 넘기세요. 빼면 서버가 공유 플랫폼 토큰으로 대체하는데, 이 토큰은 공개 저장소만 읽고 그 배포의 모든 호출자에게서 차감됩니다 — 토큰과 요청 한도가 그 대가를 다룹니다. 어느 토큰이 쓰이든, 그것은 업스트림 GitHub 호출만 이끌 뿐입니다. 로그에도 감사 로그에도 남지 않고, 저장되지 않으며, 응답이나 오류로 되돌려 보내지지도 않습니다.

다시 실행해도 안전합니다. 이미 가져온 행은 소스 id로 대조되어 건너뛰고 중복되지 않습니다. 두 번째 임포트는 첫 번째 이후에 나타난 것으로 보드를 채워 넣습니다.

이슈는 기본으로 가져옵니다. 나머지는 전부 옵트인이며, 유형마다 플래그 하나입니다.

GitHub 쪽이렇게 됩니다플래그
이슈스토리. 열림 → Backlog의 unstarted. 닫힘 → accepted, 또는 GitHub가 이슈를 not_plannedduplicate로 닫았다고 알리면 rejected(스토리에 그에 맞는 라벨이 붙습니다).기본
이슈 본문 체크리스트태스크- [ ] / - [x] 각 줄이 본문 순서대로 태스크 하나가 되고, [x]는 완료 상태로 도착합니다. 체크리스트는 설명에도 남습니다.기본
라벨라벨. 있는 그대로 넘어옵니다.기본
풀 리퀘스트pull-request 라벨이 붙은 스토리. 열림 → started, 병합됨 → accepted, 병합 없이 닫힘 → rejected.include_pull_requests
마일스톤마일스톤 이름을 딴 에픽. 제목으로 중복이 제거되므로 같은 마일스톤을 공유하는 두 이슈는 한 에픽에 들어갑니다. 플래그를 끄면 대신 milestone:<제목> 라벨로 따라옵니다.include_milestones
릴리스릴리스 스토리. 게시됨 → accepted, 초안 → unstarted.include_releases
이슈 의존성스토리의 블로커. 이슈만 해당하며 풀 리퀘스트는 아닙니다.include_dependencies

스토리 유형은 이슈가 말하지 않을 때 추론됩니다. bug, fix, defect를 담은 라벨 — 또는 fixbug로 시작하는 제목 — 은 그것을 버그로 만들고, chore, maintenance, devops, infra는 chore로 만들며, 나머지는 전부 feature입니다. 가져오기 전에 알아둘 가치가 있습니다. East Agile Tracker에서는 feature만 포인트를 갖고 feature만 속도에 반영되기 때문입니다. 소개 → 스토리를 보세요.

샘플 저장소를 가져온 직후의 프로젝트 보드: 이슈는 라벨이 붙은 스토리로, 마일스톤은 에픽으로, GitHub 사용자는 오너로

7. 에이전트가 스토리를 진행한다

섹션 제목: “7. 에이전트가 스토리를 진행한다”

이제 보드에는 이력이 있고 에이전트에게는 키가 있습니다. 여기서부터의 루프는 네 번의 호출입니다.

스토리를 찾거나 하나 쓰기. 집어 들 것을 찾아 보드를 거르세요.

Terminal window
curl "https://eastagiletracker.com/api/v1/projects/$PROJECT_ID/stories?state=unstarted" \
-H "X-TrackerToken: $TRACKER_TOKEN"

import_source=github은 임포트가 데려온 것으로 범위를 좁힙니다. 저장소가 한 번도 담아내지 못한 일을 에이전트가 찾았다면 대신 스토리를 만듭니다 — API 가이드 → 스토리 만들기를 보세요.

맡기. 에이전트는 빈 본문을 POST해 자신을 소유자로 추가합니다.

Terminal window
curl -X POST https://eastagiletracker.com/api/v1/projects/$PROJECT_ID/stories/$STORY_ID/owners \
-H "X-TrackerToken: $TRACKER_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'

빈 본문은 호출자를 뜻하므로 에이전트가 자기 id를 알 필요가 없습니다. 이제 보드가 에이전트를 소유자로 보여주고, 지켜보는 사람은 그것으로 일이 잡혔음을 압니다.

시작하기.

Terminal window
curl -X POST https://eastagiletracker.com/api/v1/projects/$PROJECT_ID/stories/$STORY_ID/transitions \
-H "X-TrackerToken: $TRACKER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"to": "started"}'

그다음 에이전트는 실제 일을 하러 갑니다. 저장소를 읽고, 코드를 쓰고, 풀 리퀘스트를 엽니다. 그 부분은 여기가 아니라 당신의 코딩 도구 안에서 일어납니다.

풀 리퀘스트 붙이기.

Terminal window
curl -X POST https://eastagiletracker.com/api/v1/projects/$PROJECT_ID/stories/$STORY_ID/links \
-H "X-TrackerToken: $TRACKER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url": "https://github.com/octocat/hello-world/pull/42"}'

GitHub 풀 리퀘스트 URL은 그 자체로 인식됩니다. 따로 말할 필요가 없습니다. 스토리와 그것을 닫는 코드가 이제 양방향으로 한 번의 클릭 거리에 있습니다.

끝내기. finished로 옮기고 거기서 멈추세요. feature 앞에는 아직 deliveredaccepted가 남아 있고, 그것이 리뷰 관문입니다. 일이 옳은지는 에이전트가 아닌 다른 누군가가 결정합니다. chore에는 그런 관문이 없습니다 — started → accepted가 남은 길의 전부입니다.

가져온 닫힌 이슈의 CODE 섹션에 이를 고친 풀 리퀘스트가 연결되어 있고, 옆에 GitHub 댓글이 있음

모든 임포트는 인증을 거칩니다. 이슈와 댓글과 풀 리퀘스트 조회는 GitHub의 GraphQL API에서 이뤄지고, GraphQL은 토큰이 없는 요청을 거부합니다. 공개 저장소든 비공개 저장소든 익명 등급은 없습니다. 문제는 GitHub에 토큰이 가느냐가 아니라 오직 누구의 것이냐입니다.

임포트 호출에 token을 넘기거나 GitHub-to-EAT에 --token을 넘기세요. 저장소 이슈에 읽기 권한이 있는 세분화된 개인 액세스 토큰이면 충분합니다. 그것은 업스트림 GitHub 호출만 이끌 뿐입니다. 로그에도 감사 로그에도 남지 않고, 저장되지 않으며, 응답이나 오류로 되돌려 보내지지도 않습니다.

데모를 넘어서는 일이라면 자신의 토큰을 가져오세요. 그러면 아무도 건드리지 않는 예산을 쓰게 되고, 남의 임포트 때문에 사전 점검에서 거부당하는 일도 없습니다.

--engine direct는 선택의 여지를 주지 않습니다. 그 엔진은 Tracker를 거치지 않고 당신의 머신에서 GitHub를 읽으므로 서버의 토큰은 손이 닿지 않습니다. 토큰 없는 실행은 조회하거나 쓰기 전에 사용법 오류와 함께 2로 종료합니다. 환경이나 .envGITHUB_TOKEN--token과 똑같이 인정됩니다.

토큰을 강제하는 것은 엔진 전체가 아니라 이슈 순회입니다. direct 는 이슈, 댓글, 풀 리퀘스트를 GraphQL로 읽는데 GraphQL에는 익명 모드가 없습니다. REST는 릴리스 목록과 무료 /rate_limit 조회에만 씁니다. 이 도구에는 공개 저장소 임포트를 시간당 60 예산 안에서 수행하던 오래된 익명 REST 페처가 아직 포함돼 있지만, 이제 어떤 CLI 경로도 거기에 닿지 않으며 삭제될 예정입니다. 따라서 direct 에서는 --token 을 필수로 여기세요.

token을 보내지 않으면 서버가 운영자가 설정한 플랫폼 토큰(GITHUB_IMPORT_PAT)으로 대체합니다. 여기에는 세 가지 제약이 따라옵니다.

  • 선택적 설정입니다. 호스팅되는 eastagiletracker.com 은 하나를 제공하므로 그곳에서는 토큰 없는 공개 저장소 임포트가 작동합니다. 자체 호스팅 설치 — 내려받은 바이너리 — 는 운영자가 환경에 GITHUB_IMPORT_PAT 를 설정하기 전까지 없으며, 그때까지는 토큰 없는 임포트를 모두 400 import_github_no_token 으로 거부합니다.
  • 공개 저장소만 읽습니다. 호스팅 서비스는 이를 공개 저장소에 대한 읽기 전용으로 발급하므로, 비공개 저장소에는 언제나 당신 자신의 토큰이 필요합니다.
  • 배포의 모든 호출자가 하나의 예산을 나눠 씁니다. 토큰 없는 임포트가 실행되기 전에 서버는 공유 토큰에 남은 GraphQL 포인트를 읽고, 500 아래면 400 import_github_shared_quota_low로 거부합니다. 임포트 도중 예산이 떨어지면 잡이 import_github_rate_limited_platform으로 실패합니다. 두 메시지 모두 같은 해법을 가리킵니다. 자신의 토큰을 제공하세요.

GitHub는 두 API를 따로 계량하며, 인증하지 않았을 때의 상한은 두 자릿수 낮습니다.

GitHub API쓰이는 곳토큰 있을 때토큰 없을 때
GraphQL이슈, 댓글, 풀 리퀘스트, 하위 이슈, 의존성시간당 5,000 포인트. 쿼리가 돌려주는 노드로 점수가 매겨집니다거부 — GraphQL에는 익명 등급이 없습니다
REST릴리스(include_releases)와 /rate_limit 사전 점검시간당 5,000 요청시간당 60 요청. IP 주소별로 세고 그 뒤에 있는 모두와 나눠 씁니다

임포트가 그 시간당 60의 등급으로 떨어지는 일은 없습니다. 보낼 토큰이 없으면 익명으로 재시도되는 대신 앞에서 거부되기 때문입니다. 이 숫자가 중요해지는 것은 임포트 주변에서 무엇을 하느냐입니다. GitHub를 직접 읽는 스크립트나, 다른 클라이언트와 같은 네트워크에 있는 셸은 60 요청을 몇 초 만에 다 씁니다.

남은 예산은 언제든 읽을 수 있습니다. GET /rate_limit은 두 한도에서 모두 면제되므로 확인에 비용이 들지 않습니다.

Terminal window
curl -H "Authorization: Bearer $GITHUB_TOKEN" https://api.github.com/rate_limit

GraphQL 포인트는 요청 수가 아닙니다. GitHub는 쿼리가 돌려주는 노드로 점수를 매기므로, 댓글과 담당자를 곁들인 이슈 100건 한 페이지도 많은 포인트를 씁니다. 큰 저장소는 REST 시절의 숫자가 시사하는 것보다 훨씬 적은 호출로 시간당 예산을 소진합니다. --dry-run(3단계)과 dry_run(4단계)은 각각 실제 조회와 같은 포인트를 씁니다 — 그래서 그 개수를 믿을 수 있습니다 — 큰 임포트를 사전 점검할 때는 두 번 분량을 예산에 넣으세요.

  • API 가이드 — 검색 문법, 이벤트 스트림, 일괄 전이, 멱등 쓰기, 그리고 나머지 표면.
  • 운영 안내 — UI에서 본 같은 작업, 그리고 나머지 열 개의 임포터.
  • 소개 — 상태 기계와 네 가지 스토리 유형이 이런 모양인 이유.
  • GitHub-to-EAT — 임포터 자체의 저장소: 모든 플래그, 두 엔진, 그리고 기여하는 방법.