Claude Code 세션 8개를 매번 같은 자리에 띄우려면 무엇이 어려울까?
Windows Terminal 창 배치 자동화에서 가장 어려운 일은 창을 띄우는 것이 아니라 띄운 창이 끝까지 그 자리에 머무는지 확인하는 일이었습니다. 저희 PC는 모니터 4대를 2×2로 놓았고, 모니터마다 화면을 왼쪽과 오른쪽 반으로 나눠 프로젝트별 Claude Code 창을 하나씩 둡니다. 그러면 창이 8개, 자리(존)가 8개입니다.
이 배치가 흩어지는 상황은 세 가지입니다. 부팅할 때 자동 배치가 안 된 날, WSL(Windows 안에서 도는 리눅스 환경)이 튕겨서 병렬 터미널이 한꺼번에 죽은 날, 그리고 그냥 작업 공간을 처음 상태로 돌리고 싶은 날입니다. 어느 쪽이든 창 8개를 다시 띄우고 8개 자리에 맞춰 끌어다 놓아야 합니다.
그래서 저희는 이 일을 한 명령으로 묶었습니다. 감시용 스크립트가 아니라 사람이 필요할 때 부르는 스킬이고, "8개 띄워줘", "세션 8개 다시", "터미널 다시 배치" 같은 말로 부릅니다. 명령 하나가 새 창 8개를 스폰하고(새로 띄우고), 모니터를 자동으로 감지해 좌우 반으로 쪼갠 뒤, 각 창을 존에 맞춰 붙입니다. 전체 실행에는 30~90초가 걸립니다.

실행 방식도 짧게 적어 둡니다. 전부 죽은 뒤에는 launch-8-sessions.sh를 --only 없이 돌려 8개를 새로 띄웁니다. 일부가 살아 있으면 retile-sessions.sh --only 1 로 지금 쓰는 창을 존1에 붙이고, launch-8-sessions.sh --only 2,3,4,5,6,7,8 로 나머지 존 7개만 채웁니다. 창을 띄우지 않고 존과 프로젝트 매핑만 미리 보고 싶으면 --dry-run 을 붙입니다.
이 구조에서 창을 새로 띄우는 일은 쉽습니다. 어려운 쪽은 붙이는 일입니다. 런처가 powershell.exe를 통해 Windows 쪽 스크립트를 부르고, 스크립트가 모니터마다 좌우 반쪽 존을 계산해 창마다 한 존씩 맞춰 줍니다. 창 위치를 정하는 주체가 런처와 Windows Terminal, 둘이라는 점이 뒤에서 문제가 됩니다.
다만 이 기록에는 손으로 창을 맞추던 시간을 잰 값이 없습니다. 그래서 이 글의 "전"은 시간이 아니라 구조입니다. 창 8개를 사람이 8번 끌던 방식에서 명령 1개로 줄었고, 그 명령이 2026년 8월 15일까지 안고 있던 결함이 이 글의 주제입니다. 같은 종류의 무음 결함을 구조 원인으로 접근한 다른 점검 기록은 운영 크론 감시 점검기에 있습니다.
처음 잰 숫자는 무엇이었나?
처음 잰 숫자는 존8 창 1개의 좌표였습니다. 창 8개를 모두 띄운 뒤 마지막 창, 즉 존8에 붙어야 할 창이 Windows Terminal의 기본 캐스케이드 위치인 861,90에 남아 있었습니다. 화면 좌표로 보면 존이 아니라 새 창이 처음 뜨는 자리입니다.
문제는 그 순간 런처의 보고였습니다. 런처는 스냅이 끝나면 창마다 결과를 적고, 마지막에 배치된 개수를 N/N 형태로 한 줄 요약합니다. 존8 창이 861,90에 남아 있는데도 런처는 그 창을 ok로 적었습니다. 창 1개가 어긋난 것이 아니라, 어긋난 창을 정상이라고 말하는 보고가 결함이었습니다.
| 항목 | 런처 보고 | 화면 실제 |
|---|---|---|
| 존1~존7 창 | 이 기록에는 적히지 않음 | 이 기록에는 적히지 않음 |
| 존8 창(마지막) | ok | 기본 캐스케이드 위치 861,90 |
| 스냅 후 확인 단계 | 없음 | — |
출처: 세션 8개 배치 스킬 문서의 8월 15일 실측 수정 항목. 존1~존7 상태는 문서에 적혀 있지 않아 비워 두었습니다.
여기서 한 가지는 분명히 적어 둡니다. 이 기록은 "8개 중 몇 번 중 몇 번 실패했다"는 반복 측정이 아닙니다. 실제로 마지막 창이 어긋난 현장 관측 1건이 출발점이고, 그래서 재현율이나 실패율은 이 글에 없습니다.
측정 방법에 대해 남은 기록은 한 줄입니다. 8월 15일 실측에서 존8 창의 좌표가 861,90으로 읽혔다는 것입니다. 별도 계측 도구나 반복 실행 로그는 이 기록에 없습니다. 861,90은 Windows Terminal이 새 창을 겹쳐 띄울 때 쓰는 기본 캐스케이드 위치입니다. 그래서 "존 근처에서 몇 픽셀 어긋났다"가 아니라 "스냅이 없던 것과 같은 상태"로 읽었습니다.
이 시점에 전후 비교용으로 쓸 수 있는 값은 이렇습니다. 창 수는 8개, 모니터는 4대, 자리 배치는 2×2이고, 전체 실행에는 30~90초가 걸립니다. 시간과 창 수는 수정 전후로 달라지지 않았고, 바뀐 것은 어긋난 창 1개를 찾아내는 능력입니다.
처음에 세운 가설은 무엇이었나?
처음 설계는 창을 한 번 밀면 그 자리에 머문다는 가정 위에 있었습니다. 창을 존 좌표로 옮기는 명령을 한 번 내리고, 창 가장자리의 그림자 영역(DWM 테두리)만큼 보정해 픽셀 단위로 맞추면 끝이라고 봤습니다. 이 가정이 틀렸다는 신호는 한동안 없었습니다.
이 가정 때문에 런처는 "한 번 밀고 확인 없이 끝내는 구조"가 됐습니다. 창이 존에 앉았는지 다시 읽는 단계가 없으니, 명령이 에러 없이 끝나기만 하면 그 창은 ok였습니다. 가설 자체는 틀린 가설이라기보다 검증하지 않은 가설이었고, 검증 장치가 없다는 점이 8월 15일에 드러났습니다.
여러 가설을 세워 하나씩 지운 기록은 남아 있지 않습니다. 이 글에서 반증된 가설은 위의 한 가지, "한 번 밀면 그 자리에 머문다"입니다.
가설은 어디서 틀렸을까?
가설은 창이 스냅 이후에도 움직인다는 지점에서 틀렸습니다. 존8 창은 스냅 명령을 받은 뒤 861,90으로 되돌아가 있었습니다. 명령은 성공했고, 그 직후에 다른 무언가가 창을 되돌렸다는 뜻입니다.
되돌린 쪽을 의심할 후보는 많지 않았습니다. 런처 코드의 좌표 계산이 틀렸다면 존1~존7도 같이 틀렸어야 하는데, 문서에 적힌 어긋난 창은 마지막 하나입니다. 좌표가 아니라 시점의 문제라는 방향이 여기서 잡혔습니다. 마지막 창만 어긋난다는 사실이 가장 큰 단서였습니다.
기록에서 읽히는 사실은 셋입니다. 문서에 어긋남으로 적힌 창은 존8입니다. 런처는 그 창을 ok로 보고했는데, 구조가 한 번 밀고 확인 없이 끝나는 형태라 보고가 명령 뒤의 창 위치를 보지 않았습니다. 그리고 존8은 스폰 루프의 마지막이라 그 뒤에 스냅 이후를 지켜볼 동작이 없었습니다.
관측 수단에는 한계가 있습니다. 이 기록에는 창 위치를 시간 순서로 남긴 로그가 없습니다. 그래서 "복원이 몇 밀리초 뒤에 왔다" 같은 값은 이 글에 쓰지 못합니다. 원인은 Windows Terminal이 저장해 둔 창 크기와 위치를 첫 페인트 때 비동기로 복원한다는 설명과 존8의 실제 좌표를 맞춰 얻은 결론입니다.
한 번 밀고 확인 없이 끝내는 구조라 뒤에 아무 동작이 없는 마지막 창이 특히 노출된다.
진짜 원인은 무엇이었나?
진짜 원인은 Windows Terminal이 첫 화면을 그릴 때 자기가 저장해 둔 크기와 위치를 비동기로 복원한다는 점이었습니다. 창을 스냅한 시점이 이 복원보다 이르면, 복원이 나중에 끝나면서 이미 붙여 둔 창을 제 위치에서 밀어냅니다. 런처 쪽에서 보면 스냅은 성공했고, 그 뒤의 일은 보이지 않습니다.
왜 마지막 창이 특히 위험했을까요. 창 8개를 순서대로 띄우는 스폰 루프에서 존1~존7 창은 스냅한 뒤에도 다음 창을 띄우고 붙이는 동작이 이어집니다. 그 사이에 복원이 끝나고, 그 창들은 제자리를 지켰을 수 있습니다. 마지막 존8 창은 스냅한 뒤 아무 동작도 이어지지 않고 런처가 곧바로 끝납니다. 복원이 늦게 오면 되돌려진 창을 아무도 보지 못합니다.
다만 "앞의 창들은 우연히 괜찮았다"는 설명은 문서에 적힌 사실이 아니라 이 구조에서 나오는 추론입니다. 문서가 확정한 사실은 두 가지입니다. 하나는 Windows Terminal이 저장해 둔 크기와 위치를 비동기로 복원한다는 점, 다른 하나는 존8 창이 실제로 861,90에 남았다는 점입니다.
DWM 프레임이라는 말도 풀어 둡니다. Windows는 창 가장자리에 눈에 보이지 않는 여백을 두는 것이 일반적이라(일반 지식), 창 사각형을 그대로 읽으면 화면에 보이는 크기와 어긋날 수 있습니다. 런처는 이 경계(DWM border)를 보정해 픽셀 단위로 붙이고, 수정 후 검증도 DWM 프레임을 기준으로 위치를 읽습니다.
정리하면 원인은 두 겹입니다. 윗겹은 외부 프로그램이 스냅 이후에 창을 되돌린다는 사실이고, 아랫겹은 그 되돌림을 볼 장치가 런처에 없었다는 사실입니다. 윗겹은 우리가 고칠 수 없습니다. 고칠 수 있는 쪽은 아랫겹이라, 수정은 모두 아랫겹에 들어갔습니다.
- 복원 시점: 첫 페인트(처음 화면을 그리는 순간) 때 비동기로 일어나, 이미 스냅한 창을 나중에 되돌림
- 관측 결과: 존8 창이 기본 캐스케이드 위치 861,90에 남음
- 보고 결함: 런처가 그 창을 ok로 적음 — 스냅 후 다시 읽는 단계 없음
어떻게 고쳤나?
고친 방법은 스냅을 한 번에 끝내지 않고 스냅, 대기, 검증, 재스냅 순서로 바꾼 것입니다. 8월 15일 수정 이후 한 창당 흐름은 이렇습니다. 창을 존에 붙이고, 잠시 기다리고, DWM 프레임(창 테두리까지 포함한 실제 창 사각형)을 다시 읽어 존과 맞는지 확인하고, 어긋나면 다시 붙입니다. 재시도는 창마다 최대 5회입니다.

두 번째 장치는 스폰 루프 전체가 끝난 뒤의 점검입니다. 8개 창을 모두 띄운 후 1.5초를 기다렸다가 전 창을 한 번 더 검증하고, 밀려난 창만 다시 스냅합니다. 앞의 창들을 스냅한 뒤에 복원이 늦게 와서 창을 되돌리는 경우, 그리고 마지막 창처럼 뒤에 아무 동작도 이어지지 않는 경우를 이 한 번의 전수 점검이 같이 덮습니다.
출력도 바꿨습니다. 점검이 끝나면 verify: all placed windows on-zone 한 줄이 찍히고, 재스냅이 있었다면 re-snap zone{N} 줄이 존 번호와 함께 찍힙니다. 이전에는 창마다 ok만 찍었지만, 이제는 "확인했다"는 표시와 "다시 붙였다"는 표시가 분리됩니다.

같은 기회에 운영 규칙도 문서에 남겼습니다. 2026년 8월 12일에 넣은 규칙이 이 수정의 토대입니다. 창이 전멸했으면 전체 실행으로 8개를 새로 띄우고, 일부가 살아 있으면 retile(스폰 없이 기존 창만 존에 붙이는 명령)으로 존1을 맞춘 뒤 launch --only 2,3,4,5,6,7,8 로 빈 존 7개만 채웁니다. --only 없이 launch를 돌리면 항상 8개를 새로 스폰하므로, 이미 열린 창이 있으면 중복으로 생깁니다.
retile은 지금 이 스킬을 실행 중인 세션의 창, 즉 전경 창을 어느 모니터에 있든 첫 타겟 존에 붙입니다. 덕분에 "세션 1개가 열려 있는 상태에서 존1에 두고 나머지 2~8을 채우는" 흐름이 어떤 모니터에서도 동작합니다. 대신 한 존이 비고 다른 존에 창 2개가 겹쳤을 때는 retile-sessions.sh --only 7,8 --no-current-first 처럼 그 두 존만 다시 나누고 전경 창 끌어오기를 끕니다. 옵션을 빼면 제자리에 있던 창까지 헝클어집니다.
한 가지 더 있습니다. 이 PC는 4모니터 2×2라 8세션이지만, 런처가 모니터를 자동으로 감지하기 때문에 구성이 달라도 같은 명령이 적응합니다.
모니터 1대를 좌우로 쪼개 존 2개를 만든다. 출처: 스킬 문서의 이식성 절. 프로젝트가 존보다 적으면 남는 존은 건너뛴다.
이식성을 위해 지킨 규칙도 있습니다. 런처는 좌표를 하드코딩하지 않고 모니터를 자동 감지하며, distro와 home과 claude 실행 경로는 wrapper가 실행할 때 넘깁니다. 스크립트가 모두 ~/.claude 안에 있어서 스킬 폴더를 복사하거나 WSL을 export/import 하면 통째로 따라옵니다. 그래서 8월 15일 수정도 이 런처 한 곳에만 들어가고, 구성이 다른 PC에서도 같은 코드가 돕니다.
수정 날짜의 순서도 기록해 둡니다. 2026년 8월 5일에 회사 랩톱용 retile 스크립트가 실측을 거쳤고, 8월 12일에 이 검증 흐름을 집 PC용 포터블 런처로 옮겼으며, 8월 15일에 스냅 후 검증과 재시도를 더했습니다. 열흘 사이에 같은 스크립트가 세 번 손을 탔고, 세 번째가 이 글의 사건입니다.
재측정하니 무엇이 달라졌나?
고친 뒤의 확인 기준은 출력 한 줄입니다. 점검이 끝났을 때 verify: all placed windows on-zone 이 찍히면 8개 창이 모두 존 안에 있다는 뜻이고, 밀려난 창이 있었다면 re-snap zone{N} 이 그 존 번호와 함께 찍힙니다. 어긋남이 눈에 보이지 않는 "ok"가 아니라 로그에 남는 사건이 됐습니다.
이 변화가 중요한 이유는 측정 대상이 바뀌었기 때문입니다. 수정 전에는 "런처가 ok라고 했는가"가 기준이었고, 이 값은 창이 861,90에 있어도 참이었습니다. 수정 후에는 "DWM 프레임이 존과 맞는가"가 기준입니다. 같은 창을 보고도 앞의 기준은 틀린 답을, 뒤의 기준은 맞는 답을 냅니다.
정직하게 적으면 이 재측정은 "고친 뒤 한 번 돌려 보니 verify 줄이 찍혔다"까지입니다. 한 번 재고 끝내지 말라는 기준에 비춰 보면 부족합니다. 그래서 반복 측정을 만들기보다, 어긋남이 생겼을 때 로그가 말해 주도록 설계했습니다. re-snap zone{N} 줄이 몇 번 찍히는지 쌓이면 어느 존이 자주 밀리는지가 드러납니다. 아직 쌓인 값이 없어 이 글에서는 그 숫자를 쓰지 않습니다.
| 항목 | 수정 전 | 수정 후(2026년 8월 15일) |
|---|---|---|
| 스냅 횟수 | 1회 | 창마다 최대 5회 재시도 |
| 확인 방식 | 없음 (에러 없이 끝나면 ok) | 대기 후 DWM 프레임 검증 |
| 스폰 루프 종료 후 | 바로 종료 | 1.5초 뒤 전 창 한 번 더 검증 |
| 출력 | 창마다 ok | verify 줄, 재스냅 시 re-snap zone{N} 줄 |
| 8월 15일 사건 재발 시 | 존8 창이 861,90에 남고 ok 보고 | 밀려나면 감지해 재스냅 |
출처: 세션 8개 배치 스킬 문서의 2026년 8월 15일 수정 항목.
다만 "수정 후 100번 돌렸더니 어긋남 0" 같은 반복 재측정 값은 이 기록에 없습니다. 있는 것은 사건 1건의 원인 규명과, 그 원인에 맞춘 검증 장치 2겹입니다. 개선율이 아니라 검증 방식이 바뀌었다고 읽어 주세요.
남는 한계는 무엇인가?
첫째 한계는 재시도 상한 5회를 넘기면 어떤 일이 일어나는지 문서에 없다는 점입니다. 상한 안에 존에 앉지 못한 창을 어떻게 보고하는지, 다음 실행에서 어떻게 복구하는지는 이 기록에서 확인되지 않습니다. 확인이 필요한 항목입니다.
둘째 한계는 점검 대상 범위입니다. 창 필터는 프로세스 이름이 WindowsTerminal인 창이고, 임시로 뜨는 conhost 창은 제외합니다. 최소화된 창은 retile 대상에서도 빠집니다. 그래서 최소화된 채로 있는 세션은 재배치되지 않습니다.
셋째 한계는 어떤 프로젝트가 어느 존에 뜨는지가 PC마다 직접 편집해야 하는 유일한 설정이라는 점입니다. 존 순서는 위에서 아래, 왼쪽에서 오른쪽입니다. 현재 8개 존의 매핑은 아래 표와 같고, 절반인 4개 존이 같은 b2b-consulting 프로젝트입니다. 존보다 프로젝트가 적으면 남는 존은 건너뜁니다.
| 존 | 프로젝트 |
|---|---|
| 1 | home |
| 2 | threads-loop |
| 3 | b2b-consulting |
| 4 | b2b-consulting |
| 5 | tradestudio |
| 6 | trading |
| 7 | b2b-consulting |
| 8 | b2b-consulting |
출처: 스킬 문서의 현재 매핑 줄. 존8이 8월 15일 어긋난 창이다.
넷째는 작은 기술 제약입니다. 런처 스크립트(.ps1)는 ASCII 문자만 써야 합니다. Windows PowerShell 5.1이 UTF-8을 인식하지 못해서, 런처를 고칠 때 한글 주석은 쓰지 않습니다. 또 이 PC가 쓰는 스킬은 집 PC용이고, 회사 랩톱에는 별도 스킬이 있습니다. 회사 랩톱 쪽은 파일 이름을 따로 두어 동기화가 덮어쓰지 않게 했습니다.
마지막으로, 이 사건에서 일반화할 수 있는 교훈은 하나입니다. 외부 프로그램(여기서는 Windows Terminal)이 비동기로 상태를 바꾸는 자리에서 "명령이 에러 없이 끝났다"는 "결과가 맞다"와 다른 말입니다. 자동화의 마지막 단계에 읽기 확인을 넣어 두면, 이런 결함이 보고서의 ok 뒤에 숨는 일을 막을 수 있습니다. 업무 자동화에 이런 검증 단계를 넣는 일이 필요하시다면 상담에서 상황을 알려 주세요.