최근 Claude CodeGPT Engineer 같은 고성능 CLI 기반 AI 에이전트가 등장하면서, 개발 워크플로우를 자동화하려는 시도가 급증하고 있습니다. 이슈 트래커에서 할 일을 가져와 AI가 자동으로 코드를 짜고, 테스트한 뒤 깃허브에 PR(Pull Request)까지 올리는 파이프라인은 이제 현실이 되었습니다.

사실 처음에는 Jira와 Linear의 깊은 차이점을 알지 못했고, 그저 "AI 에이전트랑 붙이기에는 Linear가 훨씬 좋다"는 얘기만 듣고 시작하신 분들이 많을 것입니다.

하지만 직접 파이프라인을 구축하고 구동해 보면 왜 다들 입을 모아 Linear를 극찬하는지 그 이유를 명확히 알게 됩니다. 결론부터 말씀드리면, AI 자동화 측면에서 Jira 대신 Linear를 선택한 것은 신의 한 수입니다. 어떤 면에서 압도적인 장점이 있는지 핵심 요소를 정리해 드립니다.


1. AI가 이해하기 가장 좋은 '단순하고 명확한 API' (GraphQL)

AI 에이전트가 개발을 자동화하려면 이슈 트래커의 데이터를 API로 읽고(Read) 상태를 변경(Write)할 수 있어야 합니다. 이때 API의 복잡도는 AI의 작업 성공률과 직결됩니다.

  • Atlassian Jira: 수많은 대기업의 다양한 워크플로우를 수용하다 보니 데이터 구조가 극도로 비대하고 무겁습니다. 필드 하나를 수정하려 해도 커스텀 필드 ID, 화면 구성, 워크플로우 권한(Transition) 규칙을 모두 만족해야 합니다. AI가 복잡한 Jira API를 다루다 보면 Context 토큰을 과도하게 소모하고, 잦은 예외 에러를 마주하기 쉽습니다.
  • Linear: 처음부터 현대적인 소프트웨어 빌더들을 위해 설계된 도구답게 GraphQL API를 기본으로 지원합니다. 데이터 구조가 매우 정제되어 있고 직관적입니다. AI 에이전트 입장에서는 최소한의 토큰만 사용하여 정확하게 이슈를 조회하고, 필요한 필드만 깔끔하게 업데이트할 수 있는 최적의 환경을 제공합니다.

2. 고속 AI 에이전트의 속도를 받쳐주는 '초고속 성능'

Claude Code는 터미널 환경에서 실시간으로 코드를 분석하고 실행하는 고속 AI 에이전트입니다. 자동화 스크립트가 매끄럽게 돌기 위해서는 이슈 트래커의 응답 속도(Latency)가 매우 중요합니다.

Jira를 사용할 때 웹 UI가 무겁게 리로드되는 경험을 다들 해보셨을 겁니다. 이는 API 응답 속도에서도 비슷하게 나타납니다. 반면, Linear의 핵심 철학은 '무조건 빨라야 한다(As fast as light)'입니다. 로컬 중심의 캐싱과 최적화된 초고속 API 덕분에 AI 에이전트가 Linear의 이슈 상태를 확인하거나 댓글을 달 때 지연 시간이 거의 없습니다. 덕분에 전체 자동화 흐름이 끊기지 않고 물 흐르듯 이어집니다.


3. GitHub과의 유기적인 삼각편대 (Webhook 최소화)

AI 에이전트가 작업을 마치면 최종 결과물은 결국 GitHub(또는 GitLab)의 PR(Pull Request)로 이어집니다. 이때 Linear는 브랜치 이름 규칙이나 PR 본문의 키워드 생성(linear-issue-id)만으로도 완벽한 상호 연동을 지원합니다.

  • Jira: GitHub과의 연동을 위해 복잡한 통합 앱을 설정하고 웹훅 규칙을 정교하게 맞춰야 하며, 가끔 상태 동기화가 밀리는 현상이 발생합니다.
  • Linear: Claude Code가 코드를 수정한 뒤 깃 브랜치나 PR에 이슈 ID를 포함하여 날리면, 별도의 복잡한 파이프라인 설정 없이도 [Linear 이슈 확인 → 코드 수정 → GitHub PR 생성 → Linear 이슈 자동 완료]로 이어지는 완벽한 자동화 삼각편대가 즉시 완성됩니다.

4. 도구에 매몰되지 않는 개발자 중심 UX

Jira는 기획자, PM, 디자이너, 심지어 인사팀이나 경영진까지 회사 내 '모든 부서'를 만족시키기 위해 거대해진 도구입니다. 개발자나 AI 입장에서는 불필요한 노이즈가 너무 많죠.

반면 Linear는 철저히 '소프트웨어를 만드는 엔지니어링 팀'에만 집중합니다. 백로그 관리, 사이클(스프린트), 로드맵 구조가 개발 프로세스 모범 사례(Best Practice)에 딱 맞게 정제되어 있습니다. 따라서 AI에게 복잡한 예외 처리를 프롬프트로 줄 필요 없이, *"현재 사이클에서 미완료된 태스크를 가져와서 분석해줘"*라는 단순한 명령만으로도 AI가 맥락을 완벽하게 이해하고 작업을 시작할 수 있습니다.


💡 요약하자면

Jira가 회사의 모든 비즈니스 프로세스와 커스텀 규칙을 담아내는 거대한 '성(Castle)'이라면,
Linear는 개발자와 AI가 오직 최고 속도로 소프트웨어를 빌드하고 배포하기 위해 최적화된 '레이싱 카(Racing Car)'입니다.

잘 모르고 추천을 받아 시작한 조합(Linear + Claude Code)이었을지라도, 결과적으로는 현시점 AI 개발 자동화 생태계에서 가장 트렌디하고 효율적인 정답 조합을 찾아내신 것입니다.

도구의 복잡성에 에너지를 쏟는 대신, Linear의 극도로 정제된 환경 위에서 Claude Code와 함께 압도적인 생산성을 경험해 보세요!

이슈 하나를 Linear에 등록하면 — 기획, 개발, 보안 점검, 배포까지 AI가 자동으로 처리한다


들어가며

개발 팀이 아니어도 서비스를 만들 수 있을까? 이 질문에서 이 프로젝트가 시작됐습니다.

아이디어를 Linear 이슈로 작성하면, Claude Code가 자동으로 개발 플랜을 세우고, GitHub 레포를 만들고, 코드를 짜고, 보안 점검까지 마친 뒤, Synology NAS에 배포할 수 있는 Dockerfile까지 생성해줍니다. 사람이 하는 일은 이슈 작성과 중간 중간 단계 승인(Linear 상태 변경)뿐입니다.

이 글에서는 그 전체 구조와 구현 과정을 최대한 상세하게 정리합니다.


전체 아키텍처

파이프라인은 Linear 이슈 상태를 트리거로 삼습니다. 상태가 바뀌는 순간 Node.js 폴링 모니터가 감지하고, 해당 상태에 맞는 Claude Code 스킬을 실행합니다.

[ Linear 이슈 생성 ]
        ↓ 상태: Todo
  📋 플랜 작성 & Plan Review 이동
        ↓ (사람이 검토 후) 상태: Develop
  💻 코드 개발 & PR 생성 & Test 이동
        ↓ (사람이 테스트 후) 상태: Security Audit
  🔒 보안 점검 (SAST + DAST) & Security Review 이동
        ↓ (사람이 보안 검토 후) 상태: Reviewed
  🎉 PR Merge + Dockerfile 생성 + Done 이동

각 단계마다 Slack 알림이 오고, Linear 이슈에 상세 댓글이 달립니다.


프로젝트 구조

/workspace/linear-pipeline/
├── linear-monitor.js      # Linear API 폴링 + 스킬 실행 (핵심)
├── skills/
│   ├── skill-02-todo-detect.md      # 플랜 작성
│   ├── skill-05-develop.md          # 코드 개발
│   ├── skill-08-security-audit.md   # 보안 점검
│   └── skill-11-reviewed-merge.md   # Merge & Dockerfile
├── state/                 # 이슈별 컨텍스트 JSON 파일
├── logs/                  # 스킬 실행 로그
└── .env                   # API 키 및 상태 ID 설정

의존 패키지는 dotenv 하나뿐입니다. 나머지는 모두 Node.js 내장 모듈(https, child_process, fs)로만 구현했습니다.


트리거 방식: 폴링 모니터 (linear-monitor.js)

linear-monitor.js는 Linear GraphQL API를 주기적으로 쿼리해 처리 대상 이슈를 감지합니다. Cron으로 5분마다 실행됩니다.

const ROUTE = {
  'Todo'           : 'skill-02-todo-detect.md',
  'Develop'        : 'skill-05-develop.md',
  'Security Audit' : 'skill-08-security-audit.md',
  'Reviewed'       : 'skill-11-reviewed-merge.md',
};

최근 24시간 이내에 업데이트된 이슈 중 위 4개 상태에 해당하는 것만 조회합니다.

// 최근 24시간 이내 업데이트된 이슈만 조회
const since = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();

중복 실행 방지 로직:

  • lastTriggeredAt 기록 → 30분 이내면 스킵
  • lastCompletedAt 기록 → 완료 후 새 변경(댓글 등)이 없으면 스킵
  • 30분 초과 시 타임아웃으로 간주하고 재실행

댓글로 새 활동이 감지되면 해당 이슈의 현재 상태 스킬을 재실행합니다. 이를 통해 "댓글로 수정 요청 → 자동 재개발"이 가능합니다.


이슈별 상태 저장: JSON 파일

각 이슈의 컨텍스트는 state/{issueId}.json에 저장됩니다. 파이프라인의 각 단계가 다음 단계에 필요한 정보를 이 파일을 통해 전달합니다.

{
  "issueId": "abc-123",
  "identifier": "JOS-15",
  "title": "개인정보 처리방침 페이지",
  "branchName": "feature/JOS-15-privacy-policy",
  "prNumber": 3,
  "prUrl": "https://github.com/...",
  "testCommentUrl": "https://linear.app/...",
  "stack": "nextjs",
  "port": 3001,
  "devUrl": "http://***.freeddns.org",
  "lastCompletedState": "Develop",
  "lastCompletedAt": "2026-06-04T12:00:00Z"
}

프로젝트별 고정 포트 관리

개발 서버는 10개의 포트(3001~3010)를 사용합니다. 한 프로젝트는 항상 같은 포트를 씁니다. _port_map.json에 영구 저장됩니다.

{
  "Privacy Policy": 3001,
  "SearchMissa": 3004
}

각 포트는 역방향 프록시로 외부 도메인에 연결되어 있어, 어느 프로젝트든 개발 완료 즉시 URL로 확인할 수 있습니다.


Claude Code 스킬 실행 방식

스킬은 마크다운 파일입니다. 모니터가 스킬 파일 내용을 읽어 Claude Code의 프롬프트로 전달합니다.

const prompt = `다음 스킬 파일의 지시사항을 처음부터 끝까지 모두 실행하라.
단계를 건너뛰지 말고 순서대로 실행하라.

---
${skillContent}`;

const child = spawn('/usr/bin/claude', [
  '--print',
  '--dangerously-skip-permissions',
  prompt,
], {
  env: { ...process.env, ...envVars },
  detached: true,
});

이슈 ID, 제목, 브랜치명, PR URL 등 컨텍스트는 환경변수로 주입됩니다. Claude Code는 이 환경변수들을 쉘 명령어($ISSUE_ID, $BRANCH_NAME 등)로 바로 사용합니다.


Step 1: Todo → 플랜 작성 (skill-02-todo-detect.md)

이슈가 Todo 상태가 되면 실행됩니다.

동작 순서:

  1. Linear GraphQL API로 이슈 상세 조회 (제목, 설명, 레이블, 우선순위)
  2. 이슈 분석 후 개발 플랜 작성
  3. Linear 이슈에 플랜 댓글 등록
  4. Linear 상태를 Plan Review로 변경
  5. Slack으로 "플랜 리뷰 요청" 알림 전송

작성되는 플랜 형식 예시:

## 📋 개발 플랜 — JOS-15: 개인정보 처리방침 페이지

### 이슈 분석
- 유형: feature
- 우선순위: medium
- 예상 복잡도: Low

### 구현 전략
1. Next.js App Router 기반 정적 페이지 구현
2. /privacy-policy 라우트 추가
3. 마크다운 렌더링 또는 정적 HTML

### Feature Branch 명
feature/JOS-15-privacy-policy

### 완료 기준 (Definition of Done)
- [ ] 기능 구현 완료
- [ ] 개발 서버 동작 확인

💡 설명이 없는 이슈는 제목만으로 최소 플랜을 작성하고 "⚠️ 이슈 설명을 보완해주세요"를 추가합니다.


Step 2: Develop → 전체 개발 워크플로우 (skill-05-develop.md)

이슈가 Develop 상태가 되면 실행됩니다. 가장 복잡한 스킬입니다.

이슈 전체 맥락 로드

이슈 본문뿐 아니라 모든 댓글을 시간순으로 읽습니다. 플랜 댓글, 피드백, 수정 요청이 모두 포함됩니다.

ALL_COMMENTS=$(jq -r '
  .data.issue.comments.nodes[] |
  "---\n작성자: \(.user.name)\n시간: \(.createdAt)\n\n\(.body)\n"
' /tmp/issue_full.json)

상충되는 댓글이 있으면 가장 최근 댓글을 우선합니다.

GitHub Repo 자동 생성

프로젝트 폴더가 없으면 GitHub API로 private 레포를 만들고 clone합니다. 이미 있으면 최신 상태로 pull합니다.

기술 스택 자동 판단

이슈 키워드로 스택을 결정합니다:

키워드 선택 스택
"웹사이트", "페이지", "UI", "화면" Next.js
"API", "백엔드", "서버", "REST" Express
"크롤링", "스크래핑", "자동화" Python
판단 불가 Next.js (기본값)

개발 서버 자동 오류 수정 루프

서버가 정상 응답할 때까지 오류를 분석하고 수정합니다. 시도 횟수에 제한이 없습니다.

while true; do
  서버 시작 시도
  90초 대기 (HTTP 응답 확인)

  응답 성공 → break
  응답 실패 → 로그 분석 후 자동 수정
done
오류 패턴 자동 수정 방법
Cannot find module npm install 실행
EADDRINUSE (포트 충돌) fuser -k 포트/tcp 후 재시도
TypeScript / ESLint 빌드 오류 코드 파일 직접 수정
ModuleNotFoundError (Python) pip install 실행
.env 없거나 값 오류 .env 파일 생성 또는 수정
동일 오류 반복 다른 접근 방법 시도

🚨 즉시 중단 & 사람 알림 조건
API 키·DB 비밀번호 없음 / 외부 서비스 미응답 / 시스템 패키지 설치 필요 / 동일 오류 5회 이상 반복
→ Linear 댓글 + Slack 알림 후 중단. 문제 해결 후 댓글을 남기면 자동 재시작.

PR 생성 및 이후 처리

  1. Feature Branch commit & push
  2. GitHub PR 생성 (본문에 이슈 링크, 개발 서버 URL, 반영된 댓글 수 포함)
  3. 수동 테스트 체크리스트 Linear 댓글 등록
  4. Linear 상태를 Test로 변경
  5. Slack에 "개발 완료 — 테스트 요청" 알림

Step 3: Security Audit → 보안 점검 (skill-08-security-audit.md)

이슈가 Security Audit 상태가 되면 SAST → SCA → DAST 순으로 자동 보안 점검이 실행됩니다.

SAST: Semgrep 정적 분석

semgrep scan \
  --config "p/owasp-top-ten" \
  --config "p/cwe-top-25" \
  --config "p/secrets" \
  --json \
  --output /tmp/semgrep_result.json \
  $PROJECT_ROOT

OWASP Top 10, CWE Top 25, 시크릿 탐지 룰셋을 적용합니다.

SCA: 의존성 취약점 분석

# Node.js 프로젝트
npm audit --json > /tmp/sca_result.json

# Python 프로젝트
pip-audit -r requirements.txt --format json

DAST: OWASP ZAP 동적 분석

Docker가 설치된 환경이면 ZAP 컨테이너로 자동 스캔합니다. 없으면 curl로 수동 점검을 수행합니다:

# 보안 헤더 확인
curl -sI "$TARGET" | grep -iE \
  "x-frame-options|content-security-policy|strict-transport|x-xss-protection"

# 민감 경로 탐색
for path in /.env /.git/config /admin /swagger; do
  STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$TARGET$path")
  echo "$path → $STATUS"
done

# SQL Injection / XSS 기초 탐지
curl -s "$TARGET/?id=1'" ...
curl -s "$TARGET/?q=<script>alert(1)</script>" ...

통합 진단보고서

구분 상(High) 중(Medium) 하(Low)
SAST (소스코드) 0 2 5
DAST (모의해킹) 0 1 3
SCA (의존성) 0 0
합계 0 3 8

취약점 수에 따라 종합 위험도를 판정합니다: 🔴 상(HIGH) / 🟠 중(MEDIUM) / 🟢 양호

보고서 등록 후 상태를 Security Review로 변경하고 Slack 알림을 전송합니다.


Step 4: Reviewed → Merge & Dockerfile & Done (skill-11-reviewed-merge.md)

이슈가 Reviewed 상태가 되면 마지막 단계가 실행됩니다.

동작 순서:

  1. PR Merge 가능 여부 확인: Mergeable 상태를 GitHub API로 확인
  2. Squash Merge: 깔끔한 커밋 히스토리 유지
  3. Feature Branch 삭제: 자동 정리
  4. Dockerfile 자동 생성: 프로젝트 유형을 자동 감지해 멀티스테이지 빌드 Dockerfile 생성
  5. 배포 가이드 Linear 댓글 등록: Synology NAS Container Manager + DSM 역방향 프록시 설정 방법 상세 안내
  6. Linear 상태 Done으로 변경
  7. Slack 완료 알림 🎉

Dockerfile 자동 감지 기준

감지 조건 생성되는 Dockerfile
package.json에 "next" Next.js 멀티스테이지
package.json에 "express" Node.js 멀티스테이지
requirements.txt 존재 Python (gunicorn)
go.mod 존재 Go (scratch 베이스)

배포 환경: Synology NAS

이 파이프라인 자체는 Synology NAS의 Container Manager 위에서 돌아갑니다.

외부 HTTPS 요청
    ↓
DSM 역방향 프록시 (SSL 종단, Let's Encrypt)
    ↓
Docker 컨테이너 (linear-pipeline)
    ↓
Claude Code 프로세스 (스킬 실행)
    ↓
개발 서버 컨테이너 (포트 3001~3010)

NAS에서 제공하는 Let's Encrypt 인증서로 HTTPS를 처리하기 때문에, 내부는 HTTP로 통신하지만 외부에는 HTTPS로 노출됩니다.


실제 동작: Slack 알림 흐름

① Todo → Plan Review

📋 플랜 리뷰 요청
이슈: [JOS-15] 개인정보 처리방침 페이지
상태: Todo → Plan Review
[📝 플랜 보기] 버튼

② Develop → Test

✅ 개발 완료 — 테스트 요청
프로젝트: Privacy Policy
이슈: [JOS-15] 개인정보 처리방침 페이지
개발 서버: http://test1.joseph84.freeddns.org
스택: nextjs (포트: 3001)
[🧪 테스트 가이드] [🌐 개발 서버] [🔀 PR 보기]

③ Security Audit → Security Review

🟢 보안 점검 완료 — 리뷰 요청
종합 판정: 🟢 양호
SAST: 상 0 / 중 1 / 하 3
DAST: 상 0 / 중 0 / 하 2
[📋 진단보고서] [🔀 PR 보기]

④ Reviewed → Done

🎉 개발 완료 — Done
이슈: [JOS-15] 개인정보 처리방침 페이지
Merge: a1b2c3d (Squash)
Dockerfile: nextjs 유형 생성 완료

구현하면서 마주친 문제들

문제 1: 스킬 실행 중에 다음 폴링 사이클이 중복 실행된다

스킬 하나가 수십 분씩 걸립니다. lastTriggeredAt 타임스탬프를 상태 파일에 기록하고, 30분 이내면 스킵하는 방식으로 해결했습니다.

문제 2: 개발 서버가 빌드 오류로 시작을 못 한다

무제한 재시도 루프를 설계했습니다. Claude Code가 로그를 읽고 패키지 설치, 코드 수정, 포트 변경 등을 자율적으로 수행합니다. 정말 해결 불가능한 경우(외부 API 키 없음 등)만 사람에게 알립니다.

문제 3: 댓글로 수정 요청이 오면 처음부터 다시 해야 한다

TRIGGER 환경변수와 BRANCH_NAME 환경변수를 체크해서, 이미 브랜치가 있으면 코드 개발 단계를 건너뛰고 서버 구동 단계부터 재실행합니다.

문제 4: 프로젝트가 여러 개면 포트가 겹친다

_port_map.json에 프로젝트명 → 포트 번호를 영구 저장해 한 프로젝트는 항상 같은 포트를 사용하도록 했습니다.


Linear 상태 흐름 전체 정리

사람이 개입하는 지점은 단 4곳입니다:

# 사람이 하는 일 그 이후 자동 처리
1 Linear에 이슈 작성 플랜 자동 작성 → Plan Review
2 플랜 검토 후 Develop으로 이동 코드 개발 → PR 생성 → Test
3 기능 테스트 후 Security Audit으로 이동 SAST + DAST 보안 점검 → Security Review
4 보안 검토 후 Reviewed로 이동 PR Merge + Dockerfile + Done

마치며

이 파이프라인을 만들면서 가장 놀랐던 점은, 스킬 파일(마크다운)이 단순히 프롬프트가 아니라 실행 가능한 워크플로우 정의처럼 동작한다는 것입니다. Claude Code가 bash 명령어를 직접 실행하고, API를 호출하고, 오류를 만나면 코드를 고치고 다시 시도합니다.

물론 아직 한계도 있습니다. 복잡한 비즈니스 로직이나 외부 서비스 연동이 많은 프로젝트는 여전히 사람의 손이 많이 필요합니다. 하지만 랜딩 페이지, 정책 페이지, 간단한 API 서버 같은 프로젝트는 이슈 작성 후 거의 손대지 않고 배포 직전까지 도달할 수 있었습니다.

이 글이 유용하셨다면 공감 부탁드립니다. 궁금한 점은 댓글로 남겨주세요.

+ Recent posts