Claude Code Subagents: 안전한 배포를 위한 프로덕션 워크플로우
헤드리스 사이트를 위한 Claude 코드 배포 전 파이프라인
우리는 모든 것을 측정하는 클라이언트를 위해 헤드리스 사이트를 배포한다 -- Core Web Vitals, 스키마 마크업, 접근성 점수, 오가닉 트래픽 변화. 한 번의 잘못된 배포로 몇 개월간 구축한 순위가 떨어질 수 있다. Anthropic이 Claude 코드에서 서브에이전트, 훅, 스킬을 출시했을 때, 우리는 전체 배포 전 파이프라인을 이들 기능 주위로 다시 구축했다.
이 글은 우리의 정확한 설정을 안내한다: .claude/ 디렉토리 구조, 각 서브에이전트 정의, 훅 구성, 그리고 모든 것을 연결하는 스킬 파일들. 우리는 시스템이 포착한 4가지 실제 사건, 우리 규모에서의 ROI 수학, 그리고 이 접근 방식이 여전히 가진 격차를 공유할 것이다.
40% CLS 급증이 프로덕션에도 진행됐다
3주 전. 클라이언트의 블로그 리디자인. 개발 환경에서는 모든 것이 좋아 보였다. 머지했다.
2일 후 그들의 CTO가 Search Console에서 스크린샷을 보냈다. CLS가 모바일에서 0.08에서 0.14로 급증했다. "enterprise billing software"에서 3위였던 페이지들이 8위로 떨어졌다. 수익 영향? 그들은 월 $40,000으로 추정했다.
문제가 뭐였을까? 비동기로 로드되지만 크기 속성이 없는 히어로 이미지. 클래식하다. 우리의 CI는 실제 미리보기 빌드에서 레이아웃 시프트를 확인하지 않았기 때문에 아무것도 포착하지 못했다.
그때 우리는 서브에이전트를 살펴보기 시작했다.
서브에이전트는 자신의 시스템 프롬프트, 도구 접근, 그리고 작업 경계를 가진 부모 세션 내부에서 실행되는 범위가 지정된 Claude 코드 인스턴스다. 훅은 명령이 실행되기 전, 파일 변경 후, 또는 커밋 시에 서브에이전트를 특정 지점에서 트리거한다. 스킬은 Claude에게 특정 작업을 수행하는 방법을 가르치는 재사용 가능한 명령 파일(마크다운)이다.
Anthropic은 2025년 4월 14일에 이러한 기초들과 함께 루틴을 도입하는 리디자인을 배포했다. 우리의 사용 사례를 위해, 순수 서브에이전트와 훅은 각 확인이 언제 실행되고 어떤 컨텍스트를 받는지에 대해 더 세밀한 제어를 제공했다.
기존 CI 확인과의 핵심 차이점: 서브에이전트는 결과를 추론하고, 확인 간에 실패를 상관시키고, 인간이 읽을 수 있는 요약을 작성할 수 있다. CI 작업은 종료 코드 0 또는 1을 반환한다. 서브에이전트는 "/blog/[slug]의 구조화된 데이터가 이전 빌드에 있었던 dateModified 필드를 누락하고 있으며, 이는 3-5일 내에 Google 검색 콘솔에서 리치 스니펫 회귀를 초래할 가능성이 높습니다."를 반환한다.
그게 다 요점이다.
3개월 후, 우리의 GitHub Actions 설정이 마침내 우리를 망가뜨렸다
우리의 이전 파이프라인은 Lighthouse CI, pa11y, linkinator, 그리고 맞춤 Node 스크립트를 호출하는 GitHub Actions의 복잡한 얽힘이었다. 작동했다.
대충.
하지만 3가지 문제가 있었다.
확인 간 추론이 없다. Lighthouse가 CLS 문제를 플래그했고 접근성 스캔이 같은 이미지의 누락된 alt 태그를 플래그했다면, 우리는 연결이 없는 두 개의 별도 경고를 받았다. 엔지니어들은 CI 로그를 수동으로 grep하고, 타임스탬프를 연관시키고, 같은 컴포넌트였다는 것을 파악해야 했다.
시간 낭비다.
취약한 구성. 각 도구는 자신의 구성 파일, 임계값 형식, 그리고 출력 스키마를 가졌다. 임계값을 업데이트하는 것은 4-6개의 파일을 만지는 것을 의미했다. YAML 여기. JSON 저기. 환경 변수 세 번째 장소. 한 글자 오타면 전체 파이프라인이 실패해야 할 때 0으로 종료된다.
문맥적 설명이 없다. 엔지니어들은 성공/실패를 받았다. 주니어 개발자들은 왜 실패했고 무엇을 해야 하는지 이해하는 데 20-40분을 보냈다. "접근성 점수: 87"은 어떤 ARIA 속성이 누락되었거나 스크린 리더에 왜 중요한지 말해주지 않는다.
우리는 거짓 양성을 디버깅하거나 Slack에서 실패를 설명하는 데 주당 3시간을 소비했다.
최후의 짚? 2025년 8월. 우리는 금요일 오후 4시에 Northwind Traders 리디자인을 푸시했다 (알다시피). Lighthouse 통과. 접근성 통과. 링크 통과. 배포했다.
월요일 아침, 그들의 마케팅 부사장이 우리에게 이메일을 보냈다. "왜 우리 제품 페이지가 Google에서 사라졌어?" 우리가 실수로 /products/ 아래의 모든 페이지에서 robots 메타를 noindex로 설정했다는 것으로 밝혀졌다. 우리의 CI는 robots 태그를 확인하지 않았다. 재색인화에 6일이 걸렸다. 그들은 약 $12,000의 수익 손실을 입었다.
우리는 다른 CI 도구가 필요하지 않았다 -- 우리가 이미 신뢰하는 도구의 출력을 추론할 수 있는 오케스트레이션 레이어가 필요했다. 잘 작성된 스킬 파일은 할루시네이션하는 접근성 규칙을 가진 서브에이전트와 올바른 플래그로 pa11y를 실행하고 JSON 출력을 해석하는 것 사이의 차이다.
우리의 .claude/ 디렉토리 구조
실제 트리는 다음과 같다:
.claude/
├── settings.json
├── agents/
│ ├── seo-regression.md
│ ├── cwv-smoke.md
│ ├── accessibility.md
│ ├── broken-links.md
│ ├── schema-validation.md
│ └── deploy-gate.md
├── skills/
│ ├── run-lighthouse.md
│ ├── run-pa11y.md
│ ├── run-linkinator.md
│ ├── parse-schema-org.md
│ ├── compare-seo-snapshot.md
│ └── format-deploy-report.md
└── snapshots/
└── seo-baseline.json
snapshots/ 디렉토리는 비교 확인을 위한 기준 데이터를 보관한다. 단순하다. 우리는 클라이언트가 "왜 순위가 지난 화요일에 떨어졌어?"라고 물었을 때 무엇이 변경되었는지 볼 수 있도록 Git에서 버전 관리한다.
특별한 것 없다. 마크다운 파일과 JSON일 뿐이다.
클라이언트가 밤 11시에 Google이 모든 리치 스니펫을 떨어뜨렸다고 전화했다
2025년 9월. 우리는 중견 소매업체를 위한 전자상거래 사이트를 구축하고 있었다 (그들을 Acme Home Goods라고 부르자). 그들은 리치 스니펫 -- 제품 별, 가격, 가용성 -- 검색 결과에 표시되도록 6개월을 보냈다.
우리는 Shopify 테마 업데이트를 푸시한다. 좋아 보인다. 금요일 밤에 배포된다.
토요일 밤 11시 14분에 텍스트를 받는다. "우리 제품 페이지가 Google에서 깨져 보입니다. 별이 없어요. 가격이 없어요. 뭐가 됐어?"
Search Console을 연다. 모든 단일 제품 페이지가 구조화된 데이터 오류를 던지고 있다. offers 필드가 priceCurrency를 누락하고 있다. 그것 없이는 Google이 리치 스니펫을 표시하지 않을 것이다. 순위는 떨어지지 않았지만, 클릭률은 밤새 4.2%에서 1.8%로 떨어졌다.
비용? 우리가 수정하고 Google이 다시 크롤링할 때까지 주당 약 $8,000의 트래픽 손실.
스키마는 거기 있었다. 우리는 Shopify API가 그 키를 사용하기 때문에 속성 이름을 priceCurrency에서 currency로 바꿨을 뿐이다. 생각해보지 않았다. 유효성 검사가 이를 포착하지 못했다.
그때 우리는 schema-validation 서브에이전트를 구축했다.
.claude/agents/에 마크다운 파일을 만들고 시스템 프롬프트, 허용된 도구 목록, 작업 명령을 작성한다. 부모 세션(또는 훅)은 dispatch_agent()로 또는 settings.json의 훅 구성을 통해 이를 생성한다.
최소 구조:
# Agent: [이름]
## Role
[한 줄 설명]
## Allowed Tools
- Bash (특정 명령으로 제한됨)
- Read file
- Write file
## Instructions
[단계별 작업 설명, 스킬 파일 참조]
## Output Format
[부모가 예상하는 정확한 형식]
출력 형식에 대해 극도로 구체적이다. deploy-gate 오케스트레이터가 passed 부울과 summary 문자열을 가진 JSON을 기대한다면, 그것을 명시한다. 자유형식 텍스트를 반환하는 서브에이전트는 오케스트레이션을 깨뜨린다. 우리는 서브에이전트가 마크다운 표를 반환했고 부모가 이를 파싱할 수 없을 때 이것을 어렵게 배웠다. 아무 오류도 없었다. 단지 트리거되지 않았다. 내가 오전 2시에 2시간을 디버깅하는 데 소비했기 때문에 조용히 실패했다.
내 실수를 반복하지 마라. 형식을 잠가라.
서브에이전트 1: SEO 회귀 확인
이는 현재 빌드의 SEO 중요 요소를 기준 스냅샷과 비교한다.
# Agent: SEO Regression Check
## Role
현재 빌드와 저장된 기준 간의 SEO 회귀를 감지한다.
## Allowed Tools
- Bash (node 스크립트만)
- Read file
## Instructions
1. .claude/skills/compare-seo-snapshot.md의 스킬 파일을 읽는다
2. 실행: node scripts/extract-seo-meta.js --url=$PREVIEW_URL --output=/tmp/seo-current.json
3. .claude/snapshots/seo-baseline.json을 읽는다
4. 두 스냅샷을 필드별로 비교한다:
- title 태그 (정확히 일치)
- meta 설명 (유사성 > 0.85)
- canonical URL (정확히 일치)
- h1 개수 (페이지당 1개여야 함)
- robots meta (noindex로 변경되지 않아야 함)
- Open Graph 태그 (og:title, og:description, og:image 존재)
5. robots가 noindex로 변경된 페이지는 CRITICAL로 플래그한다.
6. 누락되거나 중복된 title 태그는 HIGH로 플래그한다.
7. meta 설명 변경이 15% 이상 다르면 MEDIUM로 플래그한다.
## Output Format
{"passed": boolean, "critical": [], "high": [], "medium": [], "summary": string}
extract-seo-meta.js 스크립트는 사이트맵의 모든 페이지를 방문하고 title, meta, canonicals, h1s, OG 태그를 JSON으로 덤프하는 120줄의 Puppeteer다. 똑똑한 것 없다. 그냥 추출이다.
서브에이전트의 값은 비교와 추론에 있고, 추출이 아니다. 어떤 변경이 중요한지 안다. 어떤 것이 화장 같은지. 어떤 것이 클라이언트에게 다음 분기에 $15,000의 오가닉 트래픽 손실을 야기할 것인지.
예: meta 설명을 "Best CRM software for small businesses in 2025"에서 "Best CRM software for small business"로 변경하면, 유사성 점수는 0.91이다. 괜찮다. 하지만 "CRM software"로 변경하면, 유사성이 0.65로 떨어진다. 서브에이전트는 이것을 MEDIUM으로 플래그한다. 왜냐하면 이것은 키워드 밀도의 40% 감소이고 아마 CTR을 해칠 것이기 때문이다.
그냥 diff가 아니다. 그 diff가 의미하는 것에 대한 추론이다.
우리는 지금까지 이것으로 4가지 문제를 포착했다. robots noindex 것. 누군가가 모든 OG 이미지를 삭제한 경우 (소셜 공유를 망쳤을 것이다). title 태그가 60자 대신 40자로 잘린 경우 (그냥 나쁜 모양, SEO를 해치지 않았지만, 클라이언트가 공지했을 것이다). 그리고 canonical URL이 https://에서 http://로 변경된 경우 (중복 콘텐츠 페널티를 야기했을 것이다).
각각은 최소한 몇 시간의 정리와 클라이언트 신뢰를 우리에게 야기했을 것이다. 아마 더.
우리는 seo-baseline.json을 repo에 저장하고 deploy-success 훅의 일부로 업데이트한다.
서브에이전트 2: Core Web Vitals 스모크 테스트
# Agent: CWV Smoke Test
## Role
핵심 페이지에서 Lighthouse를 실행하고 CWV 회귀를 플래그한다.
## Allowed Tools
- Bash
## Instructions
1. .claude/skills/run-lighthouse.md를 읽는다
2. 이 페이지들에 대해 $PREVIEW_URL에 대해 Lighthouse CI를 실행한다:
- / (홈페이지)
- /blog/ (목록)
- /blog/[most-recent-post] (상세)
- /services/ (존재하는 경우)
3. 임계값 (아래 시 실패):
- LCP: 2500ms
- FID/INP: 200ms
- CLS: 0.1
- Performance 점수: 85
- 접근성 점수: 90
4. 메트릭이 이전 실행에서 10% 이상 회귀했다면,
여전히 임계값 위에 있어도 WARNING으로 플래그한다.
5. Lighthouse가 보고하는 LCP 또는 CLS를 야기하는 특정 요소를 포함한다.
## Output Format
{"passed": boolean, "pages": [{"url": string, "scores": {}, "flags": []}], "summary": string}
연결된 스킬 파일 (run-lighthouse.md)은 정확한 lhci CLI 호출을 포함한다:
# Skill: Run Lighthouse
## Command
```bash
npx @lhci/cli@0.14.0 collect \
--url="$1" \
--numberOfRuns=3 \
--settings.preset=desktop \
--settings.output=json \
--settings.outputPath=/tmp/lhci-results/
Parsing
/tmp/lhci-results/에서 중간 실행을 읽는다. 추출:
- categories.performance.score * 100
- audits['largest-contentful-paint'].numericValue
- audits['cumulative-layout-shift'].numericValue
- audits['interaction-to-next-paint'].numericValue (존재하는 경우)
## 서브에이전트 3: 접근성 스캔
```markdown
# Agent: Accessibility Scan
## Role
미리보기 URL에 대해 pa11y를 실행하고 WCAG 2.1 AA 위반을 보고한다.
## Allowed Tools
- Bash
## Instructions
1. .claude/skills/run-pa11y.md를 읽는다
2. CWV 에이전트와 동일한 페이지 세트에 대해 pa11y를 실행한다.
3. 심각도별로 결과를 그룹화한다: error, warning, notice.
4. 각 오류에 대해, 다음을 포함한다:
- 위반된 WCAG 기준 (예: 1.1.1 Non-text Content)
- HTML 요소 (선택자)
- 한 문장 고정 제안
5. 오류가 존재하면 실패. 경고 > 10이면 경고.
## Output Format
{"passed": boolean, "error_count": number, "warning_count": number, "errors": [{"criterion": string, "selector": string, "fix": string}], "summary": string}
우리는 pa11y@8.0.0을 --runner=axe 플래그와 함께 사용한다. 기본 htmlcs 러너는 axe가 포착하는 일부 색상 대비 문제를 놓친다.
서브에이전트 4: 깨진 링크 스캔
# Agent: Broken Link Scan
## Role
미리보기 사이트를 크롤링하고 깨진 내부 및 외부 링크를 보고한다.
## Allowed Tools
- Bash
## Instructions
1. .claude/skills/run-linkinator.md를 읽는다
2. 실행: npx linkinator@6.1.2 $PREVIEW_URL --recurse --timeout 15000 --format json > /tmp/link-results.json
3. 상태 >= 400 또는 상태 === 0 (타임아웃)인 결과를 필터링한다.
4. 내부 (같은 도메인)와 외부 깨진 링크를 분리한다.
5. 내부 깨진 링크는 CRITICAL. 외부 깨진 링크는 WARNING.
6. 알려진 불안정한 외부 도메인을 제외한다: twitter.com, linkedin.com (그들은 크롤러를 차단한다).
## Output Format
{"passed": boolean, "internal_broken": [{"source": string, "target": string, "status": number}], "external_broken": [...], "summary": string}
서브에이전트 5: 스키마 유효성 검사
# Agent: Schema Validation
## Role
모든 페이지에서 JSON-LD 구조화된 데이터의 유효성을 검사한다.
## Allowed Tools
- Bash
- Read file
## Instructions
1. .claude/skills/parse-schema-org.md를 읽는다
2. 사이트맵의 각 페이지에 대해:
a. 모든 <script type="application/ld+json"> 블록을 추출한다
b. JSON으로 파싱한다 (잘못된 경우 실패)
c. @type당 필수 필드의 유효성을 검사한다:
- Article: headline, datePublished, dateModified, author, image
- LocalBusiness: name, address, telephone
- WebPage: name, description
- BreadcrumbList: position, name, item이 있는 itemListElement
d. 모든 @id 참조가 페이지의 그래프 내에서 해결되는지 확인한다
e. 스키마의 URL이 절대, 상대가 아닌지 검사한다
3. 누락된 필수 필드는 HIGH로 플래그한다.
4. 잘못된 JSON은 CRITICAL로 플래그한다.
## Output Format
{"passed": boolean, "pages": [{"url": string, "schemas": [{"type": string, "valid": boolean, "issues": []}]}], "summary": string}
서브에이전트 6: Deploy 게이트 오케스트레이터
이 부모 에이전트는 다른 5개를 생성하고 go/no-go 결정을 내린다.
# Agent: Deploy Gate
## Role
모든 배포 전 확인을 오케스트레이션하고 최종 배포 결정을 생성한다.
## Allowed Tools
- Bash
- Read file
- Write file
- dispatch_agent
## Instructions
1. 이 에이전트들을 병렬로 생성한다:
- .claude/agents/seo-regression.md
- .claude/agents/cwv-smoke.md
- .claude/agents/accessibility.md
- .claude/agents/broken-links.md
- .claude/agents/schema-validation.md
2. 모든 출력을 수집한다.
3. .claude/skills/format-deploy-report.md를 읽는다
4. 의사결정 로직:
- ANY 에이전트가 CRITICAL 플래그를 가지면: 배포를 BLOCK.
- 2개 이상의 에이전트가 HIGH 플래그를 가지면: 배포를 BLOCK.
- 1개 에이전트가 HIGH 플래그를 가지면: 경고, 수동 오버라이드 필요.
- 그 외: 승인.
5. 전체 보고서를 /tmp/deploy-report.md에 쓴다
6. 의사결정을 출력한다.
## Output Format
{"decision": "APPROVE" | "WARN" | "BLOCK", "reports": {agent_name: agent_output}, "summary": string}
훅 구성: settings.json
우리의 실제 settings.json은 다음과 같다 (클라이언트 특정 URL은 편집됨):
{
"hooks": {
"pre-commit": [
{
"agent": ".claude/agents/schema-validation.md",
"condition": "files_changed_match('**/*.json', '**/structured-data/**')",
"env": {
"PREVIEW_URL": "http://localhost:3000"
}
}
],
"pre-push": [
{
"agent": ".claude/agents/deploy-gate.md",
"env": {
"PREVIEW_URL": "$VERCEL_PREVIEW_URL"
},
"timeout": 300,
"on_failure": "block"
}
],
"post-deploy-success": [
{
"command": "node scripts/extract-seo-meta.js --url=$PRODUCTION_URL --output=.claude/snapshots/seo-baseline.json",
"description": "성공적인 배포 후 SEO 기준 업데이트"
}
]
},
"agent_defaults": {
"model": "claude-sonnet-4-20250514",
"max_tokens": 8192,
"timeout": 120
},
"skills_directory": ".claude/skills/"
}
이 구성의 주석:
- 우리는 서브에이전트를 위해
claude-sonnet-4-20250514를 사용한다, Opus가 아니라. 여기서의 추론 작업은 비용 차이를 정당화하지 않는다. Sonnet은 "두 JSON 객체를 비교하고 차이를 플래그"를 잘 처리한다. - deploy 게이트의
timeout: 300은 모든 5개 서브에이전트에 시간을 준다. 개별 에이전트는 120초 기본값을 가진다. 오케스트레이터는 모두에 기다리기 때문에 5분을 받는다. - pre-commit 훅의
condition은 스키마 유효성 검사가 스키마 관련 파일을 만질 때만 실행됨을 의미한다. CSS 변경에서 실행할 이유가 없다. post-deploy-success는 기준을 업데이트한다. 이것 없이, SEO 회귀 확인은 오래된 데이터와 비교한다.
모든 것을 함께 붙이는 스킬 정의
가장 많은 작업을 하는 스킬 파일은 compare-seo-snapshot.md다:
# Skill: Compare SEO Snapshots
## Purpose
두 SEO 메타데이터 스냅샷을 비교하고 회귀를 식별한다.
## Input
- 현재 스냅샷: /tmp/seo-current.json
- 기준 스냅샷: .claude/snapshots/seo-baseline.json
## Comparison Rules
### Title Tags
- title이 변경되고 페이지의 오가닉 트래픽 (기준 메타데이터에서) > 1000 sessions/month이면, HIGH로 플래그한다.
- title이 이제 비어 있거나 다른 페이지의 title과 일치하면, CRITICAL로 플래그한다.
- 저트래픽 페이지에서 title이 변경되면, MEDIUM으로 플래그한다.
### Canonical URLs
- canonical URL에 대한 모든 변경은 HIGH다.
- 다른 도메인을 가리키는 canonical은 CRITICAL이다.
- 누락된 canonical (있었지만 이제 없음)은 HIGH다.
### Robots Meta
- "noindex"를 얻은 페이지는 CRITICAL이다.
- 내부 링크에서 "nofollow"를 얻은 페이지는 HIGH다.
### 새 페이지
- 현재에는 있지만 기준에는 없는 페이지는 INFO다 (새 콘텐츠에 예상됨).
- 하지만 다음을 확인한다: title, meta 설명, canonical, 최소 하나의 h1.
### 제거된 페이지
- 기준에는 있지만 현재에는 없는 페이지는 HIGH다.
- 이는 실수로 된 경로 제거를 나타낼 수 있다.
이 스킬 파일은 몇 달의 SEO 인시던트 대응을 Claude가 안정적으로 따를 수 있는 형식으로 인코딩한다. 이것 없이, 서브에이전트는 회귀를 구성하는 것에 대해 합리적이지만 일관성 없는 판단을 내릴 것이다.
시스템이 포착한 4가지 인시던트
인시던트 1: 47개 블로그 게시물에서 우발적인 noindex
클라이언트: B2B SaaS 회사, 200페이지, 월 60,000 오가닉 세션.
개발자가 새 메타 태그를 추가하기 위해 블로그 템플릿의 <Head> 컴포넌트를 업데이트했다. 그들은 스테이징 구성에서 복사했는데, 여기에는 <meta name="robots" content="noindex, nofollow">이 하드코딩되어 있었다. 변경은 리뷰어가 새 태그에 집중했기 때문에 코드 검토를 통과했고, 기존 태그를 통과하지 않았다.
SEO 회귀 서브에이전트는 47페이지를 CRITICAL로 플래그했다 -- robots meta가 noindex로 변경됨. 배포가 차단되었다.
탐지 시간: push 후 2분 14초. 시스템이 없으면, Search Console이 커버리지 하락을 표시할 때 3-7일 후 포착되었을 것이다.
회피된 추정 영향: 그 47개 게시물은 대략 월 $14,000의 파이프라인을 구동했다. 1주일의 deindex 이벤트도 $3,500+를 야기했을 수 있다.
인시던트 2: 새 히어로 이미지로부터의 CLS 회귀
클라이언트: 전자상거래 브랜드, Shopify Hydrogen의 Next.js 14 스토어프론트.
디자인 팀이 홈페이지 히어로를 다른 가로세로비를 가진 새 이미지로 바꿨지만 <Image> 컴포넌트의 width/height 속성을 업데이트하지 않았다. 이미지는 잘 로드되었지만 0.34의 CLS를 야기했다 -- 0.1 임계값을 훨씬 초과했다.
CWV 스모크 테스트 서브에이전트는 홈페이지에서 CLS 회귀를 보고했다. 요약은 구체적으로 호출했다: "CLS 요소 img.hero-banner로 인해 0.34 누적. 이미지 치수 (1920x800)가 컨테이너 가로세로비 (16:9 = 1920x1080)와 일치하지 않습니다. 명시적 width={1920} height={800}을 추가하거나 컨테이너를 업데이트하십시오."
탐지 시간: 1분 47초.
인시던트 3: URL 재구조화 후 깨진 내부 링크
클라이언트: 전문 서비스 회사, 80페이지.
우리는 서비스 페이지를 /services/[name]에서 /[category]/[name]으로 재구조화했다. 리디렉트는 제자리에 있었지만, 3개의 블로그 게시물은 오래된 URL에 하드코딩된 링크를 가졌고, CMS 구동 네비게이션은 삭제된 페이지를 가리키는 캐시된 항목을 가졌다.
깨진 링크 스캔은 4개의 내부 404를 찾았다. 서브에이전트의 요약은 4개 중 3개가 블로그 게시물 본문 콘텐츠 (네비게이션 아님)에 있다고 지적했으며, 이는 리디렉트 감사에서 놓쳤다는 것을 의미했다.
탐지 시간: 3분 8초. linkinator 크롤은 가장 느린 부분이다.
인시던트 4: 기사 스키마에서 누락된 dateModified
클라이언트: 미디어 회사, 2,000개 기사.
CMS 마이그레이션은 WordPress에서 Sanity로 dateModified 필드 매핑을 잃었다. 스키마 생성 코드는 dateModified에 대해 null로 폴백했으며, 이는 잘못된 JSON-LD를 생성했다.
스키마 유효성 검사 서브에이전트는 모든 기사 페이지를 HIGH로 플래그했다 -- 누락된 필수 dateModified 필드. 요약은 설명했다: "Google은 기사 구조화된 데이터가 Top Stories 및 리치 결과 자격을 가지기 위해 dateModified를 요구합니다. 모든 2,147개 기사 페이지가 영향을 받습니다."
탐지 시간: 4분 22초 (큰 사이트맵).
ROI: 배포당 분 절약 및 월 달러
우리의 수학은 다음과 같다:
| 메트릭 | Before (CI + 수동) | After (서브에이전트) | Delta |
|---|---|---|---|
| 배포당 확인 | 4개 도구, 수동 검토 | 5개 에이전트, 자동화 | +1 확인, -100% 수동 검토 |
| 모든 확인 실행 시간 | 8-12분 (순차 CI) | 3-5분 (병렬 서브에이전트) | -60% |
| 실패 이해 시간 | 실패당 20-40분 | 1-2분 (문맥적 요약) | -90% |
| 주당 배포 (모든 클라이언트) | 18 | 18 | Same |
| 거짓 양성 비율 | ~15% (시끄러운 Lighthouse) | ~4% (추론이 소음을 필터링) | -73% |
배포당 절약되는 분: 확인이 실패할 때 평균 25분 (배포의 30%). 이는 주당 25 × 5.4 실패하는 배포 = 135분/주 = 월 9시간이다.
시스템의 비용:
- 서브에이전트를 위한 Claude API 비용: ~$0.12 per full deploy 게이트 실행 (5개 에이전트, Sonnet, 에이전트당 6,000 토큰 평균)
- 주당 18개 배포 × 4.3주 × $0.12 = 월 $9.29 API 비용
- Puppeteer/Lighthouse 인프라: 기존 Vercel 빌드 인스턴스에서 실행, 추가 비용 없음
- 유지보수 시간: 스킬 파일 및 임계값 업데이트에 월 ~2시간
엔지니어 시간 절약의 달러 가치: 월 9시간 × $85/시간 (우리 팀의 혼합 비율) = 월 $765 절약.
회피된 인시던트의 달러 가치: 위의 4개 인시던트를 기반으로, noindex 인시던트만 $3,500을 야기했을 수 있다. 분기당 그런 인시던트 하나를 방지하면, 그것은 월 $1,166의 회피된 클라이언트 영향이다.
순 ROI: 월 $9.29의 API 비용에 대한 월 $1,920의 가치. 이는 206배의 반환이다. 더 큰 팀을 위해 API 비용을 10배로 해도, 여전히 유리하다.
격차 및 우리가 변경할 것
이 시스템이 완벽하지는 않다. 여기 여전히 거친 것들이 있다:
시각적 회귀 테스트가 없다. 서브에이전트는 Lighthouse와 pa11y를 실행할 수 있지만 스크린샷을 볼 수 없고 "히어로 섹션이 깨졌습니다"라고 말할 수 없다. 우리는 Claude의 비전 기능을 지켜보고 있다.
기준 드리프트. SEO 기준은 성공적인 배포에서 업데이트되지만, 시스템이 포착하지 못하는 회귀를 배포하면, 그것은 새로운 기준이 된다. 우리는 기준을 월별로 수동으로 검토한다.
외부 링크 불안정성. Twitter/X, LinkedIn, 그리고 일부 정부 사이트는 크롤러를 차단하거나 공격적으로 속도 제한한다. 우리는 제외 목록을 유지하지만, 수동 업데이트가 필요하다.
콜드 스타트 시간. repo를 복제한 후 첫 실행은 npx가 패키지를 페치해야 하기 때문에 더 오래 걸린다. 우리는 Docker 레이어에서 CLI 도구를 미리 설치하는 것을 고려하고 있다.
Anthropic 속도 제한. 피크 시간 동안 5개의 서브에이전트를 동시에 생성하면 Claude API의 속도 제한을 가끔 타격할 수 있다. 우리는 spawns 간에 2초 스태거를 추가했고, 작동하지만 어색하다.
우리의 더 긴 에이전트 정의 (스키마 유효성 검사는 400단어)는 때때로 더 짧은 것들보다 덜 구조화된 출력을 생성한다. 우리는 스키마 유효성 검사 에이전트를 type-per-type sub-subagents로 분할하는 것을 고려하고 있다.
FAQ
Claude 코드 서브에이전트는 어떤 LLM이든 작동하나, 아니면 Claude만?
서브에이전트는 Anthropic API에 연결된 Claude 코드 기능이다. Claude API 접근이 있는 Claude 코드가 필요하다. 에이전트 정의 형식은 일반 표준이 아닌 Claude 코드의 .claude/ 디렉토리 규약에 특정하다.
배포당 5개 서브에이전트를 실행하면 API 수수료로 얼마가 나가?
우리 규모에서, Claude Sonnet을 사용하여 full 배포 게이트 실행당 대략 $0.12. 주당 18개 배포에 대해 월 약 $9-10이다. Opus는 약 5배 더 비싸지만 우리는 이 작업들에 대해 필요하다고 찾지 못했다.
서브에이전트는 GitHub Actions와 같은 CI/CD 파이프라인에서 실행될 수 있나?
예. CI 환경에서 Claude 코드를 헤드리스로 호출할 수 있다. 우리는 Vercel 미리보기 배포 완료 시 webhook를 통해 미리보기 URL을 환경 변수로 사용하여 claude-code run .claude/agents/deploy-gate.md를 호출한다.
Claude 코드 스킬과 서브에이전트의 차이는 무엇인가?
스킬은 Claude에게 뭔가를 하는 방법을 가르치는 마크다운 명령 파일이다 -- 레시피 같은. 서브에이전트는 자신의 컨텍스트와 도구로 생성할 수 있는 격리된 Claude 인스턴스다. 서브에이전트는 스킬을 사용한다. 스킬을 설명서로, 에이전트를 노동자로 생각하라.
당신은 Anthropic의 루틴 기능이 필요한가, 아니면 순수 서브에이전트만으로 충분한가?
우리의 배포 게이트 워크플로우에 대해, 순수 서브에이전트와 settings.json의 훅이 충분하다. 루틴은 더 복잡한 다단계 워크플로우에 유용한 높은 수준의 오케스트레이션 레이어를 추가한다. 우리의 배포 확인이 6개 에이전트를 초과해 증가하면 루틴을 채택할 수 있다.
서브에이전트 실패 또는 타임아웃을 어떻게 처리하나?
각 서브에이전트는 120초 타임아웃을 가진다. 서브에이전트가 실패하거나 타임아웃하면, 배포 게이트 오케스트레이터는 그것을 BLOCK이 아닌 WARN으로 취급한다. 우리는 Lighthouse가 매달려 있어서 배포를 블록하는 것보다 불완전한 확인으로 배포하는 것을 선호한다. 요약은 어떤 확인이 완료되지 않았는지 기록한다.
이 접근 방식이 Lighthouse CI 또는 pa11y와 같은 전용 도구를 대체할 수 있나?
아니다 -- 그것은 그들을 감싼다. 서브에이전트는 bash를 통해 이 도구들을 호출한 다음 출력을 추론한다. 당신은 여전히 기본 도구들을 설치해야 한다. 가치는 오케스트레이션, 상관성, 자연어 보고 레이어에 있으며, 스캐너 자체를 대체하는 것이 아니다.