Paseo 의 Project·Workspace·Tab 을 worktree 작업 단위로 끊는 법
같은 폴더에서 paseo run 을 반복하면 워크스페이스가 계속 새로 생긴다. 계층이 무엇에 대응하는지, 1 워크스페이스=1 워크트리=1 브랜치를 어떻게 지키고 CLI 로 검증하는지.
에이전트 오케스트레이션 도구 Paseo 를 며칠 쓰다 보니 앱 사이드바가 이상하게 불어 있었다. 한 repo 밑에 워크스페이스가 예닐곱 개씩 쌓였는데, 정작 나는 브랜치를 그렇게 많이 딴 기억이 없었다. 같은 develop 체크아웃 하나에 “로그인 버그”, “메모 정규식”, “로그인 버그” 가 또… 제목이 반쯤 겹친 워크스페이스가 줄줄이 있었다.
원인을 짚으려면 Paseo 의 계층이 실제로 무엇에 대응하는지부터 봐야 했다. 버전은 @getpaseo/cli 0.2.5.
계층이 실제로 가리키는 것
앱 UI 는 Project > Workspace > Tab 으로 보이지만, 디스크 상태(~/.paseo/)를 열어 보면 각 층이 다른 것에 묶여 있다.
| 계층 | 실제 단위 | 저장 위치 |
|---|---|---|
| Project | repo 정체성 (git remote URL, non-git 은 host:<serverId>:<path>) |
projects/projects.json |
| Workspace | 작업 디렉터리 + 작업 맥락 1개 | projects/workspaces.json |
| Tab | 그 워크스페이스 안의 에이전트 1개 또는 터미널 1개 | agents/<slug>/<id>.json |
Project 는 경로가 아니라 remote URL 로 묶인다. kind: git 이면 projectKey 가 remote URL 이라, clone 위치가 다르든 워크트리가 어디 있든 같은 프로젝트로 합쳐진다. 워크트리들이 한 프로젝트 밑에 줄서는 게 이 때문이다.
문제는 그 아래 Workspace 층이었다.
증상 — 같은 폴더에서 paseo run 을 하면 매번 새로 생긴다
재현은 단순하다. 이미 워크스페이스가 걸려 있는 폴더에서 그냥
paseo run "이 버그 고쳐줘"
를 하면, 기존 워크스페이스를 재사용하지 않고 새 워크스페이스를 하나 더 민팅한다. 두 번 하면 두 개, 세 번 하면 세 개. cwd 는 전부 동일한데 workspaceId 만 다른 레코드가 쌓인다. 실제로 develop 체크아웃 하나에 워크스페이스 2개, 어떤 non-git 폴더 하나엔 4개가 붙어 있었다. 전부 같은 cwd.
즉 “폴더 = 워크스페이스” 라는 내 암묵적 모델이 틀렸다. Workspace enum 은 directory | local_checkout | checkout | worktree 네 종인데, 어느 것이든 디렉터리당 1개가 아니다.
실패한 접근 — 경로로 워크스페이스를 되찾으려 함
처음엔 “cwd 를 넘기면 Paseo 가 알아서 기존 워크스페이스에 붙여 주겠지” 라고 기대했다. 아니었다. 번들 소스의 resolve-workspace-id-for-path 파일 주석이 아예 못을 박아 둔다 — 경로→워크스페이스 역해석을 하지 않는다. 원문은 “It is NEVER used to attribute agent status or place agents under a workspace — those are keyed by workspaceId”. 경로 매칭은 archive 같은 경계에서만 쓴다.
그러니 cwd 가 같아도 워크스페이스끼리는 남남이다. 경로로 붙이려는 시도 자체가 성립하지 않았다.
근본 원인 — bare run 이 기본값으로 “새로 민팅”
paseo run 의 워크스페이스 해석 순서를 보면 명확하다(주석 그대로).
1. --workspace <id> -> 그 기존 워크스페이스에서 실행
2. $PASEO_AGENT_ID -> 데몬이 호출자(에이전트)의 워크스페이스로 해석
3. $PASEO_WORKSPACE_ID -> 워크스페이스 터미널이 export 해 둔 값
4. --new-workspace <kind> -> 명시적으로 새 워크스페이스 생성
5. bare run -> cwd 에 대해 새 local 워크스페이스를 새로 민팅
5번이 기본값이다. 아무 플래그 없이 paseo run 하면 5번으로 떨어지고, 그래서 워크스페이스는 사실상 “이 폴더에서의 작업 한 건” 이 된다. 제목(title)이 작업 제목처럼 붙는 것도 이 설계의 결과다. 불어난 사이드바는 버그가 아니라, 내가 계층 규약 없이 bare run 을 반복한 결과였다.
해결 — 1 워크스페이스 = 1 이슈 = 1 워크트리 = 1 브랜치
규약을 이렇게 고정했다. 이슈 하나당 워크스페이스 하나, 그 안에 워크트리 하나와 브랜치 하나. 병렬 브랜치가 필요하면 탭을 늘리는 게 아니라 워크스페이스를 늘린다. 탭(에이전트·터미널)은 “그 작업 하나 안에서” dev 서버, 로그 tail, 서브에이전트처럼 병렬 실행이 필요할 때만 쓴다. 다른 이슈를 탭으로 열지 않는다.
워크트리로 브랜치를 하나 새로 딸 땐 한 줄로 워크트리 생성 + 워크스페이스 등록 + 에이전트 기동까지 끝낸다.
paseo run --new-workspace worktree \
--worktree-mode branch-off --new-branch feature/fix-login --base develop \
--worktree-slug fix-login "로그인 버그 고쳐줘"
워크스페이스만 먼저 만들 거면
paseo workspace create --isolation worktree --mode branch-off \
--new-branch feature/fix-login --base develop --worktree-slug fix-login
반대로 같은 이슈에 탭을 더 붙일 땐 반드시 워크스페이스를 지정한다. 이게 사이드바가 안 불어나는 핵심이다.
paseo run --workspace wks_616d5d9ee058d9f6 "..." # 기존 워크스페이스에 탭 추가
PASEO_WORKSPACE_ID=wks_616d… paseo run "..." # 앰비언트로 지정
에이전트가 자기 워크스페이스 안에서 paseo run 을 부르면 2번(PASEO_AGENT_ID)으로 잡혀 자동으로 같은 워크스페이스에 붙는다 — 서브에이전트가 형제 탭으로 열리는 경로다.
--base 는 반드시 명시
한 가지 함정. --base 를 생략하면 repo 기본 브랜치(main/master)에서 갈라진다. paseo worktree create --help 도 --base <ref> ... (defaults to repo default) 라고 못 박는다. develop 이 사실상 운영인 repo 에서 이걸 빼면, 의도와 달리 main 에서 브랜치가 떨어져 나온다. base 는 항상 직접 준다.
브랜치명·슬러그에도 제약이 있다. 검증 정규식이
const validPattern = /^[a-z0-9-/]+$/; // 최대 100자
라서 대문자·언더스코어·점을 넣으면 이렇게 거절된다.
Invalid worktree name: Branch name must contain only lowercase letters, numbers, hyphens, and forward slashes
이슈 키를 대문자로 그대로 못 쓴다. 브랜치·슬러그는 소문자로 쓰고, 대문자 키가 필요한 곳(커밋 메시지, PR 제목)에만 따로 대문자로 박아 이슈 연결을 건다.
검증 — 상태로 확인한다
계층이 의도대로 끊겼는지는 눈으로 안 되고 CLI·디스크로 본다.
# cwd 하나에 워크스페이스가 몇 개 붙어 있나
paseo workspace ls
# 워크트리 base 가 정말 develop tip 과 같은지
git -C <worktree-path> rev-parse HEAD
git rev-parse develop # 두 해시가 같아야 한다
워크트리를 정리할 때 한 가지 더. paseo workspace archive <id> 를 하면 워크트리 디렉터리는 사라지지만 브랜치는 남는다. 실측으로 확인했다. 필요 없으면 git branch -d 로 따로 지운다.
다른 환경에 옮길 때
- 경로로 워크스페이스를 되찾을 수 있다고 가정하지 말 것. 워크스페이스는
workspaceId로만 식별된다. 스크립트에서 재사용하려면 생성 시 나온 id 를 저장해 뒀다가--workspace로 넘겨야 한다. - 관리 워크트리 경로는 마음대로 못 바꾼다. Paseo 가 만드는 워크트리는
~/.paseo/worktrees/<repoRootHash>/<slug>로 고정이고, 중간 해시 디렉터리는 repo 루트 해시라 제거할 수 없다. 평평한 경로로 맞추려고--isolation local로 우회 등록하면 setup/teardown hook, 워크트리별 포트, archive 시 자동 정리를 전부 잃는다. 위임 작업이면 기본 경로를 그대로 두는 편이 소유권이 분명하다. - 오케스트레이션 툴 주입은 기본 꺼져 있다.
create_workspace같은 MCP 툴은daemon.mcp.injectIntoAgents가 참일 때만 에이전트에 들어오고 기본값이false다. config 파일만 손으로 고친 값은 데몬 재시작 전엔 안 먹으니, 즉시 켜려면 앱 Settings 에서 토글한다. 툴이 없어도 위 CLI 경로로 동일하게 위임되므로 기능 차이는 없다.
정리하면, 사이드바가 불어나는 건 도구 버그가 아니라 계층 규약의 부재다. bare paseo run 은 항상 새 워크스페이스를 민팅한다는 것 하나만 기억하면, 나머지는 “이슈 하나 = 워크스페이스 하나” 로 자연스럽게 정렬된다.