아직도 버그를 직접 해결하시나요?

사람은 결정만, 나머지는 킬버그가 알아서 합니다.

Nari 🔅 • FE

  • 엔지니어링

채널 Web-Core 팀원으로서 Feature 팀이 더 빠르고 안정적으로 제품을 개발할 수 있도록 기반을 만들어가는 일을 담당하고 있는 엔지니어 나리입니다!

버그가 올라오는 팀메신저 방을 한 번 떠올려볼까요?

매일 팀메신저에 쌓이는 수많은 버그 제보들을 보며, 팀원들이 어느 팀 이슈인지 판단하고 담당자를 멘션하고, 일일이 triage 티켓을 생성하느라 시간을 쓰는 것이 아까워보였습니다.

"이 이슈는 Core팀인가요, Feature팀인가요?", "백엔드 쪽에서 봐야 할까요?", "누구 멘션하면 되나요?" 같은 대화로 몇 분씩 소모되는 건 너무 익숙한 풍경입니다. 실제 코드를 수정하는 시간보다, "누가 봐야 하는지 정리하는 시간"이 더 길어지는 경우도 많습니다. 이 시간을 아낄 수 있다면 문제를 이해하고 코드를 수정하는 일 자체에 최대한 집중할 수 있겠다는 생각이 들었습니다

그래서 저는 버그가 채팅방에 올라오는 순간부터 담당자 멘션 → 티켓 생성 → 코드 수정 → PR 생성까지를 최대한 자동으로 연결해주는 워크플로우를 만들었고, 내부적으로 "킬버그(Kill Bug) 🐞"라고 명명하였습니다.

이 글에서는 킬버그에 대한 배경과 구현 과정을 공유해보려고 합니다!

우리가 불편했던 것들

버그를 처리하는 기존 흐름은 대략 다음과 같았습니다.

  1. 채널 팀챗 버그 방에 제보가 올라온다.

  2. 누군가가 내용을 읽고

    • 어느 Feature/팀 이슈인지,

    • 프론트인지 백엔드인지,

    • 누구를 멘션해야 할지 수동으로 판단한다.

  3. 담당자가 "이거 제가 볼게요" 라고 말한 뒤,

    • Linear에 티켓을 만들고,

    • 버그챗 링크와 재현 방법을 옮겨 적는다.

  4. 그제서야 코드를 살펴보고, PR을 만들고, 다시 버그방에 진행 상황을 공유한다.

위 흐름에서 진짜 개발 작업은 마지막 단계에 불과합니다.

이 과정에서 실제 개발이 아닌 앞단의 triage 생성·전달·정리 단계가 상당한 비중을 차지하고 있었습니다. 해당 단계들은 대부분 반복 가능한 패턴을 가지고 있음에도, 매번 사람이 직접 판단하고 정리해야 했습니다. 특히 팀에 합류한 지 얼마 되지 않은 구성원의 경우, 해당 문제가 어떤 팀 이슈인지 파악하는 것 자체가 큰 진입 장벽으로 작용했습니다. 또한 triage를 생성하려면 스레드 전체의 맥락을 이해한 뒤 내용을 재구성해야 했기 때문에, 매번 수작업으로 정리하는 비용이 발생했습니다.

이러한 비효율을 줄이고, 이슈가 보다 빠르게 개발 단계로 이어질 수 있도록 다음과 같은 목표를 설정했습니다

  • 버그가 채팅방에 올라오는 순간부터, '누가 어떤 코드베이스를 어떻게 손봐야하는지' 까지를 최대한 자동으로 연결하자.

  • 사람은 진짜 어려운 판단에만 개입하게 만들자.

전체 아키텍처 한눈에 보기

킬버그의 흐름은 크게 네 단계로 나눌 수 있습니다.

Step 1️⃣. 버그 방 → 담당자 자동 멘션

Step 2️⃣. '킬버그 트리아지' 명령어로 Linear 티켓 자동 생성

Step 3️⃣. Linear에서 Cursor 호출 → 코드 분석 & PR 자동 생성

Step 4️⃣. PR 생성 결과를 다시 버그방 스레드에 피드백

각 단계마다 LLM과 Notion/Linear API를 연결해 맥락을 점점 풍부하게 만들어 가는 구조입니다.

킬버그 n8n 워크플로우

Step 1. 버그가 올라오면, LLM이 "어느 팀 이슈인지" 먼저 판단한다.

1-1. 버그 메시지 정제하기

버그 방에 메시지가 올라오면, Channel Webhook이 n8n 워크플로우를 호출합니다.

채널 ID, 그룹 채팅 여부, 스레드 여부, 담당자 메시지 여부를 필터링 하여 담당자를 멘션하고 싶은 메시지만 통과시킵니다. 이후 원문 plainText에서 불필요한 공백, @멘션, 이모지를 정리해 LLM이 읽기 좋은 형태의 버그 리포트 텍스트로 만듭니다. 이 단계는 단순 전처리지만, 컨텍스트 엔지니어링 관점에서 중요한 작업입니다. 지저분한 텍스트 대신, 버그 상황에 집중된 문장만 넘겨야 이후 판단이 안정적으로 이어집니다.

1-2. Notion DB를 킬버그 Config로 사용하기

어느 팀이 이슈를 봐야하는지 판단하려면, Feature 정의와 담당자 정보가 필요합니다.

이걸 코드에 상수로 박아두면 많은 사람들이 정보를 쉽게 추가 및 삭제하기 어려워집니다. 그래서 채널 팀원이라면 누구나 접근할 수 있는 Notion에 두 개의 데이터베이스를 만들었습니다.

  • Feature Config DB

    • Feature (예: Web , Front , Meet , ... )

    • Keyword (예: '둥둥이', '채널톡 버튼', '플러그인', '채팅 위젯', ... )

    • Include Description , Exclude Description

    • FE Manager List , BE Manager List (예: Nari-{매니저 id})

  • Repository Config DB

    • TeamKey : Linear에서 사용하고 있는 TeamKey

    • Repository (예: channel-io/ch-desk-web )

Notion에서 Feature DB를 파싱해, LLM에게 넘길 거대한 프롬프트 조각을 생성합니다. 이 부분이 AI에게 건네는 도메인 온톨로지 역할을 합니다.

1-3. 어느 팀 버그인지를 LLM이 결정

이제 아래 입출력으로 LLM이 호출됩니다.

Plaintext
입력
- 정제된 버그 리포트
- Notion에서 파싱한 Feature 구조, 키워드, 담당자 목록
- FE/BE 판단 규칙, 가이드 등 상세한 룰
출력
- feature: ["Web", ... ]
- isFE: true/false
- managers: [{name: "Nari", id: "512260"}, ... ]
- reason: 판단 근거 설명

여기서 중요한 점은 "애매하면 비워라"는 규칙을 강하게 걸어둔 것입니다.

  • 애매하면 feature: [], managers: [] 로 응답

  • 키워드가 들어갔다고 무조건 그 feature라고 단정하지 말 것

    → 키워드보다는 문제 발생 지점이 어떤 feature 담당인지를 판단할 것

이렇게 해서 LLM이 잘못된 팀에 멘션을 난사하는 것을 방지할 수 있었습니다.

1-4. 담당자 멘션 메시지 만들기

LLM이 출력해준 결과를 가지고 다음 두 가지 케이스를 나눕니다.

  1. 어느 Feature/담당자인지 명확할 때

    • 해당 버그 스레드에 담당자를 멘션하고

    • 판단 사유를 전송합니다.

  2. Feature는 알겠지만 담당자가 비어있을 때

    • 이 Feature의 담당자가 설정되어 있지 않으니, Notion Kill Bug Config를 업데이트해 달라는 안내 메시지와

    • Notion DB 링크 버튼을 전송합니다.

또한, 스레드에서 이미 특정 팀/사람이 멘션되어있는 경우를 필터링해, 중복 멘션 하지 않도록 하였습니다.

결과적으로, 버그가 올라온 직후 수 초 안에 "누가 볼지"가 정리된 상태로 스레드가 시작되게 됩니다.

STEP 2. 킬버그 트리아지 한 줄로 Linear 티켓까지 자동 생성

담당자가 버그 내용을 검토하다가 "이건 진짜 우리 팀이 바로 처리해야겠다"고 판단하면, 버그 스레드에 다음과 같이 입력합니다.

킬버그 web 트리아지

2-1. 명령어 파싱 해서 팀 매핑하기

  • 킬버그 트리아지 메시지를 webhook을 통해 n8n으로 받습니다.

  • Linear GraphQL로 모든 팀 목록(name, key)을 가져옵니다.

  • 킬버그 web 트리아지에서 web 을 뽑아내고,

  • Linear 팀 목록에서 key 가 일치하는 팀을 찾습니다.

  • 유효한 팀을 찾지 못하면,

    • 킬버그 web 트리아지 처럼 써달라는 가이드를 스레드에 보냅니다.

    • 킬버그 팀목록 을 입력하면, 사용할 수 있는 팀 목록을 스레드에 보냅니다.

위 과정을 거치도록 팀을 직접 텍스트로 입력하게 하였습니다. 왜냐하면, "이 버그를 어떤 Linear 팀 티켓으로 관리할지"는 사람이 의도적으로 선택할 영역이라고 판단했고, 팀 구조는 자주 바뀔 수 있는 데이터에 속했기 때문입니다.

2-2. 스레드 전체 대화로 버그 상황 재분석하기

단순히 원본 버그 메시지만 가지고 티켓을 만들면 맥락이 부족할 수 있습니다. 그래서 스레드에 있는 전체 대화를 가져와서 LLM을 호출합니다.

Plaintext
입력
- 루트 버그 메시지
- 스레드 댓글
출력
- analysis: 추가 맥락 및 종합 분석

LLM에게 버그가 정확히 어떤 상황이고, 어떤 팀이 책임져야하는지를 문서 수준으로 정리시키는 단계입니다.

2-3. LLM이 Linear 티켓 초안 작성하기

위 분석 결과를 기반으로 Linear 티켓 스펙을 채웁니다.

Plaintext
- title
- description
- resolution: 어떻게 해결하면 좋을지 제안
- priority
- rootMessageId, groupId, teamId

LLM이 채워준 스펙으로 Linear API를 호출해 실제 티켓을 생성합니다.

티켓이 생성되고나면, Linear 이슈 링크 버튼을 해당 스레드 댓글로 전송합니다.

여기까지가 사람이 한 일은 "킬버그 web 트리아지" 한 줄 뿐입니다.

STEP 3. Linear ↔ Cursor 연동으로 코드를 분석하고 자동으로 PR을 생성한다.

버그 티켓이 생성되었다고 해서 일이 끝난 것은 아닙니다. 이제 실제 코드베이스를 보고 원인 코드와 패치를 찾는 것이 필요합니다.

채널에서는 기존에도 Linear에 Cursor를 연동해서 원인 코드 찾는 데에 사용하고 있었습니다. 하지만 사람이 직접 해당 티켓에 댓글을 달아서 호출해야했기에 충분히 활용되고 있지 못 했습니다. 그래서 킬버그 워크플로우로 만들어진 티켓에는 자동으로 Cursor가 호출될 수 있도록 하였습니다.

3-1. 어떤 레포를 봐야할 지 Notion DB로 관리하기

앞서 말했듯이 Repository Config DB가 있습니다. Linear 티켓이 속한 팀 키를 기준으로 어떤 레포지토리들을 Cursor에게 넘겨야 할지를 전적으로 Notion에서 제어할 수 있게 됩니다.

팀 구조/레포 구성이 바뀌어도 워크플로우는 손대지 않고 Notion만 수정하면 됩니다.

3-2. Cursor에게 맥락 많은 한 방짜리 프롬프트 던지기

Cursor를 호출할 때 사용되는 정보는 다음과 같습니다.

Plaintext
- Linear 이슈 정보
- TeamKey에 대응하는 레포지토리 목록
- 스레드 댓글로 버그 분석 결과에서 가져온 analysis

본문에는 다음과 같은 내용을 포함시켰습니다.

Plaintext
- 이 레포지토리 안에서 버그 원인과 관련된 코드를 찾아라
- 해결 방법을 제안해라
- confidence(0~1)를 계산하고, 0.8이상이면 코드를 직접 수정해서 PR을 생성해라
- 0.8미만이면 코드는 건드리지 말고, 의심 구간과 아이디어만 정리해라

이 내용들을 Linear GraphQL commentCreate를 호출해서 실제 Linear 이슈에 Cursor를 멘션한 댓글을 남깁니다.

Cursor에게는 프롬프트 한 줄이 아닌,

  • 정확한 이슈 링크

  • 스레드 기반 버그 분석 요약

  • 레포지토리 목록

  • 행동 규칙

을 한 번에 넘겨주게 되는 것입니다.

3-3. Cursor가 남긴 결과물을 다시 읽어, PR 생성 여부/내용을 해석하기

이제 Linear쪽에서는 Cursor가 브랜치를 만들고 코드를 수정하고 PR까지 생성한 뒤 그 내용을 Linear 댓글로 남깁니다.

이를 다시 워크플로우로 받아오기 위해, Linear Comment Webhook 노드를 구성했습니다.

  1. Cursor Comment만 필터링

    • actor.id 가 Cursor인 이벤트만 통과시킵니다.

  2. 킬버그에 의한 issue만 필터링

    • Linear Issue Description 을 가져와서

    • 해당 이슈가 KillBug가 만든 티켓인지 확인합니다.

    • KillBug가 티켓을 만들 때는 Issue Description에 made by. @KillBug 를 남기도록 하여서 Description을 확인하면 KillBug가 만든 티켓임을 확인할 수 있습니다.

  3. Cursor Comment 워싱

    • LLM이 Cursor가 남긴 댓글과 Linear 이슈 Description을 입력받아

    • 다음을 출력해줍니다.

      • isSolved PR 생성 및 문제 해결 여부

      • prLink GitHub PR 링크

      • howToSolve 어떻게 해결했는지 요약

  4. PR 생성했는가?

    • isSolved: true 인 경우에만 다음 단계로 진행합니다.

  5. 스레드에 Cursor 호출 내용 전송

    • howToSolveprLink 를 사용하여

    • 원래 버그가 올라왔던 스레드에 PR 생성 안내 메시지를 전송합니다.

  6. Triage 상태로 변경

    • PR이 생성되면 티켓이 자동으로 Pending 상태로 바뀌게 되는데,

    • 이를 Triage 상태로 다시 변경합니다.

Step 4. PR 생성 결과를 다시 버그방 스레드에 피드백

결국 버그를 처음 제보한 사람은

  1. 어느 팀이 봐야하는지 모르는 상태에서 메시지를 남기고

  2. 킬버그가 담당자를 멘션해 주고

  3. 킬버그 web 트리아지 한 줄로 티켓을 만든 뒤

  4. 시간이 지나면 같은 스레드에서 고친 방법과 PR 링크까지 확인할 수 있습니다.

컨텍스트 엔지니어링 관점에서의 설계 포인트

이 워크플로우를 만들면서 신경 쓴 지점 몇 가지를 정리하면 다음과 같습니다.

  • 도메인 지식은 코드가 아닌, Notion DB에 두기

    • Feature 정의, 팀 키-레포 매핑, 담당자 목록은 모두 Notion에서 관리합니다.

    • 워크플로우는 Notion을 읽어 LLM 프롬프트를 구성하는 로직만 가집니다.

  • LLM은 판단과 문서화에만 집중시키기

    • 어느 팀/담당자인지 판단

    • 스레드 기반 버그 상황 정리

    • Linear 티켓 설명/해결 방안 작성

    • Cursor가 남긴 댓글을 요약

  • 자동화 범위를 confidence 기반으로 제한하기

    • Cursor에게 0.8이상일 때만 PR 생성하라는 규칙을 줍니다.

  • 모든 단계에서 사람이 개입할 수 있는 훅 남기기

    • TeamKey는 사람이 명시적으로 입력합니다.

    • Notion DB는 누구나 편집이 가능합니다.

    • LLM이 애매해하면 feature/managers 를 비워두도록 설계하였습니다.

이렇게 해두면, LLM이 잘못된 방향으로 폭주하기보다는 사람이 컨텍스트를 설계하고, LLM이 그 위에서 반복 작업을 수행하는 구조가 됩니다.

기대 효과

실제 운영에서 기대하는 효과는 다음과 같습니다.

  • Bug 리드타임 감소

    • "이 버그는 어떤 분이 담당해야하냐"를 두고 오가는 대화가 크게 줄어듭니다.

  • Linear 티켓 품질 균일화

    • description 템플릿과 스레드 기반 분석 덕분에, 티켓마다 맥락 노이즈가 줄어듭니다.

  • 신입/비전문가도 버그를 쉽게 올릴 수 있다.

    • 어떤 팀 이슈인지 몰라도, 자연어로 상황만 설명하면 킬버그가 담당자를 멘션해줍니다.

  • 개발자의 집중 시간 확보

    • 반복 업무에서 해방되고,

    • 코드 이해, 리뷰, 결정에 더 많은 시간을 사용할 수 있습니다.

도입한지 얼마 되지 않았지만, 엔지니어팀뿐만 아니라 디자인 팀에서도 반응이 엄청 좋은 것 같아요 매우 뿌듯합니다

또한 FALF팀에서는 킬버그로 만들어진 PR이 실제로 머지되기까지 하였습니다!

마치며

컨텍스트 엔지니어링 글에서도 언급됐듯이, "AI에게 잘 시키는 법"은 멋진 프롬프트 한 줄이 아니라 맥락을 설계하는 일에 가깝습니다.

이번 킬버그 워크플로우는,

  • Notion으로 도메인 지식을 구조화하고,

  • n8n으로 이벤트 흐름을 연결하고,

  • LLM으로 판단과 문서화를 맡기고,

  • Cursor로 전체 코드를 참조해서 자동으로 수정하되

  • confidence 기반으로 제어하는

하나의 컨텍스트 엔지니어링 파이프라인 사례라고 생각합니다.

앞으로는 자동 생성된 PR에 대한 품질 데이터를 쌓아서 confidence 임계값을 더 정교하게 조정하는 방향도 고민하고 있습니다.

We Make a Future Classic Product