코딩 에이전트를 여러 개
돌리고,
그 결과를 한 화면에서
확인하세요.
작업 하나에 worktree 하나. 그 안에서 Claude Code와 Codex를 띄우고,
바뀐 코드와 테스트를 같은 창에서 봅니다.
아래 화면은 실제 작업 흐름을 그대로 재생합니다.
webhook 재시도에 지수 백오프와 jitter를 추가하고 테스트해줘
@@ -18,7 +18,11 @@ export function retryDelay(attempt) { - return 1000; + const cap = Math.min(BASE * 2 ** attempt, MAX); + return Math.random() * cap; } +if (attempt > LIMIT) return deadLetter(job);
@@ -4,3 +4,9 @@ +it("caps the delay", () => { + expect(retryDelay(9)).toBeLessThanOrEqual(MAX); +});
$ npm test -- retry▋ ✓ 18 passed in 1.24s $ ▋
이 프로젝트가 띄운 것2
postgrespostgres:16
redisredis:7-alpine
그 밖1
mailhogmailhog/mailhog
payments · postgres 165432
public.webhook_deliveryid · endpoint · status · attempts
public.webhook_attemptdelivery_id · delay_ms · error
public.idempotency_keykey · created_at
select count(*) from webhook_attempt where error is not null;
에이전트 옆에는 이 탭들이 늘 같이 있습니다. 앱을 옮겨 다니지 않아도 됩니다.
7f2d10cHEAD → feat/webhook-retryfeat(webhook): 재시도에 백오프
a3c9037Merge branch 'main' into feat/webhook-retry
1c84be0test: 중복 요청 케이스 추가
e3181d2origin/mainfix(desktop): the preedit sits on the grid
9b21f04chore: 릴리즈 스크립트 정리
이 프로젝트가 띄운 것2
postgrespostgres:16
redisredis:7-alpine
이 머신의 다른 컨테이너1
mailhogmailhog/mailhog
나를 기다리는 것 3
- #482 webhook 재시도 큐 정리 리뷰 요청 열기worktree
- #479 웹훅 서명 검증 리뷰 요청 열기worktree
- #488 결제 실패 알림 문구 리뷰 요청 열기worktree
내가 맡은 것 6
- PAY-311 idempotency key 재사용 정리 진행 중 열기worktree
- PAY-322 정산 배치 재실행 스크립트 진행 중 열기worktree
- PAY-318 재시도 지표를 대시보드에 할 일 열기worktree
- PAY-327 환불 API 응답 스키마 정리 할 일 열기worktree
- PAY-290 웹훅 재시도 설계 문서 완료 열기worktree
- PAY-284 결제 로그 마스킹 완료 열기worktree
할 일 2
- PAY-318 재시도 지표를 대시보드에 Payments이번 주
- PAY-327 환불 API 응답 스키마 정리 Payments다음 주
진행 중 2
- PAY-311 idempotency key 재사용 정리 Payments오늘
- PAY-322 정산 배치 재실행 스크립트 Payments어제
리뷰 3
- #482 webhook 재시도 큐 정리 payments-api나를 기다림2시간 전
- #488 결제 실패 알림 문구 payments-web나를 기다림30분 전
- #479 웹훅 서명 검증 payments-api나를 기다림어제
완료 2
- PAY-290 웹훅 재시도 설계 문서 Payments지난주
- PAY-284 결제 로그 마스킹 Payments2주 전
이 폴더에서 찾은 것3
public.webhook_attempt48,102행
public.webhook_delivery12,480행
public.idempotency_key3,914행
public.webhook_attempt SQL새로 고침+ 새 행
error is not null
| id pk | delivery_id | delay_ms | error |
|---|---|---|---|
| 48100 | 9f2c | 1000 | empty |
| 48101 | 9f2c | 2480▋ | empty |
| 48102 | a71d | 4000 | timeout |
1–50행 · 48,102행 중1개 값 변경 · ⌘↵ 로 저장저장됨
일치 20건4개 파일
retry.tssrc/webhook
retry.tssrc/webhook
retry.test.tssrc/webhook
queue.tssrc/webhook
16 const MAX = 30_000; 17 18 export function retryDelay(attempt) { 19 const cap = Math.min(BASE * 2 ** attempt, MAX);22 } 23 24 if (attempt > LIMIT) return deadLetter(job); 25 queue.push(job, retryDelay(attempt));2 import { retryDelay } from "./retry"; 3 4 it("caps the delay", () => { 5 expect(retryDelay(9)).toBeLessThanOrEqual(MAX);
- 창 하나worktree · 코드 · 터미널 · 에이전트
- 계정 없음로그인도 텔레메트리도 서버도 없이
- 메모리 128MB브라우저 엔진을 번들하지 않는 Tauri 2 셸
- macOSApple Silicon · Intel
장면 01
브랜치는 그대로.
자리를 하나 더.
작업 하나에 worktree 하나. 브랜치를 오가지 않으니 빌드 캐시도
node_modules도 그대로 살아 있고, 만든 자리에서 바로 에이전트를
띄우면 됩니다.
- 만들기 · 지우기 · 옮겨 다니기가 한 메뉴 안에
- 브랜치가 이 머신에 없으면 가져온 다음 만듭니다
장면 02
에이전트마다 자기 자리.
Claude Code든 Codex든, 쓰던 CLI를 그 자리에서 띄웁니다. 지금 몇 개가 돌고 있고 몇 개가 내 답을 기다리는지는 메뉴 막대에 뜹니다.
- + 메뉴가 "새로 시작"인지 "이어서"인지 먼저 묻습니다
- 다른 worktree로 옮겨도 세션은 자기 자리에 남습니다
장면 03
바뀐 것만, 한눈에.
기준점은 세션이 시작한 순간입니다. 그 전에 내가 해 둔 편집은 섞이지 않고, 테스트는 같은 창의 터미널에서 그대로 돌립니다.
- 문법 하이라이트가 붙은 diff, 접힌 줄은 펼쳐서
- 스테이징 · 커밋 · 푸시가 같은 창 안에
기능
codeme 하나가 맡는 일.
worktree부터 diff, 터미널, 컨테이너, 티켓까지. 앱을 옮겨 다니며 하던 일이 모두 이 창 안에서 끝납니다.
-
01
worktree
프로젝트마다 만들고, 지우고, 옮겨 다닙니다. 브랜치를 갈아끼우지 않으니 빌드 캐시도
node_modules도 그대로 살아 있습니다. -
02
에이전트 세션
Claude Code · Codex를 worktree 안에서 띄웁니다. 몇 개가 돌고 있고 몇 개가 답을 기다리는지는 메뉴 막대에 뜹니다.
-
03
에이전트 변경
에이전트가 무엇을 바꿨는지만 따로 봅니다. 기준점은 세션이 시작한 순간이라, 그 전에 내가 해 둔 편집은 섞이지 않습니다.
⌃⇧X
-
04
편집기
Monaco 기반. 완성 · 호버 · 정의로 이동은 이미 깔려 있는 언어 서버가 답합니다 — 무엇도 번들하거나 대신 설치하지 않습니다.
-
05
도커 · 데이터베이스
컴포즈가 띄운 컨테이너와 그 안의 테이블을 같은 창에서 봅니다. 접속 정보는 워크스페이스에서 찾아냅니다 — 호스트와 포트를 다시 타이핑하지 않습니다.
-
06
내 작업
GitHub · Forgejo · Jira를 각자의 API로 직접 읽습니다. PR 하나를 골라 그 브랜치의 worktree를 만듭니다. 토큰은 OS 자격증명 저장소에 들어갑니다.
비교
에이전트를 위해 만든 앱.
편집기는 한 사람이 타이핑하도록 만들어졌고, 에이전트 래퍼는 대개 터미널에서 멈춥니다. codeme는 worktree · diff · 터미널 · 컨테이너가 처음부터 한 창에 있는 환경입니다.
| 항목 | codeme | 편집기 · 에이전트 래퍼 |
|---|---|---|
| 작업마다 독립된 git worktree | ✓ | 일부 |
| 에이전트가 바꾼 것만 따로 보는 diff | ✓ | — |
| 기준점이 세션이 시작한 순간 | ✓ | — |
| 터미널 · 도커 · 데이터베이스가 같은 창에 | ✓ | 확장 |
| 이미 깔린 언어 서버를 그대로 사용 | ✓ | 번들 |
| GitHub · Forgejo · Jira에서 바로 worktree | ✓ | — |
| 계정 · 서버 · 텔레메트리 없음 | ✓ | 제품마다 |
| 브라우저 엔진을 번들하지 않는 셸 | ✓ | 번들 |
| 창 하나가 쓰는 메모리 | 128MB | 제품마다 |
흐름
티켓에서 커밋까지, codeme 하나로.
-
내 작업에서 티켓을 고릅니다
리뷰 요청이 위, 내가 맡은 일이 아래에 옵니다. 이 머신에 없는 브랜치면 가져온 다음 worktree를 만듭니다.
-
만든 worktree에서 에이전트를 띄웁니다
"새로 시작"과 "이어서"는 다른 동작입니다. 어느 쪽인지 + 메뉴가 먼저 묻습니다.
-
바뀌는 파일을 옆에서 봅니다
문법 하이라이트가 붙은 diff. 접힌 줄을 펼치면 이 세 줄이 어느 함수 안인지까지 보입니다.
-
스테이징하고, 커밋하고, 푸시합니다
히스토리 그래프도 커밋 화면도 같은 창 안에 있습니다. 푸시는 커밋한 자리에서 바로 이어집니다.
local-first
전부 codeme 앱 안에.
열린 파일, PTY 프로세스, worktree, 커밋 — 이 앱이 다루는 상태는 모두 디스크에 있습니다. 서버도, 계정도, 화면이 그려지기 전에 기다려야 하는 요청도 없습니다.
예외는 하나, 의도적으로. 내 작업 패널만 GitHub · Forgejo · Jira의 API를 읽습니다. 토큰은 맥 키체인에 들어가고, 설정 파일에는 주소만 남으며, 어떤 IPC 명령도 토큰을 창으로 돌려주지 않습니다. 개인정보 처리방침에 그대로 적혀 있습니다.