@angar2/taskery 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -110,7 +110,7 @@ my-app/
110
110
  ├─ .gitignore
111
111
  ├─ .claude/
112
112
  │ ├─ settings.json # hook 등록 (PreToolUse 매칭)
113
- │ ├─ skills/<skill-name>/SKILL.md # 9 skill
113
+ │ ├─ skills/<skill-name>/SKILL.md # 9 skill (+ Claude 전용 run-team)
114
114
  │ └─ hooks/<hook-name>.sh # 2 hook
115
115
  └─ .project/
116
116
  ├─ PROJECT.md # 프로젝트 개요
@@ -192,9 +192,12 @@ my-app/
192
192
  | `/task-close` | task | 최종 검증 후 git 커밋 + dev 브랜치 `--no-ff` 병합 |
193
193
  | `/add-backlog` | meta | 사용자 발화로 plan(기능 그룹)별 `tasks/<NNN_slug>/BACKLOG.md`에 task 후보 1건씩 추가 (0.1.2+) |
194
194
  | `/log-friction` | meta | 사용자 불편을 `.project/FRICTION_LOG.md`에 한 행 기록 |
195
+ | `/run-team` | meta | 여러 작업을 묶을 수 있는 단위로 task로 나눠 자동 병렬 처리 — 리더 세션이 팀원(독립 세션)에게 task를 1건씩 분배하고 흐름을 관리 (Claude 전용 · 실험 기능 전제 · 0.3.x+) |
195
196
 
196
197
  각 스킬은 슬래시로 직접 호출하거나, 사용자 발화의 의미가 스킬의 frontmatter description과 매칭되면 메인 세션이 자동으로 발동시킨다.
197
198
 
199
+ > `/run-team`은 Claude의 실험적 멀티 세션 기능(agent teams)을 사용하는 Claude 전용 스킬이다. 기본 흐름이 아니라 *"이 작업들 한 번에 팀으로 진행해"* 같은 발화가 있을 때만 발동하며, 활성화에는 환경 변수(`CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`) 설정이 필요하다. Codex 설치에는 포함되지 않는다.
200
+
198
201
  `/project-init`, `/plan-init`, `/task-init` 세 스킬은 호출 시 다음 문서를 생성한다.
199
202
 
200
203
  | 스킬 | 생성 위치 | 생성 문서 |
package/bin/fork.js ADDED
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * bin/fork.js
4
+ * `npx @angar2/taskery fork <type> <dev> <src> <slug>` — task 분기.
5
+ *
6
+ * [채번 → 워크트리·브랜치 생성]을 init 락으로 원자 실행 (병렬 task-init 번호 충돌 차단).
7
+ * 성공 시 결과 JSON 한 줄을 stdout으로 출력 ({ taskNum, nnn, branch, wtPath, projectId }).
8
+ * 실패(정책 위배 / 동일 항목 진행중 / 동일 브랜치명 등) 시 stderr + exit 1.
9
+ *
10
+ * 호출 주체: `/task-init` Step 6 (사용자 직접 호출도 가능하나 통상 스킬 경유).
11
+ */
12
+
13
+ const path = require('path');
14
+
15
+ const {
16
+ MANIFEST_NAME,
17
+ readManifest,
18
+ getMainWorktreePath,
19
+ forkTask,
20
+ } = require('./lib');
21
+
22
+ const VALID_TYPES = ['feature', 'bug', 'improve', 'refactor', 'docs', 'chore'];
23
+
24
+ async function main() {
25
+ const [type, dev, src, slug] = process.argv.slice(2);
26
+
27
+ if (!type || !dev || !src || !slug) {
28
+ console.error('사용법: npx @angar2/taskery fork <type> <dev> <src> <slug>');
29
+ console.error('예: npx @angar2/taskery fork feature claude BL-003 login-feature');
30
+ process.exit(1);
31
+ }
32
+ if (!VALID_TYPES.includes(type)) {
33
+ console.error(`type은 ${VALID_TYPES.join(' | ')} 중 하나 (받음: ${type})`);
34
+ process.exit(1);
35
+ }
36
+ if (!/^(BL-\d+|RM-\d+|DR)$/.test(src)) {
37
+ console.error(`src는 BL-NNN | RM-NNN | DR 형식 (받음: ${src})`);
38
+ process.exit(1);
39
+ }
40
+ if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(slug)) {
41
+ console.error(`slug은 영어 kebab-case (받음: ${slug})`);
42
+ process.exit(1);
43
+ }
44
+
45
+ let mainWt;
46
+ try {
47
+ mainWt = getMainWorktreePath();
48
+ } catch (e) {
49
+ console.error(`taskery fork 실패: ${e.message}`);
50
+ process.exit(1);
51
+ }
52
+ if (!readManifest(path.join(mainWt, MANIFEST_NAME))) {
53
+ console.error(`${MANIFEST_NAME} 없음 — 'npx @angar2/taskery init' 먼저 실행 필요.`);
54
+ process.exit(1);
55
+ }
56
+
57
+ try {
58
+ const result = await forkTask(mainWt, { type, dev, src, slug });
59
+ process.stdout.write(JSON.stringify(result) + '\n');
60
+ } catch (e) {
61
+ console.error(`taskery fork 실패: ${e.message}`);
62
+ process.exit(1);
63
+ }
64
+ }
65
+
66
+ main();
package/bin/lib.js CHANGED
@@ -19,10 +19,12 @@
19
19
  * - getWorktreesRoot(projectId): ~/.taskery/worktrees/<projectId>
20
20
  * - getWorktreePath(projectId, { taskNum, src, slug }): 특정 task 워크트리 경로
21
21
  * - getMergeLockPath(projectId): ~/.taskery/<projectId>.merge.lock
22
+ * - getInitLockPath(projectId): ~/.taskery/<projectId>.init.lock (task 분기 직렬화용)
22
23
  * - withMergeLock(projectId, fn, opts): proper-lockfile로 머지 락 + fn 실행 + 자동 release
23
24
  * - withMetaLock(filePath, fn, opts): 메타 파일 쓰기 락 + fn 실행
24
25
  * - getActiveTasks(mainWtPath): SSoT 조회 (git branch --no-merged dev --list 'feature/*_TASK-*' ...)
25
26
  * - getNextTaskNumber(mainWtPath): (진행중 ∪ dev 머지 히스토리) 최대 + 1
27
+ * - forkTask(mainWtPath, {type,dev,src,slug}): init 락 안에서 채번+워크트리·브랜치 생성 원자 실행
26
28
  * - assertMainWorktreeOnDev(mainWtPath): 메인 워크트리가 dev 체크아웃 상태인지 검증
27
29
  * - assertDevExists(mainWtPath): dev 브랜치 존재 검증
28
30
  *
@@ -254,6 +256,10 @@ function getMergeLockPath(projectId) {
254
256
  return path.join(TASKERY_HOME, `${projectId}.merge.lock`);
255
257
  }
256
258
 
259
+ function getInitLockPath(projectId) {
260
+ return path.join(TASKERY_HOME, `${projectId}.init.lock`);
261
+ }
262
+
257
263
  async function withMergeLock(projectId, fn, opts = {}) {
258
264
  const lockfile = require('proper-lockfile');
259
265
  const lockPath = getMergeLockPath(projectId);
@@ -369,6 +375,34 @@ function getNextTaskNumber(mainWtPath) {
369
375
  return Math.max(...all) + 1;
370
376
  }
371
377
 
378
+ async function forkTask(mainWtPath, { type, dev, src, slug }) {
379
+ // task 분기 — [채번 → 워크트리·브랜치 생성]을 init 락(withMetaLock)으로 원자화.
380
+ // 병렬 task-init이 같은 번호를 읽고 각자 브랜치를 만들던 레이스(TOCTOU)를 차단: 락 안에서
381
+ // getNextTaskNumber 직후 worktree add까지 끝내므로 다음 호출은 늘어난 번호를 본다.
382
+ const projectId = getProjectId(mainWtPath);
383
+ return withMetaLock(getInitLockPath(projectId), () => {
384
+ assertDevExists(mainWtPath);
385
+ assertMainWorktreeOnDev(mainWtPath);
386
+ // SSoT 안전망 — 같은 출처(BL-NNN/RM-NNN)가 이미 진행중이면 거부. DR은 별도 ID 없어 검사 제외.
387
+ if (src !== 'DR') {
388
+ const dup = getActiveTasks(mainWtPath).find((t) => t.src === src);
389
+ if (dup) {
390
+ throw new Error(`${src} 이미 진행중 (${dup.branch}) — 다른 세션이 같은 항목 진행`);
391
+ }
392
+ }
393
+ const taskNum = getNextTaskNumber(mainWtPath); // 락 안 → TOCTOU 차단
394
+ const nnn = String(taskNum).padStart(3, '0');
395
+ const branch = `${type}/${dev}_TASK-${nnn}_${src}_${slug}`;
396
+ const wtPath = getWorktreePath(projectId, { taskNum, src, slug });
397
+ mkdirp(getWorktreesRoot(projectId));
398
+ // 동일 브랜치명은 git이 거부(같은 항목 동시 분기 차단). 실패 시 throw → fork.js가 사용자 보고.
399
+ execFileSync('git', ['-C', mainWtPath, 'worktree', 'add', wtPath, '-b', branch, 'dev'], {
400
+ stdio: 'pipe',
401
+ });
402
+ return { taskNum, nnn, branch, wtPath, projectId };
403
+ });
404
+ }
405
+
372
406
  function computeNextPlanNumber(mainWtPath) {
373
407
  // .project/plans/ 하위 'NNN_<slug>' 디렉토리 스캔 → NNN max+1, 3자리 zero-pad 문자열 반환.
374
408
  // plan = 기능 그룹 단위, 폴더명 앞 3자리 채번(TASK-NNN과 결 맞춤). slug은 호출측(plan-init)이 결합.
@@ -589,6 +623,7 @@ module.exports = {
589
623
  getWorktreesRoot,
590
624
  getWorktreePath,
591
625
  getMergeLockPath,
626
+ getInitLockPath,
592
627
  withMergeLock,
593
628
  withMetaLock,
594
629
  assertDevExists,
@@ -596,6 +631,7 @@ module.exports = {
596
631
  parseBranchName,
597
632
  getActiveTasks,
598
633
  getNextTaskNumber,
634
+ forkTask,
599
635
  computeNextPlanNumber,
600
636
  // 백로그 (0.1.2+)
601
637
  BACKLOG_PLACEHOLDER,
package/bin/taskery.js CHANGED
@@ -9,6 +9,7 @@
9
9
  * update — 최신 버전 fetch + manifest 비교 + 머지 갱신
10
10
  * status — 멀티세션 현황 요약 (진행중 태스크 / 워크트리 / 머지 락, 0.1.2+)
11
11
  * prune — stale 워크트리 / 브랜치 대화형 정리 (0.1.2+)
12
+ * fork — task 분기 (채번+워크트리+브랜치 생성을 init 락으로 원자 실행, 0.3.2+)
12
13
  * help — 사용법 출력
13
14
  */
14
15
 
@@ -34,6 +35,7 @@ function help() {
34
35
  npx @angar2/taskery update 최신 버전 fetch + 머지 갱신
35
36
  npx @angar2/taskery status 멀티세션 현황 (진행중 태스크 / 워크트리 / 머지 락)
36
37
  npx @angar2/taskery prune stale 워크트리 / 브랜치 대화형 정리
38
+ npx @angar2/taskery fork <type> <dev> <src> <slug> task 분기 (통상 /task-init 경유)
37
39
  npx @angar2/taskery help 도움말
38
40
 
39
41
  새 프로젝트 시작:
@@ -74,6 +76,9 @@ switch (sub) {
74
76
  }
75
77
  runScript('prune.js');
76
78
  break;
79
+ case 'fork':
80
+ runScript('fork.js');
81
+ break;
77
82
  case 'help':
78
83
  case '--help':
79
84
  case '-h':
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angar2/taskery",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Lightweight task system for Claude Code & Codex — 1 메인 세션(또는 멀티세션) + 스킬 9종 + catastrophic hook 안전망 2종",
5
5
  "bin": {
6
6
  "taskery": "bin/taskery.js",
@@ -0,0 +1,145 @@
1
+ ---
2
+ name: run-team
3
+ description: agent teams로 다건 태스크를 독립 워크트리에서 자동 병렬 처리 — 리더 세션이 팀원(독립 세션)에게 태스크 1개씩 분배하고 흐름을 관리한다. 트리거 발화(예 "백로그 한 번에 진행해" / "팀에게 전부 독립으로 맡겨") 시에만 발동. Claude 전용 · 실험 기능(agent teams) 전제.
4
+ ---
5
+
6
+ # /run-team
7
+
8
+ ## 개요
9
+
10
+ 다건 태스크(백로그 여러 건 / 명시된 작업 묶음)를 **agent teams로 자동 병렬 처리**한다. 리더 메인 세션 1개가 작업을 태스크 단위로 묶어 결정하고, 각 태스크를 **팀원(독립 Claude Code 세션)** 에게 1개씩 맡긴다. 각 팀원은 taskery 태스크 5단계(`/task-init` ~ `/task-close`)를 *독립 워크트리*에서 수행한다.
11
+
12
+ 이 스킬이 추가하는 것은 *세션 오케스트레이션 레이어*뿐이다. **워크트리 격리는 `/task-init`이, 머지 직렬화·충돌 3단계 해결은 `/task-close`가 이미 담당**한다 — 본 스킬은 그 위에서 누가 어떤 태스크를 맡고 어디서 멈추는지만 조율한다.
13
+
14
+ > **taskery 기본 플로우가 아니다.** 디폴트는 *1세션 1태스크* (사용자가 직접 지시). 본 스킬은 *트리거 발화가 있을 때만* 발동하는 고기능이다. 평소 단일 태스크 흐름을 침범하지 않는다.
15
+
16
+ ## 팀원 = agent teams 팀원 (Task tool 서브에이전트 아님)
17
+
18
+ 본 스킬의 "팀원"은 **Claude Code의 agent teams 기능으로 생성되는 독립 세션**이다. **Task tool 서브에이전트로 대체하는 것을 영구 금지**한다 — 둘은 다르다.
19
+
20
+ | | Task tool 서브에이전트 (금지) | agent teams 팀원 (본 스킬) |
21
+ |---|---|---|
22
+ | 세션 | 리더 컨텍스트 *안*의 백그라운드 워커 | **독립 세션 · 자체 컨텍스트 윈도우** |
23
+ | 사용자 접근 | 직접 들어가 지시 불가 | **사용자가 직접 들어가 확인·지시 가능** |
24
+ | 통신 | 결과만 리더에 반환 | 팀원↔리더 자동 통지 + 팀원끼리 직접 통신 (리더가 다 봄) |
25
+ | 스킬 호출 | 제한적 | 프로젝트 `.claude/skills/` 그대로 로드 → taskery 5스킬 직접 호출 |
26
+
27
+ 팀원은 각자 새 세션으로 시작하며 프로젝트 `CLAUDE.md`를 자동 로드하므로 taskery 룰을 그대로 따른다.
28
+
29
+ ## 호출 시점
30
+
31
+ - **트리거 발화** — 다건을 한 번에 / 팀으로 / 독립 병렬로 처리하라는 의도:
32
+ - *"백로그 BL-003, 005, 007 한 번에 진행해"*
33
+ - *"백로그에 쌓인 거 묶을 수 있는 단위로 팀한테 전부 맡겨"*
34
+ - *"이 작업들 독립으로 병렬 처리해"*
35
+ - **단일 태스크 의도면 발동 금지** — *"로그인 기능 추가해줘"* 류 단건은 기존 `/task-init` 흐름. 본 스킬 진입 X.
36
+
37
+ ## 입력 처리
38
+
39
+ 인자 = (선택) 대상 작업 목록 / 중단점 모드. 예: `/run-team BL-003 BL-005 BL-007` / `/run-team BL-003~009 --until test` / 인자 없이 발화로.
40
+
41
+ - 대상이 모호하면 한 번에 한 질문씩 확인. **자동 추정으로 팀 가동 금지** — 태스크 묶음·팀원 수·중단점 모드 확정 후 진입.
42
+
43
+ ## 단계
44
+
45
+ ### Step 0 — 가드 (플랫폼 + 활성화)
46
+
47
+ 본 스킬 진입 즉시 두 가드를 통과해야 한다. 하나라도 실패 시 *팀을 만들지 말고* 안내 후 중단.
48
+
49
+ 1. **플랫폼 가드** — agent teams는 Claude 전용. 현재 세션이 Codex면 *"agent teams는 Claude 전용이라 Codex에서는 자동 병렬을 지원하지 않는다. 단일 태스크 흐름(`/task-init`)으로 진행하라"* 안내 + 중단. (본 스킬은 Claude 자산으로만 설치되므로 정상 경로에선 도달하지 않으나, 발화가 Codex 세션에 들어온 경우 대비.)
50
+ 2. **활성화 가드** — agent teams는 기본 비활성. 활성 여부 확인:
51
+ ```sh
52
+ [ "$CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS" = "1" ] || echo "agent teams 비활성"
53
+ ```
54
+ - 비활성이면 *팀 가동을 시작하지 말고* 다음을 안내 + 중단:
55
+ - *"agent teams는 실험 기능이라 기본 비활성이다. `~/.claude/settings.json`의 `env`에 `\"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS\": \"1\"`를 넣고 세션을 재시작한 뒤 다시 호출하라. (팀원을 split pane으로 보려면 `env`가 아닌 최상위에 `\"teammateMode\": \"tmux\"`도 — 기본값 `auto`는 환경 자동 감지 후 in-process 폴백.)"*
56
+ - 꺼진 채로 헛도는 것을 막기 위한 안전망이다.
57
+
58
+ ### Step 1 — 작업 수집
59
+
60
+ - 대상이 백로그면 `$MAIN_WT/.project/tasks/<활성 plan>/BACKLOG.md`에서 해당 BL 항목 정독 (개요 / 대상 영역).
61
+ ```sh
62
+ MAIN_WT=$(dirname "$(git rev-parse --path-format=absolute --git-common-dir)")
63
+ ```
64
+ - 대상이 명시 작업 목록이면 그 발화를 그대로.
65
+ - 활성 plan은 `$MAIN_WT/.project/AGENT-GUIDE.md`에서 검출.
66
+
67
+ ### Step 2 — 태스크 묶기 판단
68
+
69
+ 수집한 작업을 **태스크 단위로 묶는다**. 백로그 1건 = 태스크 1개가 *필수 아님* — 작업 범위·응집도에 따라 여러 건을 한 태스크로 묶거나 한 건을 그대로 둔다 (리더 판단).
70
+
71
+ - **응집 기준**: 같은 모듈·파일군을 건드리거나 의존 관계가 있으면 한 태스크로 묶어 *충돌·중복을 사전 회피*. 서로 독립이면 분리해 병렬 이득 확보.
72
+ - **팀원 수 권장 3~5** (agent teams 권장치). 결정된 태스크가 5개를 넘으면 *배치로 분할* — 1차 배치 완료(또는 중단점 도달) 후 2차 배치. 한 번에 다 띄우지 않는다 (토큰·조율 부담).
73
+ - 묶음 결과를 사용자에게 제시 + confirm: *"태스크 N개로 묶었다 — ① <묶음>(BL-003+005) ② <묶음>(BL-007) … 팀원 N명. 이대로 갈까?"*
74
+
75
+ ### Step 3 — 중단점 모드 결정
76
+
77
+ 각 팀원이 taskery 5단계 중 *어디까지 자동 진행하고 어디서 멈출지* 결정한다.
78
+
79
+ - **기본 = 단계별 정지** — 별도 지시가 없으면 각 팀원은 *한 단계 수행 후 멈추고 리더에 보고*. 사용자(또는 리더)가 다음 단계를 지시할 때까지 대기.
80
+ - **구간 자동** — 사용자 지시(*"init부터 test까지 자동으로"*, *"--until test"*)가 있으면 해당 구간을 멈춤 없이 진행.
81
+ - **`/task-close`(머지) 게이트 권장** — 자동 구간이라도 close는 *되돌릴 수 없는 dev 병합*이므로, 별도의 명시 지시가 없으면 close 직전에 멈춰 사용자 확인을 받도록 팀원에 지시한다.
82
+ - 모드는 팀원마다 다르게 줄 수 있다 (태스크별 난이도에 따라).
83
+
84
+ ### Step 4 — agent teams 팀원 생성 + 자기완결 지시
85
+
86
+ > **팀원은 agent teams 팀원으로만 생성**한다 (위 "팀원 = agent teams 팀원" 절). Task tool 서브에이전트 대체 영구 금지.
87
+
88
+ 리더가 결정한 태스크 수만큼 팀원을 만들고, 각 팀원에게 **태스크 1개 + 자기완결 지시**를 준다. 팀원 지시에 다음을 모두 포함한다 (팀원은 리더 컨텍스트를 공유하지 않으므로 *그 자체로 완결*되어야 한다):
89
+
90
+ 1. **맡을 작업** — 태스크 주제 / 출처(BL-NNN 등) / 묶음이면 포함 항목 전부 + 각 개요·대상 영역.
91
+ 2. **시작 위치** — *메인 워크트리(dev 체크아웃) cwd에서 `/task-init`을 먼저 호출*. `/task-init`이 독립 워크트리·브랜치를 분기한다.
92
+ 3. **이동** — `/task-init` 결과 보고에 출력된 *워크트리 경로로 cd*한 뒤 후속 단계(`/task-plan` 이후)를 그 워크트리에서 수행.
93
+ 4. **중단점 모드** — Step 3에서 정한 구간/정지 규칙. 예: *"`/task-init`과 `/task-plan`까지만 수행하고 멈춰 리더에 보고하라"*.
94
+ 5. **보고 의무** — 각 중단점 도달 시 *상태(어느 단계까지 / 결과 요약 / 막힌 점)* 를 리더에 보고.
95
+
96
+ - 여러 팀원이 동시에 메인 워크트리 cwd에서 `/task-init`을 호출해도, `/task-init`이 부르는 `fork` 명령이 **init 락으로 [채번~워크트리 분기]를 직렬화**(번호 충돌 차단)하고 브랜치명 유일성을 git이 보장하므로 충돌을 막는다. 각 팀원의 작업은 *물리적으로 분리된 워크트리 디렉토리*(`~/.taskery/worktrees/...`)에서 진행되므로 **agent teams의 "같은 파일 동시 편집 → 덮어쓰기" 제약이 구조적으로 회피된다.**
97
+
98
+ ### Step 5 — 모니터링
99
+
100
+ - 팀원이 중단점에 도달하거나 idle 상태가 되면 agent teams가 리더에 자동 통지한다 (폴링 불필요).
101
+ - 리더는 각 팀원의 보고를 모아 *사용자에게 한 곳에서 종합 보고*: *"팀원 ①은 TASK-007 plan 완료·대기 / 팀원 ②는 TASK-008 dev 진행 중 …"*.
102
+ - 사용자는 리더를 통해 다음 단계를 지시하거나, 특정 팀원 세션에 *직접 들어가* 지시할 수 있다 (in-process 화살표/Enter, 또는 `teammateMode` split pane).
103
+ - **task 상태 lag 주의** — 팀원이 단계 완료를 제때 마킹하지 못해 후속이 막히면, 리더가 해당 팀원에 *상태 갱신/진행을 한 번 nudge*한다.
104
+
105
+ ### Step 6 — 머지 조율
106
+
107
+ 각 팀원의 `/task-close`는 **머지 락으로 자동 직렬화**된다 (동시 close 시도해도 한쪽씩 순차). 리더가 추가로 할 일:
108
+
109
+ - 완료 순서를 *대기열로 관리* — 여러 팀원이 동시에 close 단계면 순차 진행을 안내.
110
+ - `/task-close`의 충돌 3단계(단순 자동 / 의미적 자료 / 판단 불가)는 각 팀원이 자체 수행한다. **판단 불가(4-c)에 이르면 팀원이 사용자 호출**하도록 되어 있으므로, 리더는 그 호출을 사용자에게 전달한다.
111
+ - 모든 태스크 close 후 *전체 결과를 종합 보고*: 머지된 TASK 목록 / 충돌 해결 내역 / 미완(중단점에서 멈춘 것) 목록.
112
+
113
+ ## 도구 가이드
114
+
115
+ - **Bash**: 메인 워크트리 검출 / 활성화 가드 확인 / BACKLOG·AGENT-GUIDE 정독용 경로 산출
116
+ - **Read**: `$MAIN_WT/.project/tasks/<활성 plan>/BACKLOG.md` / `$MAIN_WT/.project/AGENT-GUIDE.md`
117
+ - **agent teams (자연어)**: 팀원 생성 + 태스크별 지시 + 모니터링. (전용 슬래시 명령은 없음 — 리더가 자연어로 팀을 가동)
118
+ - **AskUserQuestion**: 태스크 묶음 / 팀원 수 / 중단점 모드 확인
119
+
120
+ ## 주의사항
121
+
122
+ - **agent teams 팀원으로만** — Task tool 서브에이전트 대체 영구 금지 (자체 컨텍스트·사용자 직접 접근·리더 관리가 본 스킬의 전제).
123
+ - **트리거 한정 발동** — 단일 태스크 의도에는 진입 금지. 기본 플로우(1세션 1태스크) 비침범.
124
+ - **두 가드 선통과** — 플랫폼(Claude) + 활성화(env) 미충족 시 팀을 만들지 말고 안내 후 중단.
125
+ - **워크트리·머지는 기존 스킬이 담당** — 본 스킬은 worktree를 직접 만들거나 머지하지 않는다. 팀원이 `/task-init`·`/task-close`를 호출하게 할 뿐. 본 스킬에서 git 명령 직접 실행 금지.
126
+ - **팀원 지시는 자기완결** — 리더 컨텍스트 미공유. 작업·시작 위치·이동·중단점·보고 의무를 지시에 모두 명시.
127
+ - **권장 3~5 팀원 / 초과 시 배치** — 토큰 비용은 팀원 수에 선형 증가. 한 번에 다 띄우지 않는다.
128
+ - **`/task-close` 게이트 보존 권장** — 자동 구간이라도 되돌릴 수 없는 머지는 사용자 확인 후.
129
+ - **in-process resume 취약** — agent teams는 `/resume`·`/rewind`로 in-process 팀원이 복원되지 않는다. 세션 중단 후 재개 시 *살아있지 않은 팀원에 메시지 시도*가 발생할 수 있으므로, 재개하면 팀원을 새로 만들고 진행 상태는 `npx @angar2/taskery status`로 재확인한다.
130
+ - **split pane 환경 의존** — 팀원을 분할 화면으로 보려면 tmux/iTerm2 필요. VS Code 통합 터미널 등은 in-process(화살표 전환)만 가능.
131
+
132
+ ## 상태 전이
133
+
134
+ | 진입 시 | 종료 시 |
135
+ |--------|--------|
136
+ | (해당 없음 — 오케스트레이터) | (해당 없음) |
137
+
138
+ 본 스킬은 task 상태를 직접 전이시키지 않는다. **상태 전이는 각 팀원이 호출하는 task 5스킬이 수행**한다 (`/task-init`=draft … `/task-close`=closed). 본 스킬은 누가 무엇을 어디까지 진행하는지만 조율한다.
139
+
140
+ ## 멀티세션 정합
141
+
142
+ - **기존 멀티세션 위에 얹힘** — taskery는 이미 *여러 메인 세션이 독립 워크트리로 병렬* 진행을 지원한다. 본 스킬은 그 "여러 세션"을 사용자가 일일이 띄우는 대신 *리더가 agent teams로 띄우고 관리*하게 하는 것뿐이다. 워크트리·머지 락·충돌 해결 정합은 기존과 동일.
143
+ - **머지 락** — `~/.taskery/<projectId>.merge.lock` 단일. 팀원들의 close가 직렬화된다.
144
+ - **race 차단** — 동시 `/task-init`은 브랜치명 유일성 + SSoT 2층으로 차단 (기존 `/task-init` 정합 그대로).
145
+ - **완료 추적** — `npx @angar2/taskery status` (진행 중 팀원/워크트리) + dev 머지 히스토리.
@@ -210,7 +210,7 @@ docs: [TASK-{NNN}] CHANGELOG 업데이트
210
210
 
211
211
  | 작업 | 명령 | 주체 |
212
212
  |------|------|------|
213
- | 생성 | `git -C "$MAIN_WT" worktree add "$WT_PATH" -b "$BRANCH" dev` | `/task-init` |
213
+ | 생성 | `npx @angar2/taskery fork <type> <dev> <src> <slug>` (내부: init 락 + `worktree add -b`) | `/task-init` |
214
214
  | 제거 | `git -C "$MAIN_WT" worktree remove "$WT_PATH"` | `/task-close` (자동 흐름 + 안전 검증) |
215
215
  | stale 정리 | `git -C "$MAIN_WT" worktree prune` | `npx @angar2/taskery prune` (사용자 확인 후) |
216
216
 
@@ -304,5 +304,6 @@ git -C "$MAIN_WT" branch --no-merged dev --list \
304
304
  | 2026-05-31 | 0.1.2 백로그 스킬 추가 정합 — 출처 표 `BL-NNN` 채번 주체 `/backlog-add` → `/add-backlog`로 갱신 + 버전별 경로(`.project/tasks/<vX.X>/BACKLOG.md`) 명시 |
305
305
  | 2026-06-02 | 0.1.3 F2·F3 정합 — §멀티세션 워크트리 정책 *메인 HEAD 떼기 금지* + *모호 발화 자의 해석 금지* / §git-guard.sh 5종 변형 인식 (-C / --git-dir / --work-tree) + 셸 prefix 금지 명시. stash FRICTION_LOG 2026-06-01 반영 |
306
306
  | 2026-06-25 | 추적 변경 0(코드 0 · `.project` gitignore) close 시 마커 빈커밋으로 분기·채번 정보 보존 — `--no-ff` 머지 커밋 미생성 케이스의 `--allow-empty` 유일 예외 명시 (상세: task-close Step 6-8). FRICTION 검토 F1 반영 |
307
+ | 2026-06-28 | 워크트리 생성 메커니즘 갱신 — `git worktree add` 직접 실행 → `npx @angar2/taskery fork`(init 락 안에서 채번+분기 원자 실행). 병렬 task-init 번호 충돌(레이스) 차단 |
307
308
  | 2026-06-25 | §멀티세션 워크트리 정책에 "워크트리 실행 환경" 추가 — 워크트리에 의존성 심링크 금지(개발 서버 fs 접근 제한으로 로딩 실패), 실행·검수 task는 워크트리 안에 의존성 실제 마련. FRICTION 검토 F6 반영 |
308
309
  | 2026-06-25 | §멀티세션 워크트리 정책에 "멀티세션 검수 환경" 추가 — task별 dev 서버 포트 격리(메인=기준 포트, task=기준+TASK번호) + 터널 독립 + close 시 자기 것만 종료(광역 종료 금지) + 사용자 검수 시점 서버 자동 기동(task-test UNCERTAIN/PASS·task-dev 종료, FAIL 제외). FRICTION 검토 F7 반영 |
@@ -57,6 +57,15 @@
57
57
 
58
58
  ---
59
59
 
60
+ ## agent teams 자동 병렬 — Codex 미지원
61
+
62
+ > 다건 태스크를 리더가 팀원(독립 세션)에 분배해 자동 병렬 처리하는 고기능(`/run-team`)은 **Claude 전용**이다 — 기반인 agent teams 기능이 Codex에 없다.
63
+
64
+ - *"백로그 한 번에 진행해"* / *"팀에게 전부 독립으로 맡겨"* 류 자동 병렬 발화가 들어와도 Codex에서는 지원하지 않는다. **단일 태스크 흐름**(`/task-init` ~ `/task-close`)으로 안내하고 진행한다.
65
+ - 멀티세션 병렬 자체(사용자가 워크트리별 세션을 직접 띄워 진행)는 Codex에서도 가능 — 자동화(리더가 팀을 띄우고 관리)만 미지원이다.
66
+
67
+ ---
68
+
60
69
  ## 백로그 (0.1.2+)
61
70
 
62
71
  > `.project/tasks/<NNN_slug>/BACKLOG.md` = *plan(기능 그룹)별 task 후보 누적*. 사용자 발화로 1건씩 얕은 분석(개요 / 대상 영역) 곁들여 추가.
@@ -52,6 +52,19 @@
52
52
 
53
53
  ---
54
54
 
55
+ ## agent teams 자동 병렬 (Claude 전용 · 실험 · 트리거 한정)
56
+
57
+ > 다건 태스크를 *리더 메인 세션 1개가 agent teams로 팀원(독립 세션)에 분배*해 자동 병렬 처리하는 고기능. 위 멀티세션을 사용자가 일일이 띄우는 대신 리더가 띄우고 관리한다. 워크트리 격리·머지 직렬화는 기존 `/task-init`·`/task-close`가 그대로 담당.
58
+
59
+ - **기본 플로우 아님** — 디폴트는 *1세션 1태스크*. *트리거 발화*(예: *"백로그 한 번에 진행해"* / *"팀에게 전부 독립으로 맡겨"*)가 있을 때만 `/run-team` 발동. 단일 태스크 의도(*"~ 기능 추가해줘"*)는 기존 `/task-init` 흐름.
60
+ - **활성화 전제** — agent teams는 실험 기능이라 기본 비활성. `~/.claude/settings.json`의 `env`에 `"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"` 설정 후 세션 재시작. (팀원을 split pane으로 보려면 최상위에 `"teammateMode": "tmux"`도 — `teammateMode`는 `env`가 아닌 최상위 키이며 기본값 `auto`는 환경 자동 감지 후 in-process 폴백.) 미설정이면 `/run-team`이 안내하고 중단(헛도는 것 방지).
61
+ - **팀원 = agent teams 팀원** — Task tool 서브에이전트 아님(독립 세션 · 자체 컨텍스트 · 사용자 직접 접근 가능).
62
+ - **Claude 전용** — agent teams가 Codex에 없어 Codex에서는 미지원.
63
+
64
+ 상세: `.claude/skills/run-team/SKILL.md`.
65
+
66
+ ---
67
+
55
68
  ## 백로그 (0.1.2+)
56
69
 
57
70
  > `.project/tasks/<NNN_slug>/BACKLOG.md` = *plan(기능 그룹)별 task 후보 누적*. 사용자 발화로 1건씩 얕은 분석(개요 / 대상 영역) 곁들여 추가.
@@ -123,7 +136,7 @@
123
136
 
124
137
  ---
125
138
 
126
- ## 스킬 9종 — project > plan > task 위계 + 회고
139
+ ## 스킬 — 공통 9종 + Claude 전용 1종(run-team)
127
140
 
128
141
  | 스킬 | 레벨 | 역할 |
129
142
  |------|------|------|
@@ -136,9 +149,12 @@
136
149
  | `/task-close` | task | 검증 명령 게이트 + 커밋 + dev 병합 (tested → closed) |
137
150
  | `/add-backlog` | meta | 사용자 발화로 활성 plan BACKLOG.md에 항목 1건 추가 (얕은 분석 + BL-NNN 채번 — 0.1.2+) |
138
151
  | `/log-friction` | meta | FRICTION_LOG.md에 사용자 불편 한 행 기록 |
152
+ | `/run-team` | meta · **Claude 전용** | agent teams로 다건 태스크를 팀원(독립 세션)에 분배해 자동 병렬 처리 — 트리거 발화 시에만 (실험 기능 전제). 위 "agent teams 자동 병렬" 섹션 참조 |
139
153
 
140
154
  본문은 `.claude/skills/<스킬>/SKILL.md` 참조.
141
155
 
156
+ > `/run-team`은 Claude 전용 — agent teams(실험 기능)가 Codex에 없어 Codex 설치에는 미포함.
157
+
142
158
  ---
143
159
 
144
160
  ## Hook 안전망 — Catastrophic 2종
@@ -93,26 +93,9 @@ description: task 시작 — 워크트리 분기 + 6 섹션 빈 골격 + 헤더
93
93
 
94
94
  ### Step 4 — TASK 번호 결정 + 결정적 슬러그 + SSoT 안전망
95
95
 
96
- #### 4.1 다음 TASK-NNN 계산
96
+ #### 4.1 TASK 번호는 Step 6 `fork`가 채번
97
97
 
98
- `bin/lib.js` `getNextTaskNumber(MAIN_WT)` 호출. 내부 동작:
99
- ```sh
100
- # 진행중 (SSoT) — TASK-* 패턴 작업 브랜치 전체. `--no-merged dev` 미사용:
101
- # 워크트리 분기 직후 브랜치는 dev와 동일 commit이라 `--no-merged dev`가 *완전 머지 상태*로
102
- # 처리 → 빈 결과 → getNextTaskNumber 충돌. 브랜치 존재 자체가 SSoT.
103
- A=$(git -C "$MAIN_WT" branch --list \
104
- 'feature/*_TASK-*' 'bug/*_TASK-*' 'improve/*_TASK-*' \
105
- 'refactor/*_TASK-*' 'docs/*_TASK-*' 'chore/*_TASK-*' \
106
- | grep -oE 'TASK-[0-9]+')
107
- # dev 머지 히스토리
108
- B=$(git -C "$MAIN_WT" log dev --grep='TASK-[0-9]\+' --extended-regexp --oneline \
109
- | grep -oE 'TASK-[0-9]+')
110
- # 합집합 최대 + 1
111
- MAX=$( (echo "$A"; echo "$B") | sort -uV | tail -1 | sed 's/TASK-//')
112
- NEXT=$((MAX + 1))
113
- ```
114
- - 3자리 zero-padded (`001`, `015`, `120`).
115
- - 합집합 비어 있으면 `001`.
98
+ TASK-NNN은 **여기서 미리 계산하지 않는다.** 번호 읽기와 워크트리·브랜치 생성을 분리하면 병렬 task-init이 같은 번호를 읽는 레이스(TOCTOU)가 난다. 채번은 Step 6 `npx @angar2/taskery fork`가 **init 락 안에서 생성과 한 덩어리로** 수행한다 (읽기 직후 분기까지 원자 실행 → 동시 호출은 늘어난 번호를 봄). 확정 번호(`nnn`)는 fork 반환 JSON에서 받는다.
116
99
 
117
100
  #### 4.2 메타 가져오기 (BL/RM)
118
101
 
@@ -134,16 +117,9 @@ NEXT=$((MAX + 1))
134
117
  - 한국어 → 영어 kebab-case. 짧고 명확하게 (3 단어 이내 권장).
135
118
  - 같은 항목이면 같은 슬러그 → 같은 브랜치명 → git이 동시 분기 자동 거부 (race 차단 1층).
136
119
 
137
- #### 4.4 SSoT 안전망 (race 차단 2층)
120
+ #### 4.4 SSoT 안전망 (fork가 락 안에서 수행)
138
121
 
139
- ```sh
140
- git -C "$MAIN_WT" branch --no-merged dev --list \
141
- 'feature/*_TASK-*' 'bug/*_TASK-*' 'improve/*_TASK-*' \
142
- 'refactor/*_TASK-*' 'docs/*_TASK-*' 'chore/*_TASK-*' \
143
- | grep -E "_${SRC}_"
144
- ```
145
- - BL-NNN/RM-NNN이 *진행중*에 있으면 → 중단 + 사용자 알림 (*"BL-003은 이미 X 세션에서 진행 중"*).
146
- - DR은 본 안전망 검사 X (별도 ID 없음).
122
+ 같은 출처(BL-NNN/RM-NNN)가 이미 *진행중*이면 분기를 거부하는 안전망은 **Step 6 `fork`가 init 락 안에서 권위적으로 수행**한다 (채번과 동일 임계구역 → 별도 racy 중복검사 불필요). 진행중이면 fork가 *"BL-003 이미 진행중 (…브랜치)"* 로 실패하고, 스킬은 그 메시지로 중단 + 사용자 알림. DR은 별도 ID가 없어 본 검사 제외.
147
123
 
148
124
  ### Step 5 — 파일 vs 폴더 결정 + 브랜치명 산출
149
125
 
@@ -159,20 +135,21 @@ git -C "$MAIN_WT" branch --no-merged dev --list \
159
135
  ```
160
136
  - **타입**: feature → `feature`, bug → `bug`, improvement → `improve`, refactor → `refactor`, docs → `docs`, chore → `chore`
161
137
  - **개발자**: 메인 세션 = `claude`, 사용자 세션 = `angar2` 등
162
- 3. 사용자에게 브랜치명 + 파일/폴더 confirm.
138
+ - **NNN은 Step 6 `fork`가 확정** — confirm 시점엔 미정(`TASK-???`). 분기 전 번호 못 박기는 병렬 레이스 차단의 귀결.
139
+ 3. 사용자에게 브랜치 구성요소(`{타입}/{개발자}_TASK-???_{출처}_{슬러그}`) + 파일/폴더 confirm. 확정 NNN은 fork 후 §8에서 보고.
140
+
141
+ ### Step 6 — 워크트리 분기 (`fork` — 채번+생성 원자 실행)
163
142
 
164
- ### Step 6 — 워크트리 생성
143
+ `npx @angar2/taskery fork <타입> <개발자> <출처> <슬러그>` 한 번으로 **채번 → 워크트리·브랜치 생성**을 init 락 안에서 원자 실행한다 (Step 4.1 채번 + 본 단계 생성이 한 임계구역 → 병렬 task-init 번호 충돌 차단).
165
144
 
166
145
  ```sh
167
- PROJECT_ID=$(jq -r '.projectId' "$MAIN_WT/.taskery-manifest.json")
168
- WORKTREES_ROOT="$HOME/.taskery/worktrees/$PROJECT_ID"
169
- WT_PATH="$WORKTREES_ROOT/TASK-${NNN}_${SRC}_${SLUG}"
170
- mkdir -p "$WORKTREES_ROOT"
171
- git -C "$MAIN_WT" worktree add "$WT_PATH" -b "$BRANCH" dev
146
+ npx @angar2/taskery fork "$TYPE" "$DEV" "$SRC" "$SLUG"
147
+ # 예: npx @angar2/taskery fork feature claude BL-003 login-feature
172
148
  ```
173
149
 
174
- - git이 동일 브랜치명 자동 거부 (race 차단 1층).
175
- - 동시 충돌 시 *"브랜치 이미 존재 — 다른 세션이 같은 항목 진행 중"* 보고 + 중단.
150
+ - 성공 시 결과 JSON 한 줄 출력 — `{ "taskNum", "nnn", "branch", "wtPath", "projectId" }`. 이후 단계(§7 문서 / §7.5 BL 마킹 / §8 보고)는 이 반환값의 `nnn` · `branch` · `wtPath`를 사용한다.
151
+ - fork가 락 안에서 함께 수행: 채번(TOCTOU 차단) + SSoT 안전망(§4.4) + 동일 브랜치명 거부(git — 같은 항목 동시 분기 차단).
152
+ - fork 비정상 종료(exit 1) 시 stderr 메시지(*"… 이미 진행중"* / *"… 정책 위배"* 등)를 그대로 사용자에게 보고 + 중단.
176
153
 
177
154
  ### Step 7 — task 문서 위치 결정 + 빈 골격 작성
178
155
 
@@ -237,6 +214,8 @@ git -C "$MAIN_WT" check-ignore -q "$MAIN_WT/.project/dummy"
237
214
 
238
215
  ### Step 8 — 결과 보고
239
216
 
217
+ `<NNN>` · `<WT_PATH>` · `<BRANCH>`는 Step 6 fork 반환 JSON의 `nnn` · `wtPath` · `branch` 값으로 채운다.
218
+
240
219
  ```
241
220
  ✅ TASK-<NNN> 생성 완료
242
221
  - 워크트리: <WT_PATH>
@@ -249,7 +228,7 @@ git -C "$MAIN_WT" check-ignore -q "$MAIN_WT/.project/dummy"
249
228
 
250
229
  ## 도구 가이드
251
230
 
252
- - **Bash**: 메인 워크트리 검출 / 사전 검증 / `git worktree add` / SSoT 조회 / TASK-NNN 계산
231
+ - **Bash**: 메인 워크트리 검출 / 사전 검증 / `npx @angar2/taskery fork` 호출(채번+워크트리·브랜치 생성) / 결과 JSON 파싱
253
232
  - **Read**: `$MAIN_WT/.project/AGENT-GUIDE.md` / `$MAIN_WT/.project/tasks/<활성 plan>/BACKLOG.md` / `$MAIN_WT/.project/plans/<활성 plan>/ROADMAP.md`
254
233
  - **Write**: task.md 빈 골격 작성 (위치는 .gitignore 케이스에 따라)
255
234
  - **AskUserQuestion**: 분기 2 인터뷰 (한 번에 한 질문)
@@ -258,16 +237,16 @@ git -C "$MAIN_WT" check-ignore -q "$MAIN_WT/.project/dummy"
258
237
 
259
238
  - **워크트리 생성 + task 문서 작성만 담당** — 본문 채우기 금지. Requirements / Scope / Dev Plan / Test Plan 본문은 *반드시* `/task-plan`에서.
260
239
  - **단계 경계 — 허용/금지 명시 (stash FRICTION_LOG #11 반영)**:
261
- - **허용 (화이트리스트)**: `$MAIN_WT/.project/plans/<활성 plan>/ROADMAP.md` §4(다음 작업 영역) 확인 / SSoT 조회 / TASK-NNN 계산 / 빈 골격 Write
240
+ - **허용 (화이트리스트)**: `$MAIN_WT/.project/plans/<활성 plan>/ROADMAP.md` §4(다음 작업 영역) 확인 / SSoT 조회 / `fork` 호출(채번+분기) / 빈 골격 Write
262
241
  - **금지 (블랙리스트)**: ARCHITECTURE.md / API-SPEC.md / FEATURES.md 등 `.project/` 루트 제품 관통 문서 본문 Read / 도메인 코드 Read · Grep / 기존 task 본문 Read
263
242
  - 본문 정보 수집은 *다음 단계 `/task-plan`*에서 수행.
264
243
  - **자동 추정 진행 X** — 직전 맥락 명확해도 *제안 + 사용자 OK* 거친 후 워크트리/파일 생성.
265
244
  - **상태는 `draft` 고정** — `/task-init` 끝의 상태는 `draft` 외 작성 금지.
266
- - **NNN 충돌 회피** — SSoT 조회로 진행중 + dev 머지 히스토리 합집합 확인.
245
+ - **NNN 충돌 회피** — `fork`가 init 락 안에서 채번(진행중 ∪ dev 머지 히스토리 최대+1)과 워크트리 생성을 원자 실행 (병렬 task-init도 안전).
267
246
  - **slug 한국어 잔존 X** — 영어 kebab-case로 변환.
268
247
  - **헤더 5컬럼 모두 채움** — *"미정"* placeholder 작성 금지.
269
248
  - **메인 워크트리 검출 실패 시 즉시 중단** — git 버전 / 정책 위배 / dev 부재 등 안전망. 묵묵히 진행 X.
270
- - **race 발생 시 사용자 호출** — `git worktree add` 실패(같은 브랜치명) → SSoT 재조회 + 사용자에게 *"X 세션이 같은 항목 진행 중"* 알림.
249
+ - **race 발생 시 사용자 호출** — `fork` 실패(같은 브랜치명 / 같은 출처 진행중) → stderr 메시지 그대로 사용자에게 *"다른 세션이 같은 항목 진행 중"* 알림 + 중단.
271
250
 
272
251
  ## 상태 전이
273
252