uctm 2.0.0 → 2.0.2

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uc-taskmanager",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "agents": [
5
5
  "./agents/orchestrator.md",
6
6
  "./agents/specifier.md",
package/README.md CHANGED
@@ -434,6 +434,20 @@ Main Claude ── spawn once (mode=gated|auto) ──▶ orchestrator
434
434
  - `mode=auto`: no gates — orchestrator completes the entire diagram in one spawn and records any judgment calls to `DECISIONS.md`.
435
435
  - STEP C (the builder → verifier → committer loop) never gates on the user, in either mode.
436
436
 
437
+ ### Degraded Mode (nested spawn unavailable)
438
+
439
+ Some CLI builds do not inject the `Agent` tool into sub-agents, which makes the nested spawn above impossible. Before reading any file, orchestrator checks its own tool list and — if `Agent` is missing — returns immediately without creating a single artifact:
440
+
441
+ ```xml
442
+ <capability-degraded reason="no-agent-tool">
443
+ <detail>Agent tool not injected into sub-agent; nested spawn unavailable</detail>
444
+ </capability-degraded>
445
+ ```
446
+
447
+ **Main Claude then takes over the orchestrator role**: it reads `orchestrator.md` plus the 5 reference files and runs the same procedure, spawning the five children directly at depth 1. ref-cache assembly, the activity log, TASK DAG scheduling, and the retry rules are all unchanged; gates are raised by asking the user directly instead of via `<gate>` XML.
448
+
449
+ > This check exists because the failure is silent otherwise. Without it, orchestrator performs every role inline and reports success — the WORK looks complete while role separation and verification independence are gone.
450
+
437
451
  ### Stage Detail
438
452
 
439
453
  ```
@@ -463,7 +477,7 @@ Six agents work together in a clean, isolated pipeline — Main Claude spawns on
463
477
 
464
478
  ### Support Files (included in Plugin)
465
479
 
466
- In addition to the 6 pipeline agents, the plugin includes 7 support files that agents reference at startup.
480
+ In addition to the 6 pipeline agents, the plugin includes 6 support files. **Only the orchestrator reads them** — child agents receive the sections they need via ref-cache (see below).
467
481
  These are located in `plugin/references/` (synced from `develop/references/`); when installed via npm they land in `.claude/references/`:
468
482
 
469
483
  | File | Purpose |
@@ -471,10 +485,11 @@ These are located in `plugin/references/` (synced from `develop/references/`); w
471
485
  | `agent-flow.md` | Pipeline orchestration rules — Main Claude's trigger/gate boundary + orchestrator's internal nested-spawn flow |
472
486
  | `context-policy.md` | Sliding window context transfer rules between agents |
473
487
  | `file-content-schema.md` | Single source of truth for all file formats (PLAN.md, TASK.md, progress.md, result.md) |
474
- | `ref-cache-protocol.md` | 4-step ref-cache protocol checks `<ref-cache>` in the dispatch XML and skips disk reads when cached references are present |
475
- | `shared-prompt-sections.md` | Shared prompt sections with cache_control — reduces repeated token cost up to 90% |
488
+ | `shared-prompt-sections.md` | Shared prompt sections reused across agents |
476
489
  | `work-activity-log.md` | Activity log format for builder stage tracking |
477
- | `xml-schema.md` | XML communication format for dispatch and task-result messages |
490
+ | `xml-schema.md` | XML communication format for dispatch and task-result messages — also the normative ref-cache protocol (§ 4) |
491
+
492
+ Each of the five files consumed via ref-cache (`context-policy`, `file-content-schema`, `shared-prompt-sections`, `work-activity-log`, `xml-schema`) carries a **section consumption matrix** at the top, declaring which agents need which `§` sections. That matrix is what the orchestrator slices against.
478
493
 
479
494
  ---
480
495
 
@@ -650,17 +665,17 @@ Each agent file follows a consistent four-section structure:
650
665
 
651
666
  ### ref-cache: Reference File Caching
652
667
 
653
- Each agent reads 4-5 shared reference files (shared-prompt-sections.md, file-content-schema.md, xml-schema.md, etc.) on startup — totaling ~26 file reads across a full pipeline. **ref-cache** eliminates this redundancy:
668
+ Without caching, every agent re-reads 3-5 shared reference files at startup — roughly 40+ reads across a 3-TASK pipeline. **ref-cache** makes the orchestrator the single reader:
654
669
 
655
- 1. **First agent** (orchestrator itself, per its STARTUP step) reads reference files normally and can return `<ref-cache>` when nesting the next agent's dispatch
656
- 2. **Orchestrator** copies ref-cache into each nested child's dispatch instead of Main Claude relaying it
657
- 3. **Subsequent nested agents** use cached content instead of reading files from disk
670
+ 1. **Orchestrator** reads the 5 reference files once at startup, and parses each file's section consumption matrix
671
+ 2. **Before every nested spawn**, it slices out only the `§` sections that specific child needs and assembles a `<ref-cache>` with a `sections="..."` attribute per file
672
+ 3. **Child agents never touch disk** for references reading anything under `{REFERENCES_DIR}` is prohibited. Each child cross-checks the received `sections` against its own required-section list, and escalates a `<needs-decision>` if anything is missing rather than falling back to a disk read
658
673
 
659
- The protocol itself is defined in `references/ref-cache-protocol.md` (4 steps). Phase 2 (selective delivery) further reduces token usage by passing only the sections each agent needs — not the full file contents. The section mapping per agent is defined in `agent-flow.md`.
674
+ The protocol is normatively defined in `references/xml-schema.md` § 4. The per-agent section mapping lives in the **section consumption matrix at the top of each reference file** — not in a separate mapping document, so a file and its distribution rules stay together.
660
675
 
661
- **Measured impact** (3 agents):
662
- - File reads: 14 → 5 (**-64%**)
663
- - Token usage: ~85K ~72K (**-15%**)
676
+ **Design target** (3-TASK WORK):
677
+ - Reference file reads: ~42**5** (orchestrator startup only)
678
+ - Token usage: reduced proportionally to section slicing — each child receives only its own sections instead of whole files
664
679
 
665
680
  ### WORK ID Assignment Strategy
666
681
 
@@ -878,14 +893,13 @@ uc-taskmanager/
878
893
  │ │ ├── builder.md ← Code implementation
879
894
  │ │ ├── verifier.md ← Build/lint/test verification
880
895
  │ │ └── committer.md ← git commit + result.md
881
- │ ├── references/ ← 7 support files (shared across agents)
896
+ │ ├── references/ ← 6 support files (read by the orchestrator only)
882
897
  │ │ ├── agent-flow.md ← Pipeline orchestration rules
883
898
  │ │ ├── context-policy.md ← Sliding window context rules
884
899
  │ │ ├── file-content-schema.md ← File format definitions
885
- │ │ ├── ref-cache-protocol.md ref-cache protocol (4 steps)
886
- │ │ ├── shared-prompt-sections.md ← Cacheable shared sections
900
+ │ │ ├── shared-prompt-sections.md Shared reusable sections
887
901
  │ │ ├── work-activity-log.md ← Activity log format
888
- │ │ └── xml-schema.md ← XML communication format
902
+ │ │ └── xml-schema.md ← XML communication format + ref-cache protocol (§ 4)
889
903
  │ ├── skills/ ← Skill definitions (sdd-pipeline, uctm-init, work-pipeline, work-status)
890
904
  │ └── .claude-plugin/
891
905
  │ └── plugin.json ← Plugin manifest source (name, version, agents array)
package/agents/builder.md CHANGED
@@ -30,15 +30,9 @@ model: sonnet
30
30
 
31
31
  ### 3-1. 사전작업
32
32
 
33
- #### STEP 1. STARTUP — 레퍼런스 파일 즉시 읽기 (필수)
33
+ #### STEP 1. STARTUP — 레퍼런스 참조
34
34
 
35
- **REFERENCES_DIR 확인**: 입력에서 `REFERENCES_DIR=...` 라인 또는 `<references-dir>` XML 요소를 확인. 해당 절대 경로 사용. 없으면 `.claude/references`를 기본값으로 사용.
36
-
37
- `{REFERENCES_DIR}/`에서 다음 파일을 읽기:
38
- 1. `file-content-schema.md`
39
- 2. `shared-prompt-sections.md`
40
- 3. `xml-schema.md`
41
- 4. `context-policy.md`
35
+ `<ref-cache>`를 참조하여 작업을 수행한다.
42
36
 
43
37
  ### 3-2. 구현
44
38
 
@@ -29,16 +29,9 @@ model: haiku
29
29
 
30
30
  ### 3-1. 사전작업
31
31
 
32
- #### STEP 1. STARTUP — 레퍼런스 파일 즉시 읽기 (필수)
32
+ #### STEP 1. STARTUP — 레퍼런스 참조
33
33
 
34
- **REFERENCES_DIR 확인**: 입력에서 `REFERENCES_DIR=...` 라인 또는 `<references-dir>` XML 요소를 확인. 해당 절대 경로 사용. 없으면 `.claude/references`를 기본값으로 사용.
35
-
36
- `{REFERENCES_DIR}/`에서 다음 파일을 읽기:
37
- 1. `file-content-schema.md`
38
- 2. `shared-prompt-sections.md`
39
- 3. `xml-schema.md`
40
- 4. `context-policy.md`
41
- 5. `work-activity-log.md` (STEP 3의 마지막 TASK 판정을 위해 이벤트 형식 참조 — 로그 기록 목적 아님)
34
+ `<ref-cache>`를 참조하여 작업을 수행한다.
42
35
 
43
36
  ### 3-2. 커밋 수행
44
37
 
@@ -58,7 +51,7 @@ model: haiku
58
51
 
59
52
  #### STEP 2. 결과 보고서 생성
60
53
 
61
- → `{REFERENCES_DIR}/file-content-schema.md` § 3 참조 (형식 + 언어별 섹션 헤더)
54
+ → `file-content-schema.md` § 3 참조 (형식 + 언어별 섹션 헤더)
62
55
 
63
56
  `works/{WORK_ID}/TASK-XX_result.md` 생성.
64
57
  - builder context-handoff `what` → "Builder Context" 섹션
@@ -75,7 +68,7 @@ STAGE_DONE(stage=committer) 수 + 1 (현재) >= 전체 TASK 수이면:
75
68
  WORK-LIST.md에서 IN_PROGRESS → DONE으로 변경 (행 제거나 폴더 이동 금지)
76
69
  ```
77
70
 
78
- → `{REFERENCES_DIR}/shared-prompt-sections.md` § 8 참조
71
+ → `shared-prompt-sections.md` § 8 참조
79
72
 
80
73
  #### STEP 4. Git 확인
81
74
 
@@ -154,7 +147,7 @@ Committer 전용 추가 필드:
154
147
  </next-tasks>
155
148
  ```
156
149
 
157
- → `{REFERENCES_DIR}/shared-prompt-sections.md` § 8 참조
150
+ → `shared-prompt-sections.md` § 8 참조
158
151
 
159
152
  #### 출력 규칙
160
153
  - task-result XML **만** 반환. XML 앞뒤에 요약, 설명, 부연을 추가하지 말 것.
@@ -40,8 +40,40 @@ model: opus
40
40
 
41
41
  ### 3-1. 사전작업
42
42
 
43
+ #### STEP 0. 능력 확인 — 중첩 spawn 가능 여부 (최우선)
44
+
45
+ **다른 어떤 일보다 먼저 수행한다. 파일을 읽기 전에 판정한다.**
46
+
47
+ 자신의 도구 목록에 `Agent` 도구가 있는지 확인한다.
48
+
49
+ | 판정 | 처리 |
50
+ |------|------|
51
+ | `Agent` 있음 | 정상 경로 — STEP 1로 진행 |
52
+ | `Agent` 없음 | **축퇴** — 아래 절차 |
53
+
54
+ **축퇴 시 (`Agent` 도구 없음)**
55
+
56
+ 일부 CLI 버전·환경에서는 서브에이전트에 `Agent` 도구가 주입되지 않아 중첩 spawn이 불가능하다. 이때:
57
+
58
+ 1. **어떤 작업도 인라인으로 수행하지 않는다.** specifier/planner/builder/verifier/committer 역할을 스스로 대신하는 것은 **금지**다.
59
+ 2. **어떤 파일도 읽지 않는다.** 레퍼런스도, 다른 문서도 읽지 않는다. `Read`/`Glob`/`Grep`을 **단 한 번도 호출하지 않는다.**
60
+ 3. WORK 폴더·Requirement.md·PLAN.md 등 산출물을 만들지 않는다. 활동 로그도 기록하지 않는다.
61
+ 4. **첫 응답으로** 아래 XML을 그대로 반환하고 **즉시 종료**한다.
62
+
63
+ ```xml
64
+ <capability-degraded reason="no-agent-tool">
65
+ <detail>서브에이전트에 Agent 도구가 주입되지 않아 중첩 spawn 불가</detail>
66
+ </capability-degraded>
67
+ ```
68
+
69
+ > 위 XML이 반환에 필요한 전부다. **형식을 확인하려고 `xml-schema.md`를 읽지 말 것** — 위 블록을 그대로 복사하면 된다. 이 단계에서 어떤 파일이든 읽는 것은 규칙 위반이다.
70
+
71
+ > ⚠️ 이 판정을 무시하고 혼자 파이프라인을 수행하면, 겉보기에는 WORK가 완료된 것처럼 보이지만 실제로는 단일 에이전트가 모든 역할을 수행한 것이 되어 파이프라인의 역할 분리·검증 독립성이 모두 무너진다. 오류 없이 조용히 잘못되는 것이 가장 위험하므로 **반드시 즉시 반환**한다.
72
+
43
73
  #### STEP 1. STARTUP — 레퍼런스 파일 즉시 읽기 (필수)
44
74
 
75
+ > **선행 조건**: STEP 0에서 `Agent` 도구가 있다고 판정된 경우에만 이 단계를 수행한다. 축퇴로 판정됐으면 이 단계에 진입하지 않는다.
76
+
45
77
  **REFERENCES_DIR 확인**: 입력에서 `REFERENCES_DIR=...` 라인 또는 `<references-dir>` XML 요소를 확인. 해당 절대 경로 사용. 없으면 `.claude/references`를 기본값으로 사용.
46
78
 
47
79
  `{REFERENCES_DIR}/`에서 다음 파일을 읽기:
@@ -51,7 +83,44 @@ model: opus
51
83
  4. `work-activity-log.md`
52
84
  5. `context-policy.md`
53
85
 
54
- 5개 파일 내용은 자식에게 중첩 spawn할 `<ref-cache>`(→ `xml-schema.md` § 4) 재전달할 있다 자식이 동일 파일을 다시 읽지 않도록 한다.
86
+ **레퍼런스를 읽는 주체는 orchestrator 하나뿐이다.** 자식은 디스크를 읽지 않고 orchestrator가 전달한 `<ref-cache>`만 사용한다(→ `xml-schema.md` § 4). 따라서 5회 읽기가 WORK 전체에서 발생하는 유일한 레퍼런스 읽기다.
87
+
88
+ 각 파일 상단의 **`## 섹션 소비 매트릭스`** 표를 함께 파싱해 자식별 섹션 배분표를 확정한다. 이 표가 STEP 1-1 조립의 유일한 기준이다.
89
+
90
+ #### STEP 1-1. ref-cache 조립 (자식 spawn 직전 매회 수행)
91
+
92
+ 자식을 중첩 spawn하기 직전, 대상 자식 전용 `<ref-cache>`를 조립한다.
93
+
94
+ ```
95
+ 1. 대상 자식(specifier/planner/builder/verifier/committer)을 확정한다.
96
+ 2. 읽어둔 레퍼런스 5종의 "섹션 소비 매트릭스"에서 해당 자식 열이 ✅인 행을 모은다.
97
+ 표를 끝까지 훑어 ✅ 행을 하나도 빠뜨리지 않는다.
98
+ 3. ✅ 행이 하나도 없는 파일은 <ref>를 만들지 않는다.
99
+ 4. ✅ 행이 있는 파일마다 <ref>를 **정확히 1개씩만** 만든다.
100
+ - 같은 key로 <ref>를 두 번 넣지 않는다.
101
+ - sections 속성에 그 파일의 ✅ 번호를 빠짐없이 나열한다.
102
+ - 본문은 해당 § 원문을 `## § N.` 헤딩째 발췌한다.
103
+ <ref key="{파일명}" sections="{§ 번호 목록}">{원문}</ref>
104
+ 5. 조립 결과를 dispatch XML 최상단 <ref-cache>에 넣는다.
105
+ 6. spawn 직전 자체 점검 (필수) — 아래 "자식별 조립 결과 요약" 표의 해당 행과 대조한다.
106
+ - key가 중복된 <ref>가 없는가
107
+ - key 구성과 각 sections 값이 표와 정확히 일치하는가
108
+ 불일치하면 고친 뒤 spawn한다.
109
+ ```
110
+
111
+ > ⚠️ 자주 나오는 두 가지 실수 — ① 같은 파일을 `<ref>` 두 개로 중복 첨부(토큰 낭비), ② 매트릭스의 ✅ 를 일부 빠뜨림(자식이 필요한 내용을 못 받음). 6단계 대조로 둘 다 막는다.
112
+
113
+ 자식별 조립 결과 요약(매트릭스에서 유도되는 값 — 표가 갱신되면 표를 따른다):
114
+
115
+ | 자식 | ref-cache 구성 |
116
+ |------|----------------|
117
+ | specifier | `file-content-schema`(준수사항,0,5) · `shared-prompt-sections`(1,3,8,9,12) · `xml-schema`(1,2,6) |
118
+ | planner | `file-content-schema`(준수사항,0,1,2,5) · `shared-prompt-sections`(1,3,7,12) · `xml-schema`(1,2,6) |
119
+ | builder | `file-content-schema`(준수사항,2,3,5) · `shared-prompt-sections`(1,2,3,5,12) · `xml-schema`(1,2,3,6) · `context-policy`(1,2,3,4) |
120
+ | verifier | `file-content-schema`(준수사항,2,5) · `shared-prompt-sections`(1,2,3,5,12) · `xml-schema`(1,2,3,6) · `context-policy`(1,2,3) |
121
+ | committer | `file-content-schema`(준수사항,3,5) · `shared-prompt-sections`(1,3,5,8,12) · `xml-schema`(1,2,3,6) · `context-policy`(1,2,3) · `work-activity-log`(2,3) |
122
+
123
+ > `<ref-cache>` 없이 자식을 spawn하는 것은 **금지**다(→ § 3-5). 자식이 레퍼런스를 다시 읽게 되어 ref-cache가 무력화된다.
55
124
 
56
125
  #### STEP 2. 입력 파싱
57
126
 
@@ -86,7 +155,8 @@ model: opus
86
155
  #### STEP A. Specifier 중첩 spawn (WORK 생성)
87
156
 
88
157
  - 활동 로그 `STAGE_START — stage=specifier` 기록.
89
- - specifier 중첩 spawn. 프롬프트에 `REFERENCES_DIR`, 사용자 요청 원문, (있으면) `<ref-cache>`를 포함.
158
+ - **specifier `<ref-cache>`를 STEP 1-1 절차로 조립한다** `file-content-schema`(준수사항,0,5) · `shared-prompt-sections`(1,3,8,9,12) · `xml-schema`(1,2,6).
159
+ - specifier를 중첩 spawn. 프롬프트에 사용자 요청 원문과 **조립한 `<ref-cache>`(필수)** 를 포함. `REFERENCES_DIR`는 자식에게 전달하지 않는다(→ § 3-5).
90
160
  - 반환값에서 WORK 폴더/Requirement.md 생성 여부를 확인.
91
161
  - **게이트 처리**:
92
162
  - `mode=gated`: `GATE_WAIT — stage=specifier` 기록 → `[GATE-1] <gate type="stage" work="{WORK}" stage="specifier">` + Requirement 요약(`<next-stage>planner</next-stage>`) 반환 후 **yield**.
@@ -94,7 +164,8 @@ model: opus
94
164
 
95
165
  #### STEP B. Planner 중첩 spawn
96
166
 
97
- - planner 중첩 spawn `PLAN.md` + `TASK-NN.md` DAG 생성.
167
+ - **planner `<ref-cache>`를 STEP 1-1 절차로 조립한다** — `file-content-schema`(준수사항,0,1,2,5) · `shared-prompt-sections`(1,3,7,12) · `xml-schema`(1,2,6).
168
+ - planner를 중첩 spawn(**조립한 `<ref-cache>` 필수 포함**) → `PLAN.md` + `TASK-NN.md` DAG 생성.
98
169
  - 활동 로그 `STAGE_START — stage=planner`.
99
170
  - **게이트 처리**:
100
171
  - `mode=gated`: `GATE_WAIT — stage=planner` 기록 → `[GATE-2] <gate type="stage" work="{WORK}" stage="planner">` + PLAN/TASK 요약(`<next-stage>builder</next-stage>`) 반환 후 **yield**.
@@ -106,10 +177,10 @@ model: opus
106
177
 
107
178
  1. `works/{WORK}/work_{WORK}.log` + `PLAN.md`로 DAG 해석 → 각 TASK 상태(DONE/READY/BLOCKED) 판정(→ `shared-prompt-sections.md` § 4).
108
179
  2. READY TASK를 오름차순으로 선택. **복수 READY**면 builder를 동시에(같은 턴에 여러 spawn 호출을 묶어) 병렬 중첩 spawn.
109
- 3. TASK별로 builder → verifier → committer를 순차 중첩 spawn:
110
- - `STAGE_START — stage=builder task=TASK-NN` 기록 → builder spawn → 결과 확인.
111
- - `STAGE_START — stage=verifier task=TASK-NN` 기록 → verifier spawn (builder context-handoff FULL 전달) → FAIL이면 builder 재디스패치.
112
- - `STAGE_START — stage=committer task=TASK-NN` 기록 → committer spawn (verifier FULL + builder SUMMARY 전달) → FAIL이면 builder 재디스패치.
180
+ 3. TASK별로 builder → verifier → committer를 순차 중첩 spawn. **매 spawn마다 STEP 1-1로 해당 자식용 `<ref-cache>`를 조립해 필수 포함한다**:
181
+ - `STAGE_START — stage=builder task=TASK-NN` 기록 → builder spawn (`<ref-cache>`: `file-content-schema`(준수사항,2,3,5) · `shared-prompt-sections`(1,2,3,5,12) · `xml-schema`(1,2,3,6) · `context-policy`(1,2,3,4)) → 결과 확인.
182
+ - `STAGE_START — stage=verifier task=TASK-NN` 기록 → verifier spawn (`<ref-cache>`: `file-content-schema`(준수사항,2,5) · `shared-prompt-sections`(1,2,3,5,12) · `xml-schema`(1,2,3,6) · `context-policy`(1,2,3), + builder context-handoff FULL 전달) → FAIL이면 builder 재디스패치.
183
+ - `STAGE_START — stage=committer task=TASK-NN` 기록 → committer spawn (`<ref-cache>`: `file-content-schema`(준수사항,3,5) · `shared-prompt-sections`(1,3,5,8,12) · `xml-schema`(1,2,3,6) · `context-policy`(1,2,3) · `work-activity-log`(2,3), + verifier FULL + builder SUMMARY 전달) → FAIL이면 builder 재디스패치.
113
184
  - 각 단계는 게이트가 없으므로 성공 시 즉시 `STAGE_DONE — stage={builder|verifier|committer} task=TASK-NN` 기록.
114
185
  4. **재시도**: verifier 또는 committer가 FAIL 반환 → builder에 최대 2회 재디스패치(총 3회 시도) (→ `context-policy.md` Committer 재시도 절 준용).
115
186
  - 3회 모두 실패 → 자식이 직접 파이프라인을 중단하지 않고, orchestrator에 `<needs-decision>`으로 상향(판단 기준 "재시도 3회 실패" 해당, → 3-3 절 참조)한다. `mode=gated`면 게이트로 승격해 사용자에게 TASK 보류/스킵/중단을 묻고, `mode=auto`면 권고안(보통 "해당 TASK FAILED 표시 후 나머지 TASK 계속")을 자동결정해 기록한다.
@@ -159,6 +230,14 @@ model: opus
159
230
  - 파괴적/비가역적 변경 (데이터 삭제, 스키마 breaking change 등)
160
231
  - 재시도 3회 실패 (STEP C 참조)
161
232
 
233
+ **예외 — ref-cache 내용 부족**
234
+
235
+ 자식이 "ref-cache에 필요한 내용이 없다"는 사유로 `<needs-decision>`을 올리면 이는 사용자 결정 사항이 **아니다**. 게이트로 승격하지 말고 orchestrator가 즉시 처리한다:
236
+ 1. 부족하다고 보고된 `key`·내용을 확인한다.
237
+ 2. 해당 § 원문을 이미 읽어둔 레퍼런스에서 발췌해 `<ref-cache>`에 보충한다.
238
+ 3. 보충된 `<ref-cache>`로 해당 자식을 재spawn한다(로그·게이트 발생 없음).
239
+ 4. 섹션 소비 매트릭스의 배분이 실제 필요와 어긋났다는 신호이므로, 최종 보고서 `## 자동 결정 사항`에 그 사실을 1줄로 남긴다.
240
+
162
241
  **에스컬레이션 처리**
163
242
  - `mode=gated`: 위 기준에 해당 → `DECISION_WAIT — stage={agent}[ task=TASK-NN]` 기록, `DECISIONS.md`에 `상태: PENDING` 항목 추가 → `<gate type="decision" work stage>`(`<context>`/`<options>`/`<recommended>` 포함, → `xml-schema.md` § 5) 반환 후 **yield**. 재개 시 Main Claude가 전달한 `<decision by="user">`(§ 7)를 받아 `DECISIONS.md`를 `RESOLVED`로 갱신하고 `DECISION — ... by=user` 기록 후 해당 자식을 재개/재spawn.
164
243
  - 위 기준에 해당하지 않는 경미한 사항(자동 결정 가능)은 게이트 없이 orchestrator가 즉시 `<decision by="auto">`로 확정하고 자식 작업을 재개시킬 수 있다(→ `xml-schema.md` § 6) — 모든 needs-decision이 반드시 사용자에게 올라가는 것은 아니다.
@@ -187,6 +266,9 @@ TASK 간 의존성 전달(builder→verifier→committer, 그리고 다음 TASK
187
266
  | WORK 범위 고정 | 지정된 WORK 내 TASK만 처리, 다른 WORK와 혼합 금지 |
188
267
  | 게이트 우회 금지 | `mode=gated`에서 고정 게이트·동적 decision 게이트를 임의로 스킵하거나 자동결정으로 대체하지 않음 |
189
268
  | STAGE_DONE 선기록 금지 | 게이트가 있는 단계는 게이트 해소(RESOLVED) 이전에 `STAGE_DONE`을 기록하지 않음 |
269
+ | 인라인 역할 대행 금지 | `Agent` 도구가 없어 중첩 spawn이 불가능하면(→ STEP 0) 자식 역할을 스스로 수행하지 않고 `<capability-degraded>`를 반환하고 종료한다. 혼자 수행하면 오류 없이 역할 분리가 무너진 채 완료된 것처럼 보인다 |
270
+ | ref-cache 미첨부 spawn 금지 | 자식 중첩 spawn 시 `<ref-cache>`를 반드시 포함(→ STEP 1-1). 누락하면 자식이 레퍼런스를 디스크에서 다시 읽어 캐시가 무력화된다 |
271
+ | 자식 레퍼런스 읽기 금지 | 레퍼런스 파일을 읽는 주체는 orchestrator뿐. 자식 프롬프트에 `REFERENCES_DIR`나 레퍼런스 파일 경로를 **넣지 않는다** — 경로가 보이면 자식이 읽으려 든다 |
190
272
  | 파킹 핸들 1개 원칙 | orchestrator 자신만 파킹 대상 — 자식은 실행→반환하면 종료, 능동 관리 대상 아님 |
191
273
  | 재개 시 재실행 최소화 | `GATE_WAIT`/`DECISION_WAIT`로 종료된 경우 자식을 재실행하지 않고 디스크 산출물을 재사용 |
192
274
 
package/agents/planner.md CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: planner
3
3
  description: Agent that analyzes projects to create WORK (unit of work) and decompose sub-TASKs. Reads CLAUDE.md, README, and source code to create WORK and derive sub-TASKs.
4
- tools: Read, Glob, Grep, Bash, mcp__serena__*, mcp__sequential-thinking__sequentialthinking
4
+ tools: Read, Write, Edit, Glob, Grep, Bash, mcp__serena__*, mcp__sequential-thinking__sequentialthinking
5
5
  model: opus
6
6
  ---
7
7
 
@@ -33,14 +33,9 @@ WORK (작업 단위) — 사용자 요청의 목표 단위
33
33
 
34
34
  ### 3-1. 사전작업
35
35
 
36
- #### STEP 1. STARTUP — 레퍼런스 파일 즉시 읽기 (필수)
36
+ #### STEP 1. STARTUP — 레퍼런스 참조
37
37
 
38
- **REFERENCES_DIR 확인**: 입력에서 `REFERENCES_DIR=...` 라인을 확인. 해당 절대 경로 사용. 없으면 `.claude/references`를 기본값으로 사용.
39
-
40
- `{REFERENCES_DIR}/`에서 다음 파일을 읽기:
41
- 1. `file-content-schema.md`
42
- 2. `shared-prompt-sections.md`
43
- 3. `xml-schema.md`
38
+ `<ref-cache>`를 참조하여 작업을 수행한다.
44
39
 
45
40
  ### STEP 2. WORK 확인
46
41
 
@@ -102,7 +97,7 @@ specifier가 판정한 복잡도를 참고해 TASK 분해 단위를 정한다.
102
97
 
103
98
  ## 6. 승인요청
104
99
 
105
- - 승인 요청은 planner가 직접 수행하지 않는다 — orchestrator가 `<gate type="stage" work stage="planner">`(→ `xml-schema.md` § 5)를 반환해 상위 경계에서 승인을 요청한다(gated 모드).
100
+ - 승인 요청은 planner가 직접 수행하지 않는다 — gated 모드에서는 orchestrator가 `<gate>`를 발행해 상위 경계에서 승인을 처리한다. planner는 `<gate>`를 생성하지 않는다.
106
101
 
107
102
  ## 7. 결과 보고
108
103
  정의된 역할을 모두 끝내면 orchestrator에 보고해. 미해결 모호점이 있으면 `<needs-decision>`을 함께 반환해.
@@ -33,14 +33,9 @@ model: opus
33
33
 
34
34
  ## 3-1. 사전작업
35
35
 
36
- ### STEP 1. STARTUP — 레퍼런스 파일 즉시 읽기 (필수)
36
+ ### STEP 1. STARTUP — 레퍼런스 참조
37
37
 
38
- **REFERENCES_DIR 확인**: 입력에서 `REFERENCES_DIR=...` 라인을 확인. 해당 절대 경로 사용. 없으면 `.claude/references`를 기본값으로 사용.
39
-
40
- `{REFERENCES_DIR}/`에서 다음 파일을 읽기:
41
- 1. `file-content-schema.md`
42
- 2. `shared-prompt-sections.md`
43
- 3. `xml-schema.md`
38
+ `<ref-cache>`를 참조하여 작업을 수행한다.
44
39
 
45
40
  ### STEP 2. WORK ID 결정
46
41
  ```
@@ -339,7 +334,7 @@ model: opus
339
334
 
340
335
  ## 6. 승인요청
341
336
 
342
- - 승인 요청은 specifier가 직접 수행하지 않는다 — orchestrator가 `<gate type="stage" work stage="specifier">`(→ `xml-schema.md` § 5)를 반환해 상위 경계에서 승인을 요청한다(gated 모드).
337
+ - 승인 요청은 specifier가 직접 수행하지 않는다 — gated 모드에서는 orchestrator가 `<gate>`를 발행해 상위 경계에서 승인을 처리한다. specifier는 `<gate>`를 생성하지 않는다.
343
338
  - specifier는 명세서 요약 + 복잡도 판정 결과를 반환하는 것으로 역할을 마친다.
344
339
 
345
340
  ## 7. Planner Agent역할 수행 (필요 시)
@@ -31,14 +31,9 @@ Builder가 완료한 TASK의 결과를 검증하여 빌드, 린트, 테스트, A
31
31
 
32
32
  ### 3-1. 사전작업
33
33
 
34
- #### STEP 1. STARTUP — 레퍼런스 파일 즉시 읽기 (필수)
34
+ #### STEP 1. STARTUP — 레퍼런스 참조
35
35
 
36
- **REFERENCES_DIR 확인**: 입력에서 `REFERENCES_DIR=...` 라인 또는 `<references-dir>` XML 요소를 확인. 해당 절대 경로 사용. 없으면 `.claude/references`를 기본값으로 사용.
37
-
38
- `{REFERENCES_DIR}/`에서 다음 파일을 읽기:
39
- 1. `shared-prompt-sections.md`
40
- 2. `xml-schema.md`
41
- 3. `context-policy.md`
36
+ `<ref-cache>`를 참조하여 작업을 수행한다.
42
37
 
43
38
  ### 3-2. 검증
44
39
 
package/lib/constants.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { readFileSync } from 'node:fs';
1
+ import { readFileSync, existsSync, rmSync, mkdirSync, copyFileSync, readdirSync, statSync } from 'node:fs';
2
2
  import { join, dirname } from 'node:path';
3
3
  import { fileURLToPath } from 'node:url';
4
4
 
@@ -20,7 +20,6 @@ export const REFERENCE_FILES = [
20
20
  'agent-flow.md',
21
21
  'context-policy.md',
22
22
  'file-content-schema.md',
23
- 'ref-cache-protocol.md',
24
23
  'shared-prompt-sections.md',
25
24
  'work-activity-log.md',
26
25
  'xml-schema.md',
@@ -34,6 +33,78 @@ export function getReferencesSrcDir() {
34
33
  return join(__dirname, '..', 'references');
35
34
  }
36
35
 
36
+ /**
37
+ * Files and directories shipped by earlier versions that no longer exist.
38
+ * init and update copy files but never delete, so an upgraded install keeps
39
+ * stale copies unless they are pruned explicitly.
40
+ *
41
+ * Paths are relative to the install root (.claude/ or ~/.claude/).
42
+ */
43
+ export const OBSOLETE_PATHS = [
44
+ 'agents/scheduler.md', // removed in 2.0.0 — orchestrator took over scheduling
45
+ 'references/callback-protocol.md', // removed in 2.0.0 — external callback integration dropped
46
+ 'references/ref-cache-protocol.md',// removed in 2.0.1 — protocol folded into xml-schema.md § 4
47
+ 'skills/sdd-pipeline/references', // removed in 1.5.0 — references moved to references/
48
+ ];
49
+
50
+ /**
51
+ * Delete every OBSOLETE_PATHS entry that still exists under baseDir.
52
+ * Returns the paths actually removed.
53
+ */
54
+ export function pruneObsolete(baseDir) {
55
+ const removed = [];
56
+ for (const relPath of OBSOLETE_PATHS) {
57
+ const target = join(baseDir, relPath);
58
+ if (!existsSync(target)) continue;
59
+ rmSync(target, { recursive: true, force: true });
60
+ removed.push(relPath);
61
+ }
62
+ return removed;
63
+ }
64
+
65
+ /**
66
+ * Recursively copy a directory tree. Shared by init and update.
67
+ * Returns the number of files copied.
68
+ */
69
+ export function copyDirRecursive(src, dest) {
70
+ mkdirSync(dest, { recursive: true });
71
+ let count = 0;
72
+ for (const entry of readdirSync(src)) {
73
+ const srcPath = join(src, entry);
74
+ const destPath = join(dest, entry);
75
+ if (statSync(srcPath).isDirectory()) {
76
+ count += copyDirRecursive(srcPath, destPath);
77
+ } else {
78
+ copyFileSync(srcPath, destPath);
79
+ count++;
80
+ }
81
+ }
82
+ return count;
83
+ }
84
+
85
+ /**
86
+ * Copy plugin resources (.claude-plugin/, skills/) from the package root
87
+ * into the install destination. Shared by init and update.
88
+ */
89
+ export function copyPluginResources(destBaseDir) {
90
+ const pkgRoot = join(__dirname, '..');
91
+ let count = 0;
92
+
93
+ // .claude-plugin/
94
+ const pluginSrc = join(pkgRoot, '.claude-plugin');
95
+ if (existsSync(pluginSrc)) {
96
+ count += copyDirRecursive(pluginSrc, join(destBaseDir, '.claude-plugin'));
97
+ }
98
+
99
+ // skills/
100
+ const skillsSrc = join(pkgRoot, 'skills');
101
+ if (existsSync(skillsSrc)) {
102
+ count += copyDirRecursive(skillsSrc, join(destBaseDir, 'skills'));
103
+ }
104
+
105
+ return count;
106
+ }
107
+
37
108
 
38
109
  /**
39
110
  * Bash permissions required by uc-taskmanager agents.
package/lib/init.mjs CHANGED
@@ -1,10 +1,7 @@
1
- import { existsSync, mkdirSync, copyFileSync, readFileSync, writeFileSync, readdirSync, statSync } from 'node:fs';
1
+ import { existsSync, mkdirSync, copyFileSync, readFileSync, writeFileSync } from 'node:fs';
2
2
  import { join, dirname } from 'node:path';
3
- import { fileURLToPath } from 'node:url';
4
3
  import { homedir } from 'node:os';
5
- import { AGENT_FILES, REFERENCE_FILES, getAgentsSrcDir, getReferencesSrcDir, REQUIRED_PERMISSIONS } from './constants.mjs';
6
-
7
- const __dirname = dirname(fileURLToPath(import.meta.url));
4
+ import { AGENT_FILES, REFERENCE_FILES, getAgentsSrcDir, getReferencesSrcDir, REQUIRED_PERMISSIONS, pruneObsolete, copyPluginResources } from './constants.mjs';
8
5
 
9
6
  import { createInterface } from 'node:readline';
10
7
 
@@ -38,39 +35,13 @@ function copyReferences(destDir) {
38
35
  return count;
39
36
  }
40
37
 
41
- function copyDirRecursive(src, dest) {
42
- mkdirSync(dest, { recursive: true });
43
- let count = 0;
44
- for (const entry of readdirSync(src)) {
45
- const srcPath = join(src, entry);
46
- const destPath = join(dest, entry);
47
- if (statSync(srcPath).isDirectory()) {
48
- count += copyDirRecursive(srcPath, destPath);
49
- } else {
50
- copyFileSync(srcPath, destPath);
51
- count++;
52
- }
38
+ function reportPruned(baseDir) {
39
+ const removed = pruneObsolete(baseDir);
40
+ if (removed.length === 0) return;
41
+ console.log(` ${green('✓')} ${removed.length} obsolete files removed`);
42
+ for (const relPath of removed) {
43
+ console.log(` ${dim('-')} ${dim(relPath)}`);
53
44
  }
54
- return count;
55
- }
56
-
57
- function copyPluginResources(destBaseDir) {
58
- const pkgRoot = join(__dirname, '..');
59
- let count = 0;
60
-
61
- // .claude-plugin/
62
- const pluginSrc = join(pkgRoot, '.claude-plugin');
63
- if (existsSync(pluginSrc)) {
64
- count += copyDirRecursive(pluginSrc, join(destBaseDir, '.claude-plugin'));
65
- }
66
-
67
- // skills/
68
- const skillsSrc = join(pkgRoot, 'skills');
69
- if (existsSync(skillsSrc)) {
70
- count += copyDirRecursive(skillsSrc, join(destBaseDir, 'skills'));
71
- }
72
-
73
- return count;
74
45
  }
75
46
 
76
47
  function ensureWorksDir(projectDir) {
@@ -141,6 +112,7 @@ export async function init(isGlobal) {
141
112
  if (globalResCount > 0) {
142
113
  console.log(` ${green('✓')} ${globalResCount} plugin resource files copied`);
143
114
  }
115
+ reportPruned(globalClaudeDir);
144
116
  console.log(`\n ${dim('Next steps:')}`);
145
117
  console.log(` 1. Open any project and run ${dim("'claude'")}`);
146
118
  console.log(` 2. Type: ${dim(exampleTag)}\n`);
@@ -162,6 +134,8 @@ export async function init(isGlobal) {
162
134
  console.log(` ${green('✓')} ${resCount} plugin resource files copied (.claude-plugin, skills)`);
163
135
  }
164
136
 
137
+ reportPruned(claudeDir);
138
+
165
139
  if (ensureWorksDir(projectDir)) {
166
140
  console.log(` ${green('✓')} works/ directory created`);
167
141
  } else {
package/lib/update.mjs CHANGED
@@ -2,7 +2,7 @@ import { existsSync, copyFileSync, mkdirSync } from 'node:fs';
2
2
  import { join, dirname } from 'node:path';
3
3
  import { fileURLToPath } from 'node:url';
4
4
  import { homedir } from 'node:os';
5
- import { AGENT_FILES, REFERENCE_FILES, getAgentsSrcDir, getReferencesSrcDir } from './constants.mjs';
5
+ import { AGENT_FILES, REFERENCE_FILES, getAgentsSrcDir, getReferencesSrcDir, pruneObsolete, copyPluginResources } from './constants.mjs';
6
6
 
7
7
  const __dirname = dirname(fileURLToPath(import.meta.url));
8
8
 
@@ -40,9 +40,21 @@ export function update(isGlobal) {
40
40
  refCount++;
41
41
  }
42
42
 
43
+ const resCount = copyPluginResources(baseDir);
44
+ const removed = pruneObsolete(baseDir);
45
+
43
46
  const label = isGlobal ? '~/.claude/' : '.claude/';
44
47
  console.log(`\n Updating ${dim(label)} ...`);
45
48
  console.log(` ${green('✓')} ${agentCount} agent files updated`);
46
49
  console.log(` ${green('✓')} ${refCount} reference files updated`);
50
+ if (resCount > 0) {
51
+ console.log(` ${green('✓')} ${resCount} plugin resource files updated`);
52
+ }
53
+ if (removed.length > 0) {
54
+ console.log(` ${green('✓')} ${removed.length} obsolete files removed`);
55
+ for (const relPath of removed) {
56
+ console.log(` ${dim('-')} ${dim(relPath)}`);
57
+ }
58
+ }
47
59
  console.log(` ${dim('-')} CLAUDE.md untouched\n`);
48
60
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uctm",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "Universal Claude Task Manager — SDD-based task pipeline subagent system for Claude Code CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -3,12 +3,14 @@
3
3
  > Main Claude는 **트리거와 게이트 경계**만 담당합니다.
4
4
  > 파이프라인 내부 진행(WORK 생성 → 설계 → TASK 실행 → 완료)은 **orchestrator**가 전담합니다.
5
5
  > Main Claude는 orchestrator 외의 다른 에이전트를 **직접 spawn하지 않습니다**.
6
+ >
7
+ > **예외 — 축퇴 모드(§7)**: 실행 환경이 중첩 spawn을 지원하지 않으면 Main Claude가 orchestrator 역할을 넘겨받아 자식을 직접 spawn합니다.
6
8
 
7
9
  ---
8
10
 
9
11
  ## 1. Main Claude 역할 (트리거 + 게이트 경계)
10
12
 
11
- Main Claude가 직접 수행하는 일은 다음 4가지뿐입니다.
13
+ Main Claude가 직접 수행하는 일은 다음 5가지뿐입니다.
12
14
 
13
15
  1. **트리거 감지** — `[tag]` 메시지 또는 WORK 재개 요청(예: "WORK-01 계속실행", "resume WORK-01")을 감지.
14
16
  2. **orchestrator 1회 spawn** — 다음을 전달:
@@ -16,14 +18,15 @@ Main Claude가 직접 수행하는 일은 다음 4가지뿐입니다.
16
18
  - `mode=gated|auto` — 사용자 메시지에 "auto"/"자동으로"가 포함되면 `auto`, 그 외는 기본값 `gated`
17
19
  - 사용자 요청 원문 (재개 요청이면 대상 `WORK_ID`)
18
20
  - spawn 결과로 받는 **agentId를 보관**한다(재개 시 name이 아니라 **agentId**로 지정 — 이름 재사용 오배달 방지).
19
- 3. **게이트 처리** — orchestrator가 `<gate type="stage">` 또는 `<gate type="decision">`을 반환하고 **yield(파킹)** 하면:
21
+ 3. **축퇴 신호 처리** — orchestrator가 `<capability-degraded>`를 반환하면 §7 축퇴 모드로 전환한다.
22
+ 4. **게이트 처리** — orchestrator가 `<gate type="stage">` 또는 `<gate type="decision">`을 반환하고 **yield(파킹)** 하면:
20
23
  1. 게이트 내용을 사용자에게 그대로 제시한다 — `type="stage"`는 완료 요약, `type="decision"`은 배경(`<context>`) + 선택지(`<options>`) + 권고안(`<recommended>`)(`AskUserQuestion` 등으로 선택 요청).
21
24
  2. 사용자의 승인 또는 선택을 기다린다.
22
25
  3. 응답을 받으면 **`SendMessage(agentId, 결정내용)`으로 컨텍스트를 유지한 채 재개**한다.
23
26
  4. `SendMessage`가 실패하면(파킹 핸들 유실 등) **폴백**: `works/{WORK_ID}/work_{WORK_ID}.log` + `DECISIONS.md`를 근거로 orchestrator를 `WORK_ID`와 함께 새로 spawn해 재개시킨다.
24
- 4. **완료 처리** — orchestrator가 최종 WORK 요약을 반환하면 사용자에게 그대로 릴레이하고 **`TaskStop(agentId)`로 파킹 핸들을 해제**한다.
27
+ 5. **완료 처리** — orchestrator가 최종 WORK 요약을 반환하면 사용자에게 그대로 릴레이하고 **`TaskStop(agentId)`로 파킹 핸들을 해제**한다.
25
28
 
26
- `mode=auto`인 경우 orchestrator가 게이트/의사결정 정지 없이 1회 spawn으로 완주하므로, 3단계(게이트 처리)는 발생하지 않는다 — Main Claude는 spawn 후 최종 결과만 수신·릴레이하고 `TaskStop`으로 마무리한다.
29
+ `mode=auto`인 경우 orchestrator가 게이트/의사결정 정지 없이 1회 spawn으로 완주하므로, 4단계(게이트 처리)는 발생하지 않는다 — Main Claude는 spawn 후 최종 결과만 수신·릴레이하고 `TaskStop`으로 마무리한다.
27
30
 
28
31
  ---
29
32
 
@@ -155,7 +158,7 @@ Main Claude는 재개 요청을 감지하면 대상 `WORK_ID`를 orchestrator에
155
158
  ## References Directory 전달 (필수)
156
159
 
157
160
  Main Claude는 orchestrator spawn 시(신규/재개 모두) references 디렉토리 경로를 전달해야 합니다.
158
- 설치 방법(npm 또는 plugin)에 관계없이 orchestrator 그 자식이 레퍼런스 파일을 찾을 수 있도록 합니다.
161
+ 설치 방법(npm 또는 plugin)에 관계없이 orchestrator 레퍼런스 파일을 찾을 수 있도록 합니다. 이 경로를 받는 것은 orchestrator뿐이며, 자식에게는 전달되지 않습니다.
159
162
 
160
163
  **전달 방법:**
161
164
  - orchestrator spawn 프롬프트 상단에 `REFERENCES_DIR={absolute_path}` 추가
@@ -170,10 +173,48 @@ mode=gated
170
173
  [WORK] 사용자 요청 원문...
171
174
  ```
172
175
 
173
- REFERENCES_DIR를 사용할 수 없는 경우(예: plugin 없는 npm 설치), orchestrator는 `.claude/references/`를 폴백으로 사용합니다. orchestrator는 자신이 읽은 레퍼런스 내용을 `<ref-cache>`(`xml-schema.md` § 4)로 자식에게 재전달할 수 있습니다.
176
+ REFERENCES_DIR를 사용할 수 없는 경우(예: plugin 없는 npm 설치), orchestrator는 `.claude/references/`를 폴백으로 사용합니다. orchestrator는 자신이 읽은 레퍼런스 각 자식에게 필요한 섹션만 잘라 `<ref-cache>`(`xml-schema.md` § 4)로 **반드시** 재전달합니다.
174
177
 
175
178
  ---
176
179
 
177
180
  ## 레퍼런스 로딩
178
181
 
179
- Main Claude는 레퍼런스 파일을 읽지 않으며 — `agent-flow.md`만 읽습니다. orchestrator와 그 자식들이 `{REFERENCES_DIR}/`에서 각자(또는 ref-cache로 전달받아) 필요한 레퍼런스 파일을 읽습니다.
182
+ **정상 경로**: Main Claude는 레퍼런스 파일을 읽지 않으며 — `agent-flow.md`만 읽습니다. `{REFERENCES_DIR}/`의 레퍼런스 파일을 읽는 주체는 **orchestrator 하나뿐**입니다(기동 시 1회, 5개 파일).
183
+
184
+ **축퇴 모드(§7)**: orchestrator 역할이 Main Claude로 넘어오므로 Main Claude가 그 5개 파일을 읽습니다. 읽는 주체만 바뀌고 횟수·범위는 동일합니다.
185
+
186
+ 어느 경우든 자식 에이전트(specifier/planner/builder/verifier/committer)는 디스크를 읽지 않고, 각 파일 상단의 **섹션 소비 매트릭스**를 기준으로 잘라 전달된 `<ref-cache>`만 사용합니다 → `xml-schema.md` § 4.
187
+
188
+ ---
189
+
190
+ ## 7. 축퇴 모드 — Main Claude가 orchestrator 역할 수행
191
+
192
+ ### 진입 조건
193
+
194
+ orchestrator가 `<capability-degraded reason="no-agent-tool">`(→ `xml-schema.md` § 8)을 반환한 경우. 일부 CLI 버전·환경에서 서브에이전트에 `Agent` 도구가 주입되지 않아 중첩 spawn이 불가능할 때 발생합니다. orchestrator는 이때 아무 산출물도 만들지 않고 즉시 반환하므로, 디스크에는 아무것도 남아 있지 않은 상태입니다.
195
+
196
+ ### 처리 절차
197
+
198
+ 1. **사용자에게 1줄 알린다** — 예: "중첩 spawn을 지원하지 않는 환경입니다. Main Claude가 직접 오케스트레이션합니다." 승인을 기다리지 않고 그대로 진행합니다(`mode=auto`의 무정지 완주 원칙 유지).
199
+ 2. **`{REFERENCES_DIR}/orchestrator.md`와 레퍼런스 5종을 읽는다** — `file-content-schema.md`, `shared-prompt-sections.md`, `xml-schema.md`, `work-activity-log.md`, `context-policy.md`.
200
+ 3. **`orchestrator.md`의 절차를 그대로 수행한다.** 정본은 `orchestrator.md` 하나이며 축퇴용 별도 절차는 없습니다. STEP A~D, TASK DAG 스케줄링, 재시도, 컨텍스트 핸드오프, ref-cache 조립(STEP 1-1), 활동 로그 규칙이 **전부 동일하게** 적용됩니다.
201
+ 4. **활동 로그**에 `ORCHESTRATOR_START` 직후 `ORCHESTRATOR_DEGRADED — reason=no-agent-tool`을 1회 기록합니다.
202
+
203
+ ### 정상 경로와 다른 점 — 3가지뿐
204
+
205
+ | 항목 | 정상 | 축퇴 |
206
+ |------|------|------|
207
+ | 자식 spawn depth | 2 (orchestrator가 spawn) | **1** (Main Claude가 직접 spawn) |
208
+ | 게이트 처리 | orchestrator가 `<gate>` 반환 후 yield → Main Claude가 사용자에게 질의 | **Main Claude가 사용자에게 직접 질의** — `<gate>` XML·`SendMessage`·`TaskStop` 불필요 |
209
+ | 레퍼런스를 읽는 주체 | orchestrator | **Main Claude** |
210
+
211
+ 그 외 산출물 형식, 로그 이벤트 체계, ref-cache 조립 규칙, 재개 판정은 모두 같습니다.
212
+
213
+ ### 금지 사항
214
+
215
+ - **자식 역할을 인라인으로 대행하지 않는다.** 축퇴 모드에서도 specifier/planner/builder/verifier/committer는 반드시 별도 spawn한다. Main Claude가 직접 코드를 작성하거나 커밋하면 파이프라인의 역할 분리가 사라진다.
216
+ - `<ref-cache>` 없이 자식을 spawn하지 않는다 — 정상 경로와 동일하게 필수다.
217
+
218
+ ### 재개
219
+
220
+ 축퇴 모드로 진행 중이던 WORK를 재개할 때도 동일하다. Main Claude는 `works/{WORK_ID}/work_{WORK_ID}.log`의 마지막 이벤트로 재개 지점을 판정한다(§2 "재개 규칙"). 로그에 `ORCHESTRATOR_DEGRADED`가 있으면 그 WORK는 축퇴 모드로 시작됐다는 뜻이지만, 재개 시점의 환경이 바뀌었을 수 있으므로 **매번 orchestrator를 먼저 spawn해 다시 판정**한다.
@@ -2,7 +2,24 @@
2
2
 
3
3
  에이전트 간 슬라이딩 윈도우 컨텍스트 전달 규칙.
4
4
 
5
- ## 슬라이딩 윈도우
5
+ ---
6
+
7
+ ## 섹션 소비 매트릭스
8
+
9
+ orchestrator가 자식 spawn 시 `<ref-cache>`에 담을 섹션을 결정하는 기준표 → `xml-schema.md` § 4.
10
+
11
+ | § | 내용 | orch | spec | plan | build | verif | commit |
12
+ |---|------|:----:|:----:|:----:|:-----:|:-----:|:------:|
13
+ | 1 | 슬라이딩 윈도우 | ✅ | | | ✅ | ✅ | ✅ |
14
+ | 2 | Context-Handoff 4개 필드 | ✅ | | | ✅ | ✅ | ✅ |
15
+ | 3 | 파이프라인 단계별 입출력 | | | | ✅ | ✅ | ✅ |
16
+ | 4 | TASK 간 의존성 전달 | ✅ | | | ✅ | | |
17
+ | 5 | Orchestrator 디스패치 | ✅ | | | | | |
18
+ | 6 | Committer 재시도 | ✅ | | | | | |
19
+
20
+ ---
21
+
22
+ ## § 1. 슬라이딩 윈도우
6
23
 
7
24
  | 단계 거리 | 상세 레벨 | 규칙 |
8
25
  |-----------|----------|------|
@@ -10,7 +27,7 @@
10
27
  | 2단계 전 | `SUMMARY` | `what` 필드만, 1-3줄 |
11
28
  | 3단계+ | `DROP` | 생략 |
12
29
 
13
- ## Context-Handoff 4개 필드
30
+ ## § 2. Context-Handoff 4개 필드
14
31
 
15
32
  | 필드 | FULL | SUMMARY | 내용 |
16
33
  |------|:----:|:-------:|------|
@@ -19,7 +36,7 @@
19
36
  | `caution` | ✅ | ❌ | 주의사항, 조건부 완료 (1-3줄) |
20
37
  | `incomplete` | ✅ | ❌ | 미완료 항목 (1-2줄, 없으면 "None") |
21
38
 
22
- ## 파이프라인 단계별 입출력
39
+ ## § 3. 파이프라인 단계별 입출력
23
40
 
24
41
  ### Builder
25
42
 
@@ -55,15 +72,15 @@
55
72
  1. builder 성공 여부 확인 (context-handoff 상태 확인)
56
73
  2. result.md 작성 + git commit
57
74
 
58
- 출력: `{REFERENCES_DIR}/file-content-schema.md` § 3 참조
75
+ 출력: `works/{WORK_ID}/TASK-XX_result.md` + task-result XML
59
76
 
60
- ## TASK 간 의존성 전달
77
+ ## § 4. TASK 간 의존성 전달
61
78
 
62
79
  - 직전 의존 TASK: context-handoff **FULL** (4개 필드 모두)
63
80
  - 2단계 전: **SUMMARY** (what만)
64
81
  - 3단계+: **DROP**
65
82
 
66
- ## Orchestrator 디스패치
83
+ ## § 5. Orchestrator 디스패치
67
84
 
68
85
  TASK DAG 실행 중 다음 자식(중첩 spawn)의 프롬프트를 구성하는 주체는 **orchestrator**다 — dispatch XML을 만들어 자식 spawn 프롬프트에 포함한다.
69
86
 
@@ -88,7 +105,7 @@ TASK DAG 실행 중 다음 자식(중첩 spawn)의 프롬프트를 구성하는
88
105
  </dispatch>
89
106
  ```
90
107
 
91
- ## Committer 재시도
108
+ ## § 6. Committer 재시도
92
109
 
93
110
  1. 실패 원인: 검증 FAIL / 변경 파일 없음
94
111
  2. builder에 재디스패치
@@ -2,6 +2,26 @@
2
2
 
3
3
  파이프라인 산출물 파일 형식의 단일 정의 소스.
4
4
 
5
+ ---
6
+
7
+ ## 섹션 소비 매트릭스
8
+
9
+ orchestrator가 자식 spawn 시 `<ref-cache>`에 담을 섹션을 결정하는 기준표 → `xml-schema.md` § 4.
10
+
11
+ | § | 내용 | orch | spec | plan | build | verif | commit |
12
+ |---|------|:----:|:----:|:----:|:-----:|:-----:|:------:|
13
+ | — | 준수사항 (아래 표) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
14
+ | 0 | Requirement.md | | ✅ | ✅ | | | |
15
+ | 1 | PLAN.md | ✅ | | ✅ | | | |
16
+ | 2 | TASK-XX.md | | | ✅ | ✅ | ✅ | |
17
+ | 3 | TASK-XX_result.md | | | | ✅ | | ✅ |
18
+ | 4 | DECISIONS.md | ✅ | | | | | |
19
+ | 5 | 파일 이름 규칙 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
20
+
21
+ > "준수사항" 표는 § 번호가 없다. 모든 에이전트가 공통으로 필요로 하므로 이 파일을 전달할 때는 **항상 함께 싣고**, `sections` 속성에는 표기하지 않는다.
22
+
23
+ ---
24
+
5
25
  ## 준수사항
6
26
 
7
27
  | 생성 파일 | 참조 섹션 | 위반 시 결과 |
@@ -1,6 +1,27 @@
1
1
  # 공유 프롬프트 섹션
2
2
 
3
- 각 에이전트가 `cache_control` 마커를 통해 참조하는 공통 재사용 섹션.
3
+ 각 에이전트가 참조하는 공통 재사용 섹션.
4
+
5
+ ---
6
+
7
+ ## 섹션 소비 매트릭스
8
+
9
+ orchestrator가 자식 spawn 시 `<ref-cache>`에 담을 섹션을 결정하는 기준표 → `xml-schema.md` § 4.
10
+
11
+ | § | 내용 | orch | spec | plan | build | verif | commit |
12
+ |---|------|:----:|:----:|:----:|:-----:|:-----:|:------:|
13
+ | 1 | 출력 언어 규칙 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
14
+ | 2 | 빌드 및 린트 명령 | | | | ✅ | ✅ | |
15
+ | 3 | WORK 및 TASK 파일 경로 패턴 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
16
+ | 4 | 파일 시스템 Discovery 스크립트 | ✅ | | | | | |
17
+ | 5 | Task Result XML 형식 | | | | ✅ | ✅ | ✅ |
18
+ | 6 | 자동결정 기록 관례 | ✅ | | | | | |
19
+ | 7 | PLAN.md 필수 메타 정보 | | | ✅ | | | |
20
+ | 8 | WORK-LIST.md 업데이트 규칙 | | ✅ | | | | ✅ |
21
+ | 9 | 로케일 감지 | ✅ | ✅ | | | | |
22
+ | 12 | Bash 명령 규칙 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
23
+
24
+ > § 10·§ 11은 존재하지 않는다(과거 삭제분). 기존 상호참조 호환을 위해 번호를 재사용하지 않는다.
4
25
 
5
26
  ---
6
27
 
@@ -126,7 +147,7 @@ works/{WORK_ID}/
126
147
 
127
148
  ## § 7. PLAN.md 필수 메타 정보 — 7개 필드
128
149
 
129
- → `{REFERENCES_DIR}/file-content-schema.md` § 1 참조
150
+ → `file-content-schema.md` § 1 참조
130
151
 
131
152
  | 필드 | 필수 | 설명 |
132
153
  |------|------|------|
@@ -2,25 +2,42 @@
2
2
 
3
3
  `works/{WORK_ID}/work_{WORK_ID}.log`에 실행 이벤트를 기록.
4
4
 
5
- ## 규칙
5
+ ---
6
6
 
7
- 1. **기록 주체**: **orchestrator**. 자식의 spawn/완료를 `STAGE_START`/`STAGE_DONE`으로 기록한다.
7
+ ## 섹션 소비 매트릭스
8
+
9
+ orchestrator가 자식 spawn 시 `<ref-cache>`에 담을 섹션을 결정하는 기준표 → `xml-schema.md` § 4.
10
+
11
+ | § | 내용 | orch | spec | plan | build | verif | commit |
12
+ |---|------|:----:|:----:|:----:|:-----:|:-----:|:------:|
13
+ | 1 | 규칙 | ✅ | | | | | |
14
+ | 2 | 형식 | ✅ | | | | | ✅ |
15
+ | 3 | 이벤트 체계 | ✅ | | | | | ✅ |
16
+
17
+ > committer는 마지막 TASK 판정을 위해 로그를 **읽기만** 한다 — 기록 주체는 orchestrator뿐(§ 1).
18
+
19
+ ---
20
+
21
+ ## § 1. 규칙
22
+
23
+ 1. **기록 주체**: **orchestrator 역할을 수행하는 주체**. 정상 경로에서는 orchestrator 에이전트이고, 축퇴 모드(→ `xml-schema.md` § 8)에서는 그 역할을 넘겨받은 Main Claude다. 어느 쪽이든 자식의 spawn/완료를 `STAGE_START`/`STAGE_DONE`으로 기록한다.
8
24
  2. **타임스탬프**: Bash로 `date -u +"%Y-%m-%dT%H:%M:%SZ"` 실행하여 실제 UTC 시간 획득. 더미 값 사용 금지.
9
25
  3. **기록 방법**: Bash `echo` 로 추가.
10
26
  4. **`STAGE_DONE`은 게이트 통과 후에 기록한다.** 해당 단계에 게이트(`<gate type="stage">` 또는 `<gate type="decision">`)가 있는 경우, Main Claude/사용자의 승인·결정으로 게이트가 해소(RESOLVED)된 시점에만 `STAGE_DONE`을 남긴다. 게이트 대기 중에는 `GATE_WAIT`/`DECISION_WAIT`만 기록되고, `STAGE_DONE`은 아직 기록되지 않은 상태로 남는다.
11
27
  - **근거(재개 판정)**: 파이프라인이 중단 후 재개(resume)될 때 orchestrator는 로그의 마지막 이벤트로 재개 지점을 판정한다. 특정 단계에 `STAGE_START`만 있고 `STAGE_DONE`이 없다면 "그 단계의 게이트가 아직 승인/결정되지 않았다"는 뜻이므로, orchestrator는 다음 단계로 건너뛰지 않고 동일 게이트를 다시 제시해야 한다. `STAGE_DONE`을 게이트 통과 이전에 기록하면 재개 시 미승인 게이트를 건너뛰는 사고로 이어진다.
12
28
 
13
- ## 형식
29
+ ## § 2. 형식
14
30
 
15
31
  ```
16
32
  [YYYY-MM-DDTHH:MM:SSZ] EVENT — description
17
33
  ```
18
34
 
19
- ## 이벤트 체계 (orchestrator 기록)
35
+ ## § 3. 이벤트 체계 (orchestrator 기록)
20
36
 
21
37
  | 이벤트 | 기록 시점 | 예시 |
22
38
  |--------|----------|------|
23
39
  | `ORCHESTRATOR_START` | orchestrator 실행 시작 | `ORCHESTRATOR_START — WORK-NN orchestrator started` |
40
+ | `ORCHESTRATOR_DEGRADED` | 축퇴 모드 진입 — Main Claude가 orchestrator 역할을 넘겨받음. `ORCHESTRATOR_START` 직후 1회 기록 | `ORCHESTRATOR_DEGRADED — reason=no-agent-tool` |
24
41
  | `STAGE_START` | 자식 에이전트(specifier/planner/builder/verifier/committer) spawn 직전 | `STAGE_START — stage=specifier` |
25
42
  | `GATE_WAIT` | `<gate type="stage">`에서 정지, Main Claude 승인 대기 | `GATE_WAIT — stage=specifier` |
26
43
  | `DECISION_WAIT` | `<gate type="decision">` 또는 자식의 `<needs-decision>` 수신 후 결정 대기 | `DECISION_WAIT — stage=planner` |
@@ -30,4 +47,4 @@
30
47
 
31
48
  - `stage` 값: `specifier`/`planner`/`builder`/`verifier`/`committer`.
32
49
  - `by` 값: `user`/`auto`. `<decision>`(§ 7, `xml-schema.md`)의 `by` 속성과 동일한 값 체계를 사용.
33
- - 확정된 결정의 상세 내용(배경/선택지/권고안/확정값)은 로그가 아니라 `works/{WORK_ID}/DECISIONS.md`에 기록한다 `file-content-schema.md` § 4 참조. 로그의 `DECISION` 이벤트는 "언제·누가 결정했는지"만 남긴다.
50
+ - 확정된 결정의 상세 내용(배경/선택지/권고안/확정값)은 로그가 아니라 `works/{WORK_ID}/DECISIONS.md`에 orchestrator가 기록한다. 로그의 `DECISION` 이벤트는 "언제·누가 결정했는지"만 남긴다.
@@ -4,20 +4,36 @@ uc-taskmanager 에이전트용 XML 통신 형식 정의.
4
4
 
5
5
  ---
6
6
 
7
+ ## 섹션 소비 매트릭스
8
+
9
+ orchestrator가 자식 spawn 시 `<ref-cache>`에 담을 섹션을 결정하는 기준표 → § 4.
10
+
11
+ | § | 내용 | orch | spec | plan | build | verif | commit |
12
+ |---|------|:----:|:----:|:----:|:-----:|:-----:|:------:|
13
+ | 1 | Dispatch 형식 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
14
+ | 2 | Task Result 형식 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
15
+ | 3 | Context-Handoff 요소 | ✅ | | | ✅ | ✅ | ✅ |
16
+ | 4 | ref-cache 프로토콜 | ✅ | | | | | |
17
+ | 5 | Gate 요소 | ✅ | | | | | |
18
+ | 6 | needs-decision 요소 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
19
+ | 7 | decision 요소 | ✅ | | | | | |
20
+ | 8 | capability-degraded 요소 | ✅ | | | | | |
21
+
22
+ > § 4·§ 5·§ 7·§ 8은 **orchestrator 전용**이다. ref-cache 생성(§ 4), 게이트 발행(§ 5), 결정 확정(§ 7)은 모두 orchestrator의 책임이며 자식 에이전트는 수행하지 않는다. 자식에게 필요한 ref-cache 소비 규칙은 각 에이전트 정의의 STARTUP 절에 인라인으로 기술되어 있다.
23
+
24
+ ---
25
+
7
26
  > **디스패처 라벨**: dispatch를 발신하고 task-result를 수신하는 디스패처 역할은 **orchestrator**가 수행한다. 아래 §1/§2의 "디스패처"는 모두 orchestrator를 가리킨다.
8
27
 
9
- ## 1. Dispatch 형식 (orchestrator → 수신자)
28
+ ## § 1. Dispatch 형식 (orchestrator → 수신자)
10
29
 
11
30
  ```xml
12
31
  <dispatch to="{receiver}" work="{WORK_ID}" task="{TASK_ID}">
13
- <ref-cache> <!-- 선택사항 -->
14
- <ref key="shared-prompt-sections">{파일 내용}</ref>
15
- <ref key="file-content-schema">{파일 내용}</ref>
16
- <ref key="xml-schema">{파일 내용}</ref>
17
- <ref key="context-policy">{파일 내용}</ref>
18
- <ref key="work-activity-log">{파일 내용}</ref>
32
+ <ref-cache> <!-- 필수 — § 4 참조 -->
33
+ <ref key="shared-prompt-sections" sections="1,3,12">{해당 섹션 원문}</ref>
34
+ <ref key="xml-schema" sections="1,2,6">{해당 섹션 원문}</ref>
35
+ <!-- 수신자에게 필요한 섹션만 (§ 4 조립 절차 참조) -->
19
36
  </ref-cache>
20
- <references-dir>{references 디렉토리 절대 경로}</references-dir>
21
37
  <context>
22
38
  <project>{프로젝트 이름}</project>
23
39
  <language>{lang_code}</language>
@@ -32,7 +48,6 @@ uc-taskmanager 에이전트용 XML 통신 형식 정의.
32
48
  <previous-results>
33
49
  <result task="{TASK_ID}" status="{PASS|FAIL|SKIP}">{요약}</result>
34
50
  </previous-results>
35
- <cache-hint sections="{section1},{section2}"/>
36
51
  </dispatch>
37
52
  ```
38
53
 
@@ -41,9 +56,11 @@ uc-taskmanager 에이전트용 XML 통신 형식 정의.
41
56
  | `to` | builder, verifier, committer, planner, specifier |
42
57
  | `task` | `TASK-NN` — WORK 접두사 포함 금지 |
43
58
 
59
+ > `<ref-cache>`는 **필수**다. orchestrator는 이것 없이 자식을 spawn하지 않는다 — 자식이 레퍼런스를 디스크에서 다시 읽게 되어 ref-cache가 무력화된다.
60
+
44
61
  ---
45
62
 
46
- ## 2. Task Result 형식 (수신자 → orchestrator)
63
+ ## § 2. Task Result 형식 (수신자 → orchestrator)
47
64
 
48
65
  ```xml
49
66
  <task-result work="{WORK_ID}" task="{TASK_ID}" agent="{agent}" status="{PASS|FAIL}">
@@ -55,19 +72,14 @@ uc-taskmanager 에이전트용 XML 통신 형식 정의.
55
72
  <check name="{type}" status="{PASS|FAIL|N/A}">{출력}</check>
56
73
  </verification>
57
74
  <notes>{메모}</notes>
58
- <ref-cache> <!-- 선택사항 -->
59
- <ref key="shared-prompt-sections">{파일 내용}</ref>
60
- <ref key="file-content-schema">{파일 내용}</ref>
61
- <ref key="xml-schema">{파일 내용}</ref>
62
- <ref key="context-policy">{파일 내용}</ref>
63
- <ref key="work-activity-log">{파일 내용}</ref>
64
- </ref-cache>
65
75
  </task-result>
66
76
  ```
67
77
 
78
+ > task-result에는 `<ref-cache>`를 **포함하지 않는다**. 캐시의 단일 소스는 orchestrator이며(§ 4), 자식이 전달받은 내용을 되돌려주는 것은 순수한 토큰 낭비다.
79
+
68
80
  ---
69
81
 
70
- ## 3. Context-Handoff 요소
82
+ ## § 3. Context-Handoff 요소
71
83
 
72
84
  ```xml
73
85
  <context-handoff from="{agent}" detail-level="{FULL|SUMMARY|DROP}">
@@ -86,43 +98,76 @@ uc-taskmanager 에이전트용 XML 통신 형식 정의.
86
98
 
87
99
  ---
88
100
 
89
- ## 4. ref-cache 요소 정의
101
+ ## § 4. ref-cache 프로토콜 (orchestrator 전용)
102
+
103
+ ### 원칙
90
104
 
91
- `<ref-cache>`는 dispatch task-result XML 내에서 미리 로딩된 레퍼런스 파일 내용을 전달하는 선택적 컨테이너 요소입니다. 존재할 경우, 수신 에이전트는 디스크에서 파일을 읽는 대신 반드시 내용을 사용해야 합니다.
105
+ 레퍼런스 파일을 읽는 주체는 **orchestrator 하나뿐**이다. orchestrator는 기동 1회 읽고, 자식을 중첩 spawn할 때마다 **그 자식에게 필요한 섹션만** 잘라 `<ref-cache>`로 전달한다. 자식은 디스크를 읽지 않는다.
106
+
107
+ | 주체 | 행위 |
108
+ |------|------|
109
+ | orchestrator | 레퍼런스 5종 읽기(1회) → 각 파일의 **섹션 소비 매트릭스** 파싱 → 자식별 `<ref-cache>` 조립 → dispatch에 필수 포함 |
110
+ | 자식 에이전트 | `<ref-cache>` 내용만 사용. `{REFERENCES_DIR}` 하위 파일에 대한 `Read`/`Glob`/`Grep` **금지** |
92
111
 
93
112
  ### 구조
94
113
 
95
114
  ```xml
96
115
  <ref-cache>
97
- <ref key="{확장자 없는 파일명}">{전체 파일 내용}</ref>
116
+ <ref key="{확장자 없는 파일명}" sections="{쉼표 구분 § 번호}">{해당 섹션 원문}</ref>
98
117
  ...
99
118
  </ref-cache>
100
119
  ```
101
120
 
102
- | 요소 | 필수 | 설명 |
103
- |------|------|------|
104
- | `<ref-cache>` | 선택 | 캐시된 레퍼런스 파일 컨테이너. 캐시가 없으면 전체 생략. |
105
- | `<ref key="...">` | — | 개별 레퍼런스 파일. `key`는 확장자 없는 파일명 (예: `shared-prompt-sections`). |
121
+ | 요소/속성 | 필수 | 설명 |
122
+ |-----------|:----:|------|
123
+ | `<ref-cache>` | | dispatch에 항상 포함. 생략 금지. |
124
+ | `<ref key="...">` | — | 레퍼런스 파일 1개당 1개. `key`는 확장자 없는 파일명. |
125
+ | `sections="..."` | ✅ | 이 `<ref>`에 담긴 § 번호 목록 (예: `"1,3,12"`). 자식의 자기검증용. |
126
+
127
+ - `<ref>` 본문에는 **`## § N.` 헤딩을 그대로 보존**한 원문을 넣는다 — 문서 내 "→ `xml-schema.md` § 6 참조" 같은 상호참조가 그대로 해소되어야 한다.
128
+ - § 번호가 없는 도입부 표(예: `file-content-schema.md`의 "준수사항")는 해당 파일 전달 시 항상 함께 싣고 `sections`에는 표기하지 않는다.
106
129
 
107
130
  ### 인식되는 키
108
131
 
109
- | 키 | 대응 파일 |
110
- |-----|-----------|
111
- | `shared-prompt-sections` | `{REFERENCES_DIR}/shared-prompt-sections.md` |
112
- | `file-content-schema` | `{REFERENCES_DIR}/file-content-schema.md` |
113
- | `xml-schema` | `{REFERENCES_DIR}/xml-schema.md` |
114
- | `context-policy` | `{REFERENCES_DIR}/context-policy.md` |
115
- | `work-activity-log` | `{REFERENCES_DIR}/work-activity-log.md` |
132
+ | 키 | 대응 파일 | 섹션 범위 |
133
+ |-----|-----------|----------|
134
+ | `shared-prompt-sections` | `{REFERENCES_DIR}/shared-prompt-sections.md` | § 1~9, § 12 |
135
+ | `file-content-schema` | `{REFERENCES_DIR}/file-content-schema.md` | 준수사항, § 0~5 |
136
+ | `xml-schema` | `{REFERENCES_DIR}/xml-schema.md` | § 1~7 |
137
+ | `context-policy` | `{REFERENCES_DIR}/context-policy.md` | § 1~6 |
138
+ | `work-activity-log` | `{REFERENCES_DIR}/work-activity-log.md` | § 1~3 |
139
+
140
+ ### 조립 절차 (orchestrator)
141
+
142
+ ```
143
+ 1. 대상 자식(specifier/planner/builder/verifier/committer)을 확정한다.
144
+ 2. 읽어둔 레퍼런스 5종 각각의 "섹션 소비 매트릭스" 표에서 해당 자식 열이 ✅인 행을 모은다.
145
+ 표를 끝까지 훑어 ✅ 행을 하나도 빠뜨리지 않는다.
146
+ 3. ✅ 행이 하나도 없는 파일은 <ref> 자체를 생성하지 않는다.
147
+ 4. ✅ 행이 있는 파일마다 <ref>를 정확히 1개씩만 만든다.
148
+ 같은 key로 두 번 넣지 않으며, sections에 ✅ 번호를 빠짐없이 나열한다.
149
+ 본문은 해당 § 원문을 헤딩째 발췌한다.
150
+ 5. 조립된 <ref-cache>를 dispatch XML 최상단에 넣어 자식 spawn 프롬프트에 포함한다.
151
+ 6. spawn 직전 자체 점검: key 중복이 없고, key 구성·sections 값이 매트릭스와 일치하는지 대조한다.
152
+ ```
153
+
154
+ ### 조립 불변식
155
+
156
+ | 규칙 | 위반 시 |
157
+ |------|---------|
158
+ | 파일 1개당 `<ref>` 1개 | 같은 내용이 두 번 실려 토큰 낭비 |
159
+ | `sections`에 매트릭스 ✅ 를 빠짐없이 | 자식이 필요한 내용을 받지 못함 |
160
+ | `sections` 값 = 실제 담긴 § 목록 | 자식의 자기검증이 무의미해짐 |
116
161
 
117
- ### 하위 호환성
162
+ ### 내용 부족 시 처리 (엄격 모드)
118
163
 
119
- - `<ref-cache>` 없는 dispatch 또는 task-result XML은 완전히 유효 에이전트는 `REFERENCES_DIR`에서 파일을 읽는 것으로 폴백.
120
- - ref-cache 아직 지원하지 않는 에이전트는 해당 요소를 무시하고 정상적으로 파일을 읽음.
121
- - 부분적 ref-cache (일부 키만 존재)도 허용 없는 키는 디스크에서 읽음.
164
+ - 자식은 어떤 경우에도 레퍼런스 파일을 디스크에서 읽지 않는다. **폴백 경로는 없다.**
165
+ - 작업에 필요한 내용이 `<ref-cache>`에 없으면 `<needs-decision>`(§ 6)으로 부족한 `key`·내용을 명시해 orchestrator에 상향하고 종료한다.
166
+ - orchestrator는 누락분을 보충한 `<ref-cache>`로 해당 자식을 재spawn한다. 이는 매트릭스 배분이 실제 필요와 어긋났다는 신호이므로, 반복되면 해당 파일의 섹션 소비 매트릭스를 수정한다.
122
167
 
123
168
  ---
124
169
 
125
- ## 5. Gate 요소 (orchestrator → Main Claude)
170
+ ## § 5. Gate 요소 (orchestrator → Main Claude)
126
171
 
127
172
  `<gate>`는 orchestrator가 자율 실행을 일시 정지하고 Main Claude(및 사용자)의 승인 또는 결정을 요청할 때 반환하는 정지 신호입니다. orchestrator는 `<gate>`를 반환한 뒤 Main Claude의 응답(승인 또는 `<decision>`)이 돌아올 때까지 재개하지 않습니다.
128
173
 
@@ -160,7 +205,7 @@ uc-taskmanager 에이전트용 XML 통신 형식 정의.
160
205
 
161
206
  ---
162
207
 
163
- ## 6. needs-decision 요소 (자식 에이전트 → orchestrator)
208
+ ## § 6. needs-decision 요소 (자식 에이전트 → orchestrator)
164
209
 
165
210
  `<needs-decision>`은 자식 에이전트(builder/verifier 등)가 구현 중 스스로 결정할 수 없는 사항을 발견했을 때, task-result와 함께(또는 대신) orchestrator에 상향 보고하는 신호입니다. Main Claude로 직접 올라가지 않고 먼저 orchestrator가 받는다는 점에서 `<gate type="decision">`과 구분됩니다.
166
211
 
@@ -184,11 +229,11 @@ uc-taskmanager 에이전트용 XML 통신 형식 정의.
184
229
  - orchestrator는 `<needs-decision>` 수신 시 자동 결정 가능 여부를 판단한다.
185
230
  - 자동 결정 가능 → `<decision by="auto">`(§ 7)로 확정하고 자식 작업을 재개시킴.
186
231
  - 자동 결정 불가 → `<gate type="decision">`(§ 5)으로 승격하여 Main Claude에 전달.
187
- - 어느 경로든 결정 내용은 `works/{WORK_ID}/DECISIONS.md`에 기록된다 `file-content-schema.md` § 4 참조.
232
+ - 어느 경로든 결정 내용은 **orchestrator가** `works/{WORK_ID}/DECISIONS.md`에 기록한다. 자식 에이전트는 DECISIONS.md 직접 쓰지 않으므로 그 포맷을 알 필요가 없다.
188
233
 
189
234
  ---
190
235
 
191
- ## 7. decision 요소 (확정 결정 기록)
236
+ ## § 7. decision 요소 (확정 결정 기록)
192
237
 
193
238
  `<decision>`은 게이트(§ 5) 또는 needs-decision(§ 6)에 대해 내려진 확정 결정을 기록하는 요소입니다. 사용자 승인분(`by="user"`)과 orchestrator 자동결정분(`by="auto"`)이 동일한 형식을 공유합니다.
194
239
 
@@ -215,3 +260,33 @@ uc-taskmanager 에이전트용 XML 통신 형식 정의.
215
260
  | `by` | `user`(사용자 승인) / `auto`(orchestrator 자동결정) |
216
261
 
217
262
  - orchestrator는 `<decision>` 확정 즉시 `works/{WORK_ID}/DECISIONS.md`의 해당 항목을 `PENDING → RESOLVED`로 갱신하고, 활동 로그에 `DECISION` 이벤트를 기록한다 → `work-activity-log.md` 참조.
263
+
264
+ ---
265
+
266
+ ## § 8. capability-degraded 요소 (orchestrator → Main Claude)
267
+
268
+ `<capability-degraded>`는 orchestrator가 **자신의 실행 환경이 파이프라인을 수행할 수 없음**을 감지했을 때, 아무 작업도 하지 않고 즉시 반환하는 신호입니다.
269
+
270
+ ```xml
271
+ <capability-degraded reason="no-agent-tool">
272
+ <detail>서브에이전트에 Agent 도구가 주입되지 않아 중첩 spawn 불가</detail>
273
+ </capability-degraded>
274
+ ```
275
+
276
+ | 속성/요소 | 값 |
277
+ |-----------|-----|
278
+ | `reason` | `no-agent-tool` — 중첩 spawn용 `Agent` 도구 부재 |
279
+ | `<detail>` | 사람이 읽을 수 있는 사유 1줄 |
280
+
281
+ ### 발생 조건
282
+
283
+ 일부 CLI 버전·환경에서 서브에이전트에 `Agent` 도구가 주입되지 않아 자식 중첩 spawn이 불가능한 경우. orchestrator는 기동 직후(STEP 0, 레퍼런스를 읽기 전) 이를 판정한다.
284
+
285
+ ### 불변식
286
+
287
+ - orchestrator는 이 신호를 반환하기 전에 **어떤 산출물도 만들지 않는다** — WORK 폴더, Requirement.md, 활동 로그 모두 생성 금지.
288
+ - orchestrator는 자식 역할을 **인라인으로 대행하지 않는다.** 대행하면 WORK가 완료된 것처럼 보이지만 역할 분리와 검증 독립성이 사라진 채로 끝나며, 오류가 나지 않아 발견되지 않는다.
289
+
290
+ ### Main Claude의 처리
291
+
292
+ Main Claude는 이 신호를 받으면 축퇴 모드로 전환해 **자신이 orchestrator 역할을 수행**한다. 절차의 정본은 `orchestrator.md` 그대로이며, 자식이 depth=1로 뜨는 것만 다르다 → `agent-flow.md` 축퇴 모드 절 참조.
@@ -54,9 +54,24 @@ Main Claude는 `orchestrator` 에이전트 하나만 spawn합니다. specifier/p
54
54
  2. 게이트/의사결정 정지 없이 orchestrator가 전체 파이프라인을 완주하고 최종 요약(`## 자동 결정 사항` 포함)을 반환한다.
55
55
  3. 반환된 최종 요약을 사용자에게 제시한다. (파킹 상태가 아니므로 TaskStop 불필요.)
56
56
 
57
+ ## 축퇴 모드 (중첩 spawn 미지원 환경)
58
+
59
+ orchestrator가 `<capability-degraded reason="no-agent-tool">`을 반환하면, 그 환경은 서브에이전트에 `Agent` 도구를 주지 않아 중첩 spawn이 불가능한 상태입니다(CLI 버전에 따라 발생). orchestrator는 아무 산출물도 만들지 않고 즉시 반환하므로 디스크에는 아무것도 없습니다.
60
+
61
+ 이때 Main Claude가 **orchestrator 역할을 넘겨받습니다**:
62
+
63
+ 1. 사용자에게 1줄 알린다 — "중첩 spawn 미지원 환경 — Main Claude가 직접 오케스트레이션합니다". 승인을 기다리지 않고 진행.
64
+ 2. `{REFERENCES_DIR}/orchestrator.md`와 레퍼런스 5종을 읽는다.
65
+ 3. `orchestrator.md` 절차를 그대로 수행한다 — specifier/planner/builder/verifier/committer를 **직접 spawn**(depth=1)하고, ref-cache 조립·활동 로그·TASK DAG·재시도 규칙을 동일하게 적용한다.
66
+ 4. 활동 로그에 `ORCHESTRATOR_DEGRADED — reason=no-agent-tool`을 기록한다.
67
+ 5. 게이트는 `<gate>` XML/`SendMessage` 없이 사용자에게 **직접** 질의한다.
68
+
69
+ → 상세: `agent-flow.md` § 7
70
+
57
71
  ## ⚠️ CRITICAL: 에이전트 Spawn 규칙
58
72
 
59
- - Main Claude가 spawn하는 에이전트는 **orchestrator 하나뿐**이다. Main Claude가 직접 코드 구현, 파일 생성, git 명령 실행 또는 orchestrator의 작업을 수행하면 안 된다.
73
+ - **정상 경로**에서 Main Claude가 spawn하는 에이전트는 **orchestrator 하나뿐**이다. Main Claude가 직접 코드 구현, 파일 생성, git 명령 실행 또는 orchestrator의 작업을 수행하면 안 된다.
74
+ - **축퇴 모드**에서는 Main Claude가 자식 5종을 직접 spawn한다. 단 이 경우에도 **자식 역할을 스스로 대행하지는 않는다** — 반드시 각 에이전트를 spawn해야 한다.
60
75
  - 게이트 재개는 항상 **agentId** 기준(SendMessage/TaskStop 모두)으로 한다 — name 재사용에 의한 오배달을 방지한다.
61
76
 
62
77
  ## Arguments
@@ -1,31 +0,0 @@
1
- # ref-cache 프로토콜
2
-
3
- ## 개요
4
-
5
- ref-cache는 파이프라인 내 서브에이전트 호출 간 중복 파일 읽기를 방지하는 메커니즘입니다.
6
- 레퍼런스 파일이 매번 디스크에서 다시 읽히는 대신 `<ref-cache>` XML 요소를 통해 에이전트 간에 전달됩니다.
7
-
8
- ## 프로토콜 (4단계)
9
-
10
- 1. 수신한 dispatch XML에 `<ref-cache>`가 있는지 **확인**
11
- 2. 각 필수 레퍼런스 파일에 대해:
12
- - ref-cache에 있으면 → **파일 읽기 건너뛰기**, 캐시된 내용 사용
13
- - ref-cache에 없으면 → `{REFERENCES_DIR}/{filename}.md`에서 읽고 ref-cache에 추가
14
- 3. 작업 완료 시, 반환하는 task-result XML에 병합된 `<ref-cache>` 포함
15
- 4. **하위 호환성**: dispatch에 `<ref-cache>`가 없으면 모든 레퍼런스 파일을 정상적으로 읽기 (기존 동작)
16
-
17
- ## ref-cache XML 형식
18
-
19
- 전체 스키마는 `xml-schema.md` § 4 참조.
20
-
21
- ```xml
22
- <ref-cache>
23
- <ref key="file-content-schema">...내용...</ref>
24
- <ref key="shared-prompt-sections">...내용...</ref>
25
- <!-- 로딩된 레퍼런스 파일당 하나의 <ref> -->
26
- </ref-cache>
27
- ```
28
-
29
- ## 체인 전파
30
-
31
- 파이프라인에서 ref-cache가 에이전트 간에 어떻게 흐르는지는 `agent-flow.md` § ref-cache Chain Propagation 참조.