Keystone Multi-Agent Issue Automation
04 에이전트 Markdown

Multi-Agent Issue Automation

GitHub Issue를 안전한 다중 에이전트 작업 큐로 바꾸는 로컬 실행 프로세스

Source
src/content/docs/multi-agent-issue-automation.md
Order
32.5

한눈에 보기

Multi-Agent Issue Automation은 GitHub Issue를 에이전트 작업 큐로 쓰되, 자동 실행 권한을 좁게 제한하는 운영 방식입니다. 목표는 완전 자동 코딩이 아니라, 이슈, 로컬 resolver, 작업 branch, 검증 로그, PR 증거가 서로 맞는지 확인하며 안전하게 위임하는 것입니다.

이 문서에서 확인할 것

  • control repo, issue repo, work repo를 분리하는 이유
  • 로컬 path가 머신마다 달라도 같은 작업을 재현하는 resolver 계약
  • 여러 에이전트를 투입할 때의 역할 분담과 종료 조건
  • unattended 실행 전에 필요한 Project Status, label, repo policy gate

운영 원칙

GitHub Issue는 작업 요청의 source of truth입니다. 터미널 세션이나 tmux pane은 작업을 실행하는 표면일 수 있지만, 상태의 원장이 되면 안 됩니다.

flowchart LR
  subgraph GH["GitHub Work Queue"]
    I["Issue<br/>scope + acceptance"]
    S["Project Status<br/>Ready for Agent"]
    L["Labels<br/>auto-dev + approved"]
  end

  subgraph RUN["Local Runner"]
    C["Portable<br/>Job Contract"]
    R["Resolver<br/>repo id -> path"]
    P{"Policy<br/>Pass?"}
  end

  subgraph WORK["Work Repository"]
    B["Isolated<br/>Branch / Worktree"]
    A["Agent Team<br/>Coordinator + Worker + QA"]
    Q["Verification<br/>build + lint + E2E"]
    PR["Pull Request<br/>evidence attached"]
  end

  I --> C
  S --> C
  L --> C
  C --> R --> P
  P -->|pass| B --> A --> Q --> PR
  P -->|block| X["Blocked Artifact<br/>reason + next action"]
  Q -->|fail| X

  classDef queue fill:#1c2423,stroke:#86c9bd,color:#f1f1f1;
  classDef runner fill:#252119,stroke:#d1a066,color:#f1f1f1;
  classDef work fill:#1b2030,stroke:#5b8cff,color:#f1f1f1;
  classDef block fill:#2b1e1f,stroke:#e98585,color:#f1f1f1;
  class I,S,L queue;
  class C,R,P runner;
  class B,A,Q,PR work;
  class X block;

작업 완료는 코드가 바뀐 순간이 아니라 다음 증거가 맞을 때 선언합니다.

증거확인할 것
Issue상태, 승인 label, assignee, blocking label
Job contracttarget repo, base branch, issue number
Resolver실제 로컬 path, remote URL, branch
Gitisolated branch 또는 worktree
Verificationbuild, lint, typecheck, E2E, browser QA
PR변경 요약, 위험, 테스트 결과, issue link

실행 타임라인

sequenceDiagram
  autonumber
  participant O as Operator
  participant G as GitHub Issue
  participant R as Local Runner
  participant Z as Resolver
  participant A as Agent Team
  participant T as Test Gate
  participant P as Pull Request

  O->>G: Mark Ready for Agent
  G->>R: issue snapshot
  R->>R: check approval + execution labels
  R->>Z: resolve work_repo_id
  Z-->>R: path + remote + base branch
  alt gates pass
    R->>A: dispatch bounded tasks
    A->>T: changed files + verification plan
    T-->>R: pass/fail evidence
    R->>P: open PR with report
    R->>G: comment run id + PR link
  else gate fails
    R->>G: comment blocked reason
    R-->>O: needs human action
  end

저장소 역할

한 저장소 안에서 모든 일이 끝나는 경우도 있지만, 실제 운영에서는 이슈와 작업 저장소가 다를 수 있습니다.

역할의미예시
control_repo정책, runner, 공통 규칙을 가진 저장소codecleanup-dev/keystone-hub
issue_repoGitHub Issue와 Project 상태를 가진 저장소MAESTRO-BS/BisFramework
work_repo코드 변경, branch, commit, PR이 생기는 저장소MAESTRO-BS/BisFramework
pr_repoPR을 여는 대상 저장소보통 work_repo와 동일

cross-repo 작업은 허용할 수 있습니다. 다만 issue 본문이나 job contract에 work_repo, base_branch, clone_url, work_repo_id가 명확해야 합니다.

Portable Job Contract

portable contract에는 개인 머신의 절대 경로를 넣지 않습니다.

{
  "control_repo": "codecleanup-dev/keystone-hub",
  "issue_repo": "MAESTRO-BS/BisFramework",
  "work_repo": "MAESTRO-BS/BisFramework",
  "work_repo_id": "bis-framework",
  "clone_url": "[email protected]:MAESTRO-BS/BisFramework.git",
  "base_branch": "dev",
  "work_branch": "feature/123-short-title",
  "issue_number": 123,
  "pr_repo": "MAESTRO-BS/BisFramework"
}

contract는 어디서 실행해도 같은 의도를 표현해야 합니다. 로컬 path, worktree path, SSH alias, machine id는 실행 시점의 resolver artifact에만 남깁니다.

Local Resolver

resolver는 work_repo_id를 현재 머신의 실제 local path로 바꿉니다.

{
  "repos": {
    "bis-framework": {
      "allowed_roots": ["$HOME/dev-bs", "$HOME/lucy"],
      "path_hints": [
        "$HOME/dev-bs/BisFramework/BisFramework-master",
        "$HOME/dev-bs/BisFramework/BisFramework"
      ],
      "os_path_map": {
        "macos": "$HOME/dev-bs/BisFramework/BisFramework-master",
        "windows": "D:\\\\dev-bs\\\\BisFramework\\\\BisFramework-master",
        "wsl": "/mnt/d/dev-bs/BisFramework/BisFramework-master"
      },
      "clone_root": "$HOME/dev-bs"
    }
  }
}

resolver는 다음 순서로 fail-closed 해야 합니다.

  1. work_repo_id가 등록되어 있는지 확인합니다.
  2. resolved path가 allowed_roots 아래인지 확인합니다.
  3. git remote get-url originwork_repo 또는 clone_url과 맞는지 확인합니다.
  4. base_branch가 존재하거나 fetch 가능한지 확인합니다.
  5. clone이 필요하면 명시 승인 없이는 멈춥니다.
flowchart TD
  J["job.json"] --> K{"work_repo_id<br/>registered?"}
  K -->|no| B1["policy-blocked<br/>unknown repo id"]
  K -->|yes| P1["expand path hints"]
  P1 --> R1{"inside<br/>allowed_roots?"}
  R1 -->|no| B2["policy-blocked<br/>unsafe local path"]
  R1 -->|yes| R2["read git remote"]
  R2 --> R3{"remote matches<br/>clone_url?"}
  R3 -->|no| B3["policy-blocked<br/>target mismatch"]
  R3 -->|yes| R4{"base branch<br/>exists?"}
  R4 -->|no| B4["agent-blocked<br/>fetch or clone approval"]
  R4 -->|yes| OK["resolved-state.json<br/>safe to create worktree"]

  classDef input fill:#1c2423,stroke:#86c9bd,color:#f1f1f1;
  classDef decision fill:#252119,stroke:#d1a066,color:#f1f1f1;
  classDef blocked fill:#2b1e1f,stroke:#e98585,color:#f1f1f1;
  classDef ok fill:#1b2030,stroke:#5b8cff,color:#f1f1f1;
  class J,P1,R2 input;
  class K,R1,R3,R4 decision;
  class B1,B2,B3,B4 blocked;
  class OK ok;

Issue Lifecycle

unattended 실행은 단순 label 하나로 시작하지 않습니다. Project Status, execution label, approval label, repo allowlist가 모두 맞아야 합니다.

stateDiagram-v2
  [*] --> Open
  Open --> ReadyForAgent: scope fixed
  ReadyForAgent --> Claimed: approval + execution label
  Claimed --> InDev: resolver passed
  InDev --> PrReady: verification passed
  PrReady --> Done: PR merged or accepted
  InDev --> AgentBlocked: policy or QA failed
  AgentBlocked --> ReadyForAgent: human resolved

Recommended start conditions:

  • Issue is open.
  • Project Status is the configured execution-ready value, for example Ready for Agent.
  • Execution label is present, for example auto-dev.
  • Approval label is present, for example approved-for-agent.
  • Assignee is an allowed actor or team.
  • Target repository and base branch are allowlisted.
  • Repo completion policy inspection has no blockers.
  • No active branch or PR exists for the same issue.
  • No blocking labels such as blocked, manual, needs-spec, unsafe are present.

If Project V2 is inaccessible, the runner should stop. Label-only fallback is allowed only when the target repo explicitly opts into that mode.

Multi-Agent Team

에이전트는 같은 파일을 서로 덮어쓰는 작업자가 아니라, 역할과 종료 조건을 가진 팀입니다.

역할책임종료 조건
Coordinatorissue 분석, resolver 실행, 작업 분해, 최종 통합job contract와 run plan이 남음
Explorer코드 구조, 관련 파일, 기존 패턴 확인affected files와 위험 지점이 정리됨
Worker정해진 파일 또는 모듈 slice 구현변경 범위가 계획 안에 있음
Test Engineerbuild, lint, typecheck, E2E, browser QA 정의성공/실패 로그가 남음
Reviewer변경 범위, policy, PR evidence 검토승인 또는 blocker가 명확함

병렬 에이전트가 필요하면 파일 소유권을 먼저 나눕니다. 작업자가 직접 push, merge, issue close를 수행하지 않게 하고 coordinator가 policy gate를 통과한 뒤 처리합니다.

Safety Gates

작업 전 gate:

  • target repo와 base branch 확인
  • local resolver path와 remote URL 확인
  • unrelated dirty worktree 변경 확인
  • Project Status와 approval label 확인
  • package install, scheduler 등록, secret 접근 필요 여부 확인

PR 전 gate:

  • target repo verification command 실행
  • diff와 changed files 확인
  • completion git policy inspection 저장
  • PR 본문에 issue link, 테스트, 위험, 미해결 항목 기록
  • issue close는 merge 이후 또는 target repo 정책에 따름

blocked by default:

  • package install without approval
  • cron, LaunchAgent, Windows scheduled task 등록
  • secret, token, credential file 접근
  • destructive reset, protected branch mutation
  • repo policy 없이 commit, push, merge

BISFramework Reference Case

BISFramework는 이 모델의 첫 적용 후보입니다.

항목현재 관찰값
control_repocodecleanup-dev/keystone-hub
issue_repoMAESTRO-BS/BisFramework
work_repoMAESTRO-BS/BisFramework
work_repo_idbis-framework
base_branchdev
local path example/Users/choa712-mac/dev-bs/BisFramework/BisFramework-master

현재 BISFramework는 GitHub Project 2026 Development RoadmapReady -> In Dev 운영 신호를 갖고 있습니다. 다만 unattended recurring 실행에는 아직 명시적인 approval label gate와 repo-local git policy가 더 필요합니다.

Typical verification:

npm run typecheck
npm run lint
npm run build
npm run validate-menus
npm run test:e2e

UI 변경이면 Vite dev server를 띄운 뒤 http://localhost:5173 기준으로 browser QA를 수행합니다.

Operator Runbook

  1. Issue를 고릅니다.

    • Project Status, approval label, assignee, blocking label을 확인합니다.
  2. Target repo를 resolve합니다.

    • work_repo_id를 local path로 바꾸고 remote URL과 base branch를 확인합니다.
  3. Issue를 claim합니다.

    • agent-running 또는 동등한 상태를 남기고 run id, branch name을 comment로 남깁니다.
  4. 격리된 작업 공간을 만듭니다.

    • feature branch 또는 worktree를 사용합니다.
  5. 에이전트를 dispatch합니다.

    • Explorer, Worker, Test Engineer, Reviewer의 책임을 분리합니다.
  6. 검증합니다.

    • target repo command를 실행하고 artifact를 저장합니다.
  7. PR을 준비합니다.

    • repo policy가 허용할 때만 push하고 PR 본문에 evidence를 남깁니다.
  8. 종료합니다.

    • issue는 review state로 옮기고, merge 전 자동 close는 하지 않습니다.

Minimum Artifact Set

각 run은 적어도 아래 artifact를 남깁니다.

  • job.json: portable job contract
  • resolved-state.json: local resolver result
  • status.json: current state, attempts, timeout, heartbeat
  • prompt.md: exact task prompt
  • plan.md: implementation plan
  • changed-files.txt or diff.patch: change evidence
  • verification.log: verification summary
  • completion-policy.json: completion git policy inspection
  • final-report.md: PR-ready summary and residual risks

Adoption Checklist

  • control_repo, issue_repo, work_repo, pr_repo를 정했다.
  • work_repo_id, clone_url, base_branch를 정했다.
  • 머신별 local resolver config를 만들었다.
  • execution-ready Project Status를 정했다.
  • execution label과 approval label을 분리했다.
  • blocking label과 stale approval 기준을 정했다.
  • target repo verification command를 정했다.
  • artifact directory와 run id 규칙을 정했다.
  • worktree, container, branch 중 격리 방식을 정했다.
  • repo-local commit, push, merge policy를 정했다.
  • dry-run issue로 mutation 없이 한 번 검증했다.
  • 낮은 위험도의 PR-only issue로 첫 실행을 끝냈다.