okstra 0.4.0 → 0.6.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.
@@ -0,0 +1,900 @@
1
+ # okstra — 아키텍처 및 운영 매뉴얼 (한국어)
2
+
3
+ > 이 문서는 [README.kr.md](../../README.kr.md) 의 보충 문서입니다. 빠른 진입은 README, 내부 동작·계약·workflow 는 이 문서를 참고하세요.
4
+ >
5
+ > CLI 인자/옵션과 인터랙티브 입력 흐름은 별도 문서 [cli.md](cli.md) 에 있습니다.
6
+
7
+ ---
8
+
9
+ ## At a glance
10
+
11
+ `okstra`는 Claude Code의 cross-verify 워크플로를 위한 **task bundle 준비 도구**입니다. 단일 파일 리뷰 도구가 아니라, stable task key를 중심으로 task brief · profile · prompt · run history · project-level discovery metadata를 정형화해 Claude가 안정적으로 lead/worker orchestration을 수행할 수 있도록 돕는 보조 러너입니다.
12
+
13
+ 핵심 기능을 한눈에 정리하면 다음과 같습니다.
14
+
15
+ - **Task identity**: `<project-id>/<task-group>/<task-id>` 기반 stable task key로 task root를 생성하거나 재사용하고, manifest · index · timeline을 일관되게 갱신합니다.
16
+ - **Task type별 profile**: `requirements-discovery`, `error-analysis`, `implementation-planning`, `implementation`, `final-verification` 등 표준 task type 프로파일을 로드해 instruction-set을 렌더링합니다.
17
+ - **Run lifecycle**: 매 실행마다 per-run 디렉터리(`runs/<timestamp>/`)에 prompt snapshot, sessions/, expected-state, final report 템플릿, run manifest, timeline 이벤트를 저장합니다.
18
+ - **Single python authority**: 모든 prepare wiring(profile/workers/model 해소, path 계산, 9개 render, central record_start)이 [`okstra_ctl.run.prepare_task_bundle()`](scripts/okstra_ctl/run.py) 한 함수에 모여 있습니다. `okstra.sh` 와 `okstra-run` skill 은 같은 함수를 호출하는 thin caller 이며, 환경 변수로 상태를 전달하지 않습니다 — task 정체성·경로·workflow 상태는 모두 디스크 권위 파일에서 매번 계산됩니다.
19
+ - **Claude handoff (두 모드)**: (a) `okstra.sh` 가 새 `claude` 프로세스를 띄우는 전통 방식, (b) `okstra-run` skill 이 현재 claude 세션 안에서 prepare 후 lead 역할을 그대로 인계받는 in-session 모드. 둘 다 `prepare_task_bundle` 의 산출물(instruction-set 등)을 그대로 사용합니다.
20
+ - **Required team contract**: `Claude lead` + `Claude worker` · `Codex worker` · `Gemini worker` · `Report writer worker`의 필수 구성과 Agent Teams 우선 시도를 강제합니다.
21
+ - **User-home install + project-local task bundles**: `npx okstra@latest install` 한 명령이 런타임(`~/.okstra/{lib/python, bin}`) + 스킬 마크다운(`~/.claude/skills/<name>/SKILL.md`) 을 모두 깐다. 대상 프로젝트에는 task bundle 과 discovery metadata 만 `.project-docs/okstra/` 아래 저장됩니다 — 사용자의 `~/.claude/settings.json` 이나 프로젝트 `.claude/settings.local.json` 은 건드리지 않으며, per-session permission 은 `claude --settings` 로 런타임 주입합니다. (개발용으로는 `okstra-install.sh` 가 `--link` 모드 symlink 설치를 제공합니다.)
22
+ - **Resume and clarification**: `--task-key`, `--resume-clarification`, `--clarification-response`로 같은 task 재개와 lead의 추가 질문 응답 흐름을 지원합니다.
23
+ - **Optional integrations**: worker error sidecar, token usage / cost accounting을 옵션으로 제공합니다.
24
+
25
+ 판단 정책과 worker orchestration은 Claude lead가 담당하고, `okstra`는 Claude가 잘 일할 수 있는 정형화된 입력 묶음과 출력 골격을 준비하는 역할에 집중합니다.
26
+
27
+ ## Table of contents
28
+
29
+ - [Purpose](#purpose)
30
+ - [What okstra does](#what-okstra-does)
31
+ - [Runtime assets vs support assets](#runtime-assets-vs-support-assets)
32
+ - [Architecture: python authority + thin callers](#architecture-python-authority--thin-callers)
33
+ - [Claude execution behavior](#claude-execution-behavior)
34
+ - [Claude prompt contract](#claude-prompt-contract)
35
+ - [Required team contract](#required-team-contract)
36
+ - [Stable task identity](#stable-task-identity)
37
+ - [Project self-registration](#project-self-registration)
38
+ - [Task type](#task-type)
39
+ - [표준 task type](#표준-task-type)
40
+ - [Phase 간 정보 전달](#phase-간-정보-전달)
41
+ - (CLI 인자 / 옵션 / 인터랙티브 입력은 [cli.md](cli.md) 참조)
42
+ - [Storage model](#storage-model)
43
+ - [1. Stable task root](#1-stable-task-root)
44
+ - [2. Per-run execution artifacts](#2-per-run-execution-artifacts)
45
+ - [3. Project-level discovery and skill documents](#3-project-level-discovery-and-skill-documents)
46
+ - [Task manifest contract](#task-manifest-contract)
47
+ - [Task index contract](#task-index-contract)
48
+ - [Run manifest contract](#run-manifest-contract)
49
+ - [Timeline contract](#timeline-contract)
50
+ - [Claude operating contract](#claude-operating-contract)
51
+ - [Task brief usage](#task-brief-usage)
52
+ - [Recommended workflow](#recommended-workflow)
53
+ - [1. 초안 작성](#1-초안-작성)
54
+ - [2. 정식 brief 작성](#2-정식-brief-작성)
55
+ - [2.5. 필요 시 요구사항 triage](#25-필요-시-요구사항-triage)
56
+ - [3. Render-only 검증](#3-render-only-검증)
57
+ - [4. Claude 실행](#4-claude-실행)
58
+ - [5. 필요 시 에러 분석](#5-필요-시-에러-분석)
59
+ - [5.5. 답변 후 즉시 재실행](#55-답변-후-즉시-재실행)
60
+ - [6. 필요 시 구현 계획 검토](#6-필요-시-구현-계획-검토)
61
+ - [7. 승인된 plan 기반 구현](#7-승인된-plan-기반-구현)
62
+ - [8. 구현 후 최종 검토](#8-구현-후-최종-검토)
63
+ - [9. 같은 task 재개](#9-같은-task-재개)
64
+ - [Lifecycle status and resume](#lifecycle-status-and-resume)
65
+ - [Preferred final report structure](#preferred-final-report-structure)
66
+ - [Worker error collection (optional sidecar)](#worker-error-collection-optional-sidecar)
67
+ - [Token usage and cost accounting](#token-usage-and-cost-accounting)
68
+ - [Practical notes](#practical-notes)
69
+ - [Related documents](#related-documents)
70
+
71
+ ## Purpose
72
+
73
+ 이 문서는 `Okstra` 기준의 `okstra` 사용법을 task-key 중심으로 정리한 운영 가이드입니다.
74
+ `README.md`가 빠른 진입점이라면, 이 문서는 `okstra`의 실행 계약과 storage model, lifecycle, Claude handoff 규칙을 설명하는 상세 기준 문서입니다.
75
+
76
+ `okstra`는 단일 파일 리뷰 도구가 아닙니다.
77
+ `okstra`는 Claude Code가 cross verify를 수행할 수 있도록 안정적인 task bundle, run history, project-level discovery metadata를 준비하는 보조 도구입니다.
78
+
79
+ ## What okstra does
80
+
81
+ okstra 의 prepare 책임은 단일 python 진입점 [`okstra_ctl.run.prepare_task_bundle`](scripts/okstra_ctl/run.py) 에 모여 있습니다. 이 함수가 다음을 한 트랜잭션으로 수행합니다.
82
+
83
+ - okstra 설치 자산(`~/.claude/skills/okstra/...`, `~/.claude/agents/...`, `~/.okstra/bin/...`) 존재 확인
84
+ - `<PROJECT_ROOT>/.project-docs/okstra/project.json` self-registration (또는 projectId 일치 검증)
85
+ - task type → `prompts/profiles/<task-type>.md` 로드 + 권장 workers 추출
86
+ - 사용자 worker/model 오버라이드 정규화 (Claude/Codex/Gemini/Report-writer 각각 display ↔ execution-value 매핑)
87
+ - task brief / clarification response 경로 해석 (cwd 우선 → PROJECT_ROOT fallback)
88
+ - per-task mutex(`~/.okstra/.locks/<task-key>.lock`) 안에서 stable task root + 모든 path/seq 계산 후 `<run-dir>/manifests/run-context-<seq>.json` 으로 영속화
89
+ - 사용자 입력을 `<run-dir>/manifests/run-inputs-<seq>.json` 으로 영속화
90
+ - instruction-set 9 파일 렌더 (`analysis-profile.md`, `analysis-material.md`, `task-brief.md`, `reference-expectations.md`, `final-report-template.md`, `clarification-response.md`, `directive.txt`, `claude-execution-prompt.md`, lead prompt snapshot)
91
+ - `task-manifest.json` · `task-index.md` · `run-manifest-*.json` · `history/timeline.json` · `discovery/{latest-task,task-catalog}.json` 갱신
92
+ - preassigned Claude session ID + `sessions/claude-resume-*.sh` 작성 (`--render-only` 가 아닐 때)
93
+ - 중앙 인덱스(`~/.okstra/{active,recent}.jsonl`, `projects/<id>/{index.jsonl, meta.json}`) record_start
94
+
95
+ `prepare_task_bundle` 의 두 caller:
96
+
97
+ 1. **`scripts/okstra.sh`**: CLI 인자를 파싱·확인하고 → `prepare_task_bundle` 호출 → `--render-only` 가 아니면 `claude --model ... --session-id ... "$PROMPT"` 를 `exec` 으로 띄움. ~160 줄의 thin wrapper.
98
+ 2. **`okstra-run` skill**: 같은 claude 세션 안에서 `AskUserQuestion` 으로 인자를 모은 뒤 → `prepare_task_bundle(render_only=True)` 직접 호출 → 렌더된 lead prompt 를 현재 세션이 그대로 읽어 lead 역할 수행. 새 claude 프로세스를 띄우지 않음.
99
+
100
+ 판단 정책과 worker orchestration 은 lead claude 가 담당하고, okstra 의 prepare 단계는 그 lead 가 정확한 입력 묶음과 출력 골격을 받아 일을 시작할 수 있게 정형화된 자산을 준비할 뿐입니다.
101
+
102
+ ## Runtime assets vs support assets
103
+
104
+ 런타임 진입점은 python 패키지에 모여 있고, bash 와 skill 은 거기로 호출만 보냅니다.
105
+
106
+ ### Python module 진입점 (single authority)
107
+
108
+ - [`okstra_ctl.run`](scripts/okstra_ctl/run.py) — `prepare_task_bundle()` orchestrator + argparse CLI (`python3 -m okstra_ctl.run --workspace-root ... --project-root ... ...`).
109
+ - [`okstra_ctl.paths`](scripts/okstra_ctl/paths.py) — `compute_run_paths()` pure path/seq 계산.
110
+ - [`okstra_ctl.run_context`](scripts/okstra_ctl/run_context.py) — `compute_and_write_run_context()`, `write_run_inputs()`, per-task mutex.
111
+ - [`okstra_ctl.render`](scripts/okstra_ctl/render.py) — task-manifest / run-manifest / timeline / task-index / team-state / launch.template / reference-expectations / discovery 9개 render 함수 + `python3 -m okstra_ctl.render <subcommand>` dispatcher.
112
+ - [`okstra_ctl.workers`](scripts/okstra_ctl/workers.py) · [`okstra_ctl.models`](scripts/okstra_ctl/models.py) — worker / model 해소.
113
+ - [`okstra_ctl.workflow`](scripts/okstra_ctl/workflow.py) — phase rules (PHASE_ALLOWED_OUTPUTS / PHASE_FORBIDDEN_ACTIONS).
114
+ - [`okstra_ctl.material`](scripts/okstra_ctl/material.py) — `analysis-material.md` 본문 + related-tasks 빌더.
115
+ - [`okstra_ctl.session`](scripts/okstra_ctl/session.py) · [`okstra_ctl.seeding`](scripts/okstra_ctl/seeding.py) — Claude session id / resume command / 설치 검증 / runtime settings.
116
+ - [`okstra_ctl.{ids,index,invocation,jsonl,project_meta,reconcile,resolver,sequence,batch,backfill,listing,locks,tmux}`](scripts/okstra_ctl/) — 중앙 인덱스 (`~/.okstra`) 의 기존 모듈군.
117
+ - [`okstra_project.{resolver,state}`](scripts/okstra_project/) — PROJECT_ROOT 해석 + project.json upsert + task-catalog/manifest reader.
118
+
119
+ ### Bash entry points (thin)
120
+
121
+ - [`scripts/okstra.sh`](scripts/okstra.sh) ~160 줄. CLI 파싱 / interactive prompt / confirm-execution-plan / `prepare_task_bundle` 호출 / `exec claude`.
122
+ - [`scripts/lib/okstra/{cli,globals,interactive,project-resolver,usage}.sh`](scripts/lib/okstra/) — CLI/인터랙티브 보조만. 산출물 생성 로직 보유 없음.
123
+ - [`scripts/okstra-ctl.sh`](scripts/okstra-ctl.sh) + [`scripts/lib/okstra-ctl/`](scripts/lib/okstra-ctl/) — 중앙 컨트롤 센터 CLI (list / show / open / rerun / reconcile / 등).
124
+
125
+ ### Claude assets (templates + skills)
126
+
127
+ - `prompts/launch.template.md` — lead 프롬프트 템플릿.
128
+ - `prompts/profiles/*.md` — 5종 task-type profile.
129
+ - `templates/project-docs/task-index.template.md` · `templates/reports/final-report.template.md` · `templates/reports/settings.template.json` — 런타임 렌더 입력.
130
+ - `<PROJECT_ROOT>/.project-docs/okstra/project.json` — 프로젝트 self-registration. okstra.sh 첫 실행 시 자동 생성/검증되며, `--project-root` 미지정 시 ancestor / `git toplevel` 로 PROJECT_ROOT 해석.
131
+
132
+ ### Support assets (런타임 비참조)
133
+
134
+ - `templates/reports/*-input.template.md` — 사용자 입력 작성 보조.
135
+ - `validators/validate-workflow.sh`, `validators/validate-schedule.py`, `validators/validate-run.py` — 수동/CI 검증용. `validate-run.py` 의 경로는 run metadata 에 기록.
136
+
137
+ ### Skills (`skills/`, `agents/`)
138
+
139
+ - [`agents/SKILL.md`](agents/SKILL.md) — main okstra skill (cross-verify 트리거).
140
+ - [`skills/okstra-setup/SKILL.md`](skills/okstra-setup/SKILL.md) — **첫 실행 부트스트랩**. `okstra install` + `project.json` 생성.
141
+ - [`skills/okstra-run/SKILL.md`](skills/okstra-run/SKILL.md) — **현재 claude 세션 안에서 okstra task 를 시작**하는 in-session 진입점. `prepare_task_bundle` 직접 호출.
142
+ - `skills/okstra-{status,history,convergence,schedule,context-loader,team-contract,report-finder,report-writer,time-summary}/SKILL.md` — phase 진행·status·history 보조 skill.
143
+ - 플러그인 매니페스트: [`.claude-plugin/plugin.json`](.claude-plugin/plugin.json) — `npx skills@latest add Devonshin/okstra` 보조 채널이 참조. 0.3.0 부터는 `npx okstra install` 한 명령이 동일 결과를 보장하므로 일반 셋업에는 이 채널이 필요 없다.
144
+ - 설치 위치: `~/.claude/skills/<name>/SKILL.md` (`okstra-install.sh` dev 설치, 또는 위 npx 채널).
145
+ - 릴리스 절차: [`RELEASING.md`](RELEASING.md) — npm publish 흐름과 GitHub Actions 워크플로(`v*.*.*` tag → 자동 publish), 자동화 토큰 셋업, 검증/롤백.
146
+
147
+ ## Architecture: python authority + thin callers
148
+
149
+ okstra 의 prepare 단계는 디스크 권위 + 단일 python 진입점 모델을 따릅니다. 이 설계가 두 가지 목표를 동시에 만족합니다.
150
+
151
+ 1. **Claude Code 의 병렬 실행과 호환**: 같은 claude 세션이 subagent / 병렬 Bash tool / 백그라운드 작업으로 여러 자식을 띄워도 환경 변수가 공유 변경되지 않으므로 race 가 발생하지 않습니다.
152
+ 2. **bash CLI 와 in-session skill 의 동작 동일성**: `okstra.sh` 와 `okstra-run` skill 이 같은 `prepare_task_bundle()` 을 부르기 때문에 산출물·중앙 인덱스 등록·검증 경로가 같습니다.
153
+
154
+ ```
155
+ ┌────────────────────────────────────────────────────────────────┐
156
+ │ Two callers, one authority │
157
+ ├────────────────────────────────────────────────────────────────┤
158
+ │ │
159
+ │ scripts/okstra.sh skills/okstra-run/SKILL.md │
160
+ │ (CLI: bash 인자 파싱) (current claude 세션 안 AskUserQuestion) │
161
+ │ │ │ │
162
+ │ └─────────────┬────────────────┘ │
163
+ │ ▼ │
164
+ │ okstra_ctl.run.prepare_task_bundle() │
165
+ │ (single python function — 산출물 전부 책임) │
166
+ │ │ │
167
+ │ ┌────────────┴────────────────┐ │
168
+ │ ▼ ▼ │
169
+ │ on-disk authority ~/.okstra (central index) │
170
+ │ <PROJECT_ROOT>/.project-docs/ per-task mutex + record_start │
171
+ └────────────────────────────────────────────────────────────────┘
172
+ ```
173
+
174
+ ### State authority on disk
175
+
176
+ per-process 환경 변수에 task 정체성·경로·workflow 상태를 보관하지 않습니다. 모든 reader 는 다음 파일에서 매번 계산합니다.
177
+
178
+ | 데이터 | 권위 파일 |
179
+ |---|---|
180
+ | projectId, projectRoot | `<PROJECT_ROOT>/.project-docs/okstra/project.json` |
181
+ | task identity / workflow | `<task-root>/task-manifest.json` |
182
+ | task 후보 목록 | `<PROJECT_ROOT>/.project-docs/okstra/discovery/task-catalog.json` |
183
+ | 최신 task 포인터 | `<PROJECT_ROOT>/.project-docs/okstra/discovery/latest-task.json` |
184
+ | run 입력값 | `<run-dir>/manifests/run-inputs-<task-type>-<seq>.json` |
185
+ | run paths / seq | `<run-dir>/manifests/run-context-<task-type>-<seq>.json` |
186
+ | run 이력 | `<task-root>/history/timeline.json` |
187
+ | 글로벌 인덱스 | `~/.okstra/{active,recent}.jsonl`, `~/.okstra/projects/<id>/{index.jsonl, meta.json}` |
188
+
189
+ ### Concurrency
190
+
191
+ 두 종류의 파일 락이 모든 동시성을 처리합니다.
192
+
193
+ - `~/.okstra/.locks/<task-key>.lock` — per-task mutex. `compute_and_write_run_context` 가 seq 계산과 `run-context.json` 영속화를 한 트랜잭션으로 묶음. 같은 task 의 두 호출은 직렬화.
194
+ - `~/.okstra/.lock` — 중앙 인덱스 mutex. `record_start` / `reconcile` / `rotate_recent_if_needed` 에서 사용.
195
+
196
+ 다른 (project, task-group, task-id) 사이에는 직렬화가 없습니다 — 디스크 경로가 분리되므로 충돌 자체가 없음. 환경 변수 race 가 사라졌으므로 같은 claude 세션이 여러 task 를 병렬 진행해도 안전.
197
+
198
+ ### Allowed env vars (사용자 knob 한정)
199
+
200
+ 상태 전달 용도가 아닌, 사용자 설정용으로만 다음 env var 를 읽습니다.
201
+
202
+ - `OKSTRA_HOME` — 중앙 디렉터리 위치 override (기본 `~/.okstra`).
203
+ - `OKSTRA_DEFAULT_LEAD_MODEL`, `OKSTRA_DEFAULT_CLAUDE_MODEL`, `OKSTRA_DEFAULT_CODEX_MODEL`, `OKSTRA_DEFAULT_GEMINI_MODEL`, `OKSTRA_DEFAULT_REPORT_WRITER_MODEL` — 모델 default.
204
+ - `OKSTRA_TOOL_NAME`, `OKSTRA_COMMAND_NAME` — usage 출력의 표시 이름.
205
+ - `OKSTRA_RUN_SEQ_OVERRIDE` — okstra-ctl rerun / 테스트 hook 이 강제하는 run-seq (per-process).
206
+
207
+ 이 외의 `PROJECT_ID`, `TASK_GROUP`, `RUN_*`, `FINAL_*`, `CLAUDE_*` 등은 export 하지 않으며, 자식 프로세스로 leak 되지 않습니다.
208
+
209
+ ## Claude execution behavior
210
+
211
+ 현재 구현 기준으로 `okstra`의 Claude 실행 방식은 아래와 같습니다.
212
+
213
+ **Mode A — `okstra.sh` 가 새 claude 프로세스를 띄움**
214
+ - `--render-only`를 사용하면 Claude를 실행하지 않고 instruction-set 만 만든 뒤 종료합니다.
215
+ - `--render-only`가 없으면 prepare 단계가 Claude session ID 를 선할당하고 current run 의 `sessions/` 아래에 `claude-resume-<task-type>-<seq>.sh` 를 생성합니다.
216
+ - 이후 대상 프로젝트 루트에서 resolved `Claude lead` model execution value 로 `claude --model <lead> --session-id "$CLAUDE_SESSION_ID" --settings <runtime-settings> "$PROMPT"` 를 `exec` 합니다.
217
+ - `okstra.sh` 는 handoff 까지만 수행하고, 최종 보고서 저장과 run/task 상태 갱신은 Claude lead 가 이어서 수행합니다.
218
+
219
+ **Mode B — `okstra-run` skill 이 현재 claude 세션 안에서 인계**
220
+ - 사용자가 이미 claude 세션에 있고 거기서 새 okstra task 를 시작하고 싶을 때 사용합니다.
221
+ - skill 이 `AskUserQuestion` 으로 task 후보·task-type·brief 등을 받고 `prepare_task_bundle(render_only=True)` 를 호출해 동일한 instruction-set 을 디스크에 만듭니다.
222
+ - 새 claude 프로세스는 띄우지 않고, 현재 세션이 렌더된 lead prompt 를 읽어 lead 역할로 즉시 진입합니다.
223
+
224
+ 두 모드 모두 동일한 산출물(task-manifest, run-manifest, timeline, instruction-set, central index 등록) 을 만들며, `okstra-ctl` 의 후속 명령(list / show / rerun / reconcile)은 산출물 차이를 알지 못한 채 일관되게 동작합니다.
225
+ - handoff된 메인 Claude는 `Claude lead`로 동작하며 orchestration과 final synthesis를 담당합니다.
226
+ - standard workflow의 required worker role은 `Claude worker`, `Codex worker`, `Gemini worker`, `Report writer worker`입니다.
227
+ - worker 역할 분담과 최종 판단은 Claude가 task bundle을 읽고 수행합니다.
228
+ - 사용자 홈에 설치된 okstra Claude assets(`~/.claude/skills`, `~/.claude/agents`) 는 Agent Teams 를 우선 시도하고, 팀 구성이 불가능할 때만 sequential/background fallback 을 사용하도록 Claude 를 유도합니다.
229
+
230
+ ## Claude prompt contract
231
+
232
+ Claude launch prompt 본문은 항상 `prompts/launch.template.md` 템플릿에서만 렌더링됩니다.
233
+
234
+ - 프롬프트 치환은 task key, session ID, 절대/상대 경로 같은 scalar placeholder 값으로만 제한합니다.
235
+ - 선택된 profile 본문은 `instruction-set/analysis-profile.md`로 렌더링합니다.
236
+ - 분석 자료 본문은 `instruction-set/analysis-material.md`로 렌더링합니다.
237
+ - config/deployment expected-state 본문은 `instruction-set/reference-expectations.md`로 렌더링합니다.
238
+ - Claude는 위 artifact 파일들을 직접 읽어야 하며, 긴 task-specific 본문이 launch prompt 안에 inline으로 복제되면 안 됩니다.
239
+
240
+ ## Required team contract
241
+
242
+ 표준 `okstra` workflow는 아래 팀 계약을 runtime prompt, profile, manifest, skill 문서에 공통으로 반영합니다.
243
+
244
+ - 메인 Claude는 항상 `Claude lead`이며 synthesis-only로 동작합니다.
245
+ - required worker role은 `Claude worker`, `Codex worker`, `Gemini worker`, `Report writer worker`입니다.
246
+ - `Report writer worker`는 보고서 구조화와 근거 정리에 집중하지만 최종 synthesis owner는 여전히 `Claude lead`입니다.
247
+ - 기본 모델 계약은 중앙 기본값에서 계산합니다. 기본 fallback은 `Claude lead`=`opus`, `Claude worker`=`sonnet`, `Codex worker`=`gpt-5.5`, `Gemini worker`=`auto`이며, `Report writer worker`는 별도 override가 없으면 `Claude lead` 모델을 따릅니다(즉, 기본값에서는 `opus`).
248
+ - `Gemini worker`는 반드시 시도해야 합니다.
249
+ - 최종 판단 전에는 각 required worker role별로 결과 또는 명시적인 terminal status(`completed`, `timeout`, `error`, `not-run`)가 필요합니다.
250
+ - 시도된 worker(`completed`, `timeout`, `error`)는 현재 run의 `prompts/` 아래 assigned worker prompt history file을 반드시 가져야 합니다.
251
+ - 이름 없는 generic parallel worker는 required role 대체 수단으로 허용하지 않습니다.
252
+
253
+ ## Stable task identity
254
+
255
+ `okstra`의 기본 식별자는 아래 조합입니다.
256
+
257
+ - `project-id`
258
+ - `task-group`
259
+ - `task-id`
260
+
261
+ 논리적 task key는 아래 형식입니다.
262
+
263
+ ```text
264
+ <project-id>:<task-group>:<task-id>
265
+ ```
266
+
267
+ 같은 버그를 다시 열거나 같은 작업을 이어서 진행할 때는 같은 `task-group`과 `task-id`를 재사용합니다.
268
+ 새로운 unrelated 작업이면 새 `task-group` 또는 새 `task-id`를 사용합니다.
269
+
270
+ ## Project self-registration
271
+
272
+ `okstra.sh` 는 외부 등록 디렉토리(과거 `examples/projects/*.conf.sh` 모델은 폐기됨) 없이 동작합니다. 매 실행 시작 시 PROJECT_ROOT 를 다음 우선순위로 해석한 뒤 그 위치의 `.project-docs/okstra/project.json` 을 권위 소스로 자기 등록합니다.
273
+
274
+ 해석 우선순위:
275
+
276
+ 1. CLI 인자 `--project-root <path>`.
277
+ 2. cwd 또는 그 조상 디렉토리 중 `.project-docs/okstra/project.json` 보유 위치.
278
+ 3. cwd 의 `git rev-parse --show-toplevel`.
279
+
280
+ 셋 다 실패하면 `okstra.sh` 는 즉시 에러로 종료합니다 (자동 추정 없음).
281
+
282
+ `<PROJECT_ROOT>/.project-docs/okstra/project.json` 스키마:
283
+
284
+ ```json
285
+ {
286
+ "projectId": "fontradar-v2-api",
287
+ "projectRoot": "/Volumes/Workspaces/workspace/projects/fontradar",
288
+ "createdAt": "2026-05-10T00:00:00Z",
289
+ "updatedAt": "2026-05-10T00:00:00Z"
290
+ }
291
+ ```
292
+
293
+ 처음 실행이면 위 4-필드를 새로 작성합니다. 이미 존재하면 `--project-id` 인자값과 저장된 `projectId` 가 일치하는지 검증한 뒤 `projectRoot`/`updatedAt` 만 갱신합니다. 불일치 시 즉시 종료해 동일 디렉토리에서 두 개의 ID 가 혼용되는 것을 막습니다.
294
+
295
+ `okstra-ctl` 의 reindex/backfill 도 신규 모델에서 권위 소스를 변경했습니다. 과거에는 `examples/projects/*.conf.sh` 를 source 했지만, 지금은 `~/.okstra/projects/<projectId>/meta.json` (record_start 가 위 project.json 정보를 mirror 한 결과) 을 스캔하여 (projectId, projectRoot) 매핑을 복원합니다. `OKSTRA_PROJECT_DEFINITION_DIR_OVERRIDE` 환경변수도 함께 폐기되었습니다.
296
+
297
+ ## Task type
298
+
299
+ `task-type`은 이번 run의 목적과 profile 선택, 그리고 lifecycle phase 라우팅을 동시에 결정합니다.
300
+
301
+ 선택 규칙:
302
+
303
+ - `--task-type <name>`을 주면 `prompts/profiles/<name>.md`가 task bundle의 `instruction-set/analysis-profile.md`로 렌더링됩니다.
304
+ - 외부 인터페이스 기준 단일 선택자는 `task-type`입니다.
305
+ - 선택된 task type은 task-manifest.json의 `taskType`, `workflow.currentPhase`, `workflow.nextRecommendedPhase`에 그대로 반영됩니다.
306
+ - run directory 경로 세그먼트로도 사용됩니다(`runs/<task-type>/...`).
307
+
308
+ ### 표준 task type
309
+
310
+ 각 task type은 phase별 허용/금지 행동을 강제하며, 한 run은 자기 task type의 산출물만 만들고 다음 phase로 이행하지 않습니다. 다음 phase는 항상 새로운 `okstra.sh` 실행에서 시작합니다.
311
+
312
+ | task type | 목적 | 핵심 산출물 | 다음 권장 phase | 코드 변경 허용 여부 |
313
+ |---|---|---|---|---|
314
+ | `requirements-discovery` | 요청을 bugfix/feature/refactor/ops/improvement 중 하나로 분류하고 안전한 다음 phase로 라우팅 | work category, routing decision, missing-input list, clarification requests | `pending-routing-decision` (사용자 답변 후 결정) | 금지 |
315
+ | `error-analysis` | 보고된 에러/사고의 증상·원인·재현 갭을 증거 기반으로 분석 | symptom/trigger 정리, root-cause 가설, reproduction gap, validation 경로 | `implementation-planning` | 금지 |
316
+ | `implementation-planning` | 코딩 시작 전 안전한 구현 방향과 옵션을 평가 | 최소 2개 구현 옵션, 영향 파일 목록, trade-off, 단계별 실행 순서, validation/rollback, **User Approval Request** 블록 | `implementation` (사용자 승인 후) | 금지 |
317
+ | `implementation` | 승인된 `implementation-planning` final report의 단계대로 소스 코드를 수정 | commit list, diff summary, out-of-plan edits 블록, validation/TDD evidence, rollback 검증, verifier 결과(Gemini/Codex/Claude) | `final-verification` | 허용 (승인된 plan의 파일 목록 한정, `git push`/publish/deploy/실제 migration 금지) |
318
+ | `final-verification` | 완료된 작업의 잔존 결함·회귀 위험을 점검하고 release 판단 | acceptance verdict, residual risk, follow-up 라우팅(`error-analysis`/`implementation-planning`) | `done-or-follow-up` | 금지 (read-only 테스트만 허용) |
319
+
320
+ 공통 제약:
321
+
322
+ - `implementation`을 제외한 모든 phase는 source code edit, build, migration, deployment, 그 밖의 state-mutating 명령을 금지합니다(`final-verification`은 read-only 테스트 명령만 허용). `implementation`은 승인된 plan의 파일 목록 안에서만 edit/commit이 허용되며, `git push`·publish·deploy·실제 migration·third-party write API는 여전히 금지됩니다.
323
+ - 사용자가 "다음 단계 진행해" 같은 표현을 보내도, 그 발화만으로 다음 phase가 자동 시작되지 않습니다. 다음 phase는 새 `okstra.sh` 실행으로만 시작합니다.
324
+ - **Authority & permissions assumption (HARD RULE — 모든 task-type 및 `okstra-schedule` 공통)**: 사용자(및 팀)는 예상되는 모든 작업에 대해 완전한 권한·승인 권한을 보유한다고 가정합니다. 외부 승인, 서드파티 액세스, 역할/IAM 권한, 조직적 sign-off, 법무·보안 검토, 벤더 협의, "권한 보유 여부 확인" 같은 항목을 routing 결정·missing inputs·clarification questions·risk·dependency·open questions·effort/day 추정에 포함하지 않습니다. okstra 내부 phase 핸드오프(`User Approval Request` 등)는 사용자 본인이 즉시 승인 가능한 내부 게이트이므로 영향 없으며, `implementation`의 forbidden actions(`git push`, prod deploy, shared-DB migration 등)도 권한 사유가 아닌 **안전 사유**로 계속 적용됩니다.
325
+ - Phase별 상세 규칙은 `prompts/profiles/<task-type>.md`에 정의되어 있고, 그 본문이 그대로 `instruction-set/analysis-profile.md`로 렌더링됩니다.
326
+
327
+ ### Phase 간 정보 전달
328
+
329
+ - `requirements-discovery` 또는 `error-analysis`가 남긴 final report의 `## 5. Clarification Requests for the Next Run` 섹션에 사용자가 답변을 채운 뒤, 다음 run에서 `--clarification-response <previous-final-report.md>`로 그 파일을 carry-in합니다.
330
+ - carry-in된 파일은 현재 run의 `instruction-set/clarification-response.md`로 복사되고, lead가 Section 0에서 prior `Q*` 행의 `Status`(`resolved` / `obsolete`)를 갱신한 뒤 진행합니다.
331
+ - 답변 편집과 재실행을 한 번에 처리하려면 `--resume-clarification` 모드를 사용합니다. 자세한 동작은 `### --resume-clarification` 섹션을 참고합니다.
332
+
333
+
334
+
335
+ ---
336
+
337
+ ## Storage model
338
+
339
+ `okstra`가 만드는 파일은 용도에 따라 아래 3개 영역에 나뉘어 저장됩니다.
340
+
341
+ ### 1. Stable task root
342
+
343
+ task 자체의 기준 폴더입니다.
344
+ task manifest, task index, instruction-set, runs, history가 이 루트 아래에 모입니다.
345
+
346
+ ```text
347
+ <target-project>/.project-docs/okstra/tasks/<task-group>/<task-id>/
348
+ ├── task-manifest.json
349
+ ├── task-index.md
350
+ ├── instruction-set/
351
+ │ ├── analysis-profile.md
352
+ │ ├── analysis-material.md
353
+ │ ├── reference-expectations.md
354
+ │ ├── task-brief.md
355
+ │ ├── directive.txt # optional (mirrors --directive)
356
+ │ ├── final-report-template.md
357
+ │ └── claude-execution-prompt.md
358
+ ├── runs/
359
+ │ └── <task-type>/
360
+ │ ├── manifests/
361
+ │ │ └── run-manifest-<task-type>-<seq>.json
362
+ │ ├── state/
363
+ │ │ └── team-state-<task-type>-<seq>.json
364
+ │ ├── prompts/
365
+ │ │ ├── claude-execution-prompt-<task-type>-<seq>.md
366
+ │ │ ├── claude-worker-prompt-<task-type>-<seq>.md
367
+ │ │ ├── codex-worker-prompt-<task-type>-<seq>.md
368
+ │ │ ├── gemini-worker-prompt-<task-type>-<seq>.md
369
+ │ │ └── report-writer-worker-prompt-<task-type>-<seq>.md
370
+ │ ├── reports/
371
+ │ │ └── final-report-<task-type>-<seq>.md
372
+ │ ├── status/
373
+ │ │ └── final-<task-type>-<seq>.status
374
+ │ ├── sessions/
375
+ │ │ └── claude-resume-<task-type>-<seq>.sh
376
+ │ ├── logs/
377
+ │ │ └── errors-<task-type>-<seq>.jsonl # optional, lead-only writer
378
+ │ └── worker-results/
379
+ └── history/
380
+ └── timeline.json
381
+ ```
382
+
383
+ 실제 디렉터리 세그먼트는 안전한 경로 생성을 위해 slug 형태로 정규화될 수 있습니다.
384
+ 하지만 논리 task key는 항상 원래 입력값 기준 `project-id:task-group:task-id`를 유지합니다.
385
+
386
+ ### 2. Per-run execution artifacts
387
+
388
+ 실행별 산출물은 아래 경로에 누적됩니다.
389
+
390
+ ```text
391
+ <target-project>/.project-docs/okstra/tasks/<task-group>/<task-id>/runs/<task-type>/
392
+ ```
393
+
394
+ 여기에 저장되는 대표 파일:
395
+
396
+ - `manifests/run-manifest-<task-type>-<seq>.json`
397
+ - `state/team-state-<task-type>-<seq>.json`
398
+ - `prompts/claude-execution-prompt-<task-type>-<seq>.md`
399
+ - `prompts/<worker>-worker-prompt-<task-type>-<seq>.md`
400
+
401
+ 그리고 `--render-only`가 아니면 handoff된 Claude session이 보통 아래 결과 파일을 현재 run에 추가합니다.
402
+ - `sessions/claude-resume-<task-type>-<seq>.sh`
403
+ - `reports/final-report-<task-type>-<seq>.md`
404
+ - `status/final-<task-type>-<seq>.status`
405
+ 최종 결과 파일 둘은 `okstra`가 stdout을 저장해서 만드는 파일이 아닙니다.
406
+ `okstra`가 준비한 task bundle을 바탕으로 Claude가 현재 run 안에 직접 작성하는 결과물입니다.
407
+ 반면 `sessions/claude-resume-<task-type>-<seq>.sh`는 `okstra`가 Claude launch 전에 미리 생성하는 interruption recovery helper입니다.
408
+
409
+ run directory는 task-type 단위로 task 실행 이력을 모으고, 내부를 `manifests/`, `state/`, `prompts/`, `reports/`, `status/`, `sessions/`, `worker-results/`처럼 유형별 하위 폴더로 나눈 뒤 각 run-level artifact와 result 파일을 `-<task-type>-<seq>` suffix(per-category 3-digit zero-padded counter, 예: `001`, `002`)로 구분합니다.
410
+ worker prompt history는 `/tmp`가 아니라 항상 현재 run의 `prompts/` 아래 canonical artifact로 남깁니다.
411
+ 이전처럼 `analysis-profile.md`, `analysis-material.md`, `reference-expectations.md`, `task-brief.md`, skill 복사본, `final-report-template.md`를 run마다 중복 저장하지 않습니다.
412
+ 이 자료들은 stable task root의 `instruction-set/`에 canonical copy를 유지합니다.
413
+ 같은 task-type으로 다시 실행하면 동일한 `runs/<task-type>/` 폴더를 재사용하지만, 유형별 하위 폴더 아래에서 run-level 파일명이 `-<task-type>-<seq>` suffix로 분리되므로 기존 산출물을 덮어쓰지 않습니다. `<seq>`는 카테고리 디렉토리(`manifests/`, `prompts/`, `reports/`, `status/`, `state/`, `sessions/`, `worker-results/`)별로 독립 스캔되므로 같은 run에서도 카테고리별 값이 다를 수 있습니다.
414
+ 이전 flat legacy artifact가 task-type run 폴더 최상위에 남아 있으면 다음 실행 시 해당 유형별 하위 폴더로 자동 정리합니다.
415
+
416
+ ### 3. Project-level discovery and skill documents
417
+ 프로젝트 공용 discovery pointer는 아래 경로에 생성합니다.
418
+
419
+ ```text
420
+ <target-project>/.project-docs/okstra/discovery/latest-task.json
421
+ <target-project>/.project-docs/okstra/discovery/task-catalog.json
422
+ ```
423
+ scripts/okstra.sh workflow가 사용하는 project-local Claude assets는 아래 경로들에 seed합니다.
424
+
425
+ ```text
426
+ <target-project>/.claude/skills/okstra/SKILL.md
427
+ <target-project>/.claude/skills/<sub-skill>/SKILL.md
428
+ <target-project>/.claude/agents/<agent>.md
429
+ ```
430
+
431
+ 역할 구분:
432
+
433
+ - `.project-docs/okstra/discovery/latest-task.json`: 현재 프로젝트에서 가장 최근에 준비된 okstra task bundle을 가리키는 current-task convenience pointer
434
+ - `.project-docs/okstra/discovery/task-catalog.json`: 현재 프로젝트에 준비된 okstra task bundle 목록을 `taskKey`, `taskGroup`, `taskId` 기준으로 유지하는 canonical project-level catalog
435
+ - `instruction-set/reference-expectations.md`: 현재 task가 참조해야 할 config files, deployment manifests, expected values를 task-level canonical artifact로 정리한 파일
436
+ - `.claude/skills/...`, `.claude/agents/...`: `agents` 아래 Markdown asset을 project-local Claude asset 구조로 seed한 파일들
437
+
438
+ 기본 rerun에서는 이미 존재하는 project-local asset을 유지합니다.
439
+ `--refresh-assets`를 주면 mapped okstra asset을 source 기준으로 다시 생성합니다.
440
+
441
+ 이전의 아래 파일들은 더 이상 okstra 생성 대상이 아닙니다.
442
+
443
+ - `CLAUDE.md`
444
+ - `.project-docs/ai/claude-project-guide.md`
445
+ - `.project-docs/ai/claude-skill-index.md`
446
+ - `.project-docs/ai/okstra/okstra-guide.md`
447
+ - `.project-docs/ai/okstra/worker-catalog.md`
448
+
449
+ ## Task manifest contract
450
+
451
+ `task-manifest.json`은 Claude가 task continuity를 이해할 때 기준이 되는 canonical metadata 파일입니다.
452
+ 이 manifest는 `projectRoot` 절대경로를 한 번만 기록하고, 나머지 생성 경로들은 가능한 한 project-relative field로 정리하는 것을 기본 원칙으로 합니다.
453
+
454
+ 핵심 필드 예시:
455
+
456
+ - `projectId`
457
+ - `taskGroup`
458
+ - `taskId`
459
+ - `taskKey`
460
+ - `projectRoot`
461
+ - `taskType`
462
+ - `workCategory`
463
+ - `taskBriefPath`
464
+ - `relatedTasks`
465
+ - `currentStatus`
466
+ - `taskRootPath`
467
+ - `instructionSetPath`
468
+ - `referenceExpectationsPath`
469
+ - `runsPath`
470
+ - `historyTimelinePath`
471
+ - `latestRunPath`
472
+ - `latestRunStatus`
473
+ - `latestRunPromptsPath`
474
+ - `latestReportPath`
475
+ - `latestResumeCommandPath`
476
+ - `workflow.currentPhase`
477
+ - `workflow.currentPhaseState`
478
+ - `workflow.phaseStates`
479
+ - `workflow.lastCompletedPhase`
480
+ - `workflow.nextRecommendedPhase`
481
+ - `workflow.awaitingApproval`
482
+ - `workflow.routingStatus`
483
+ - `workflow.lastSafeCheckpoint`
484
+ - `inputs`
485
+ - `artifacts`
486
+ - `resultContract`
487
+ - `claudeSession`
488
+
489
+ 이 manifest는 아래 목적을 가집니다.
490
+
491
+ - Claude가 brief보다 먼저 task continuity를 이해하게 함
492
+ - 어떤 파일을 우선 읽어야 하는지 고정함
493
+ - 어떤 config files와 deployment manifests를 어떤 expected values로 해석해야 하는지 고정함
494
+ - 어떤 task key 아래 결과가 누적되는지 고정함
495
+ - related task와 latest run 위치를 빠르게 확인하게 함
496
+
497
+ ## Task index contract
498
+
499
+ `task-index.md`는 사람이 빠르게 읽기 위한 요약 문서입니다.
500
+
501
+ 주요 내용:
502
+ - task key
503
+ - current task type
504
+ - work category
505
+ - 현재 task 상태
506
+ - 최신 run 상태
507
+ - current phase
508
+ - current phase state
509
+ - next recommended phase
510
+ - reference expectations
511
+ - latest run
512
+ - latest report
513
+ - resume command
514
+
515
+ 이 문서는 quick summary일 뿐이며 source of truth가 아닙니다.
516
+ canonical metadata는 항상 `task-manifest.json`을 기준으로 확인합니다.
517
+
518
+ ## Run manifest contract
519
+
520
+ 각 실행은 `runs/<task-type>/manifests/run-manifest-<task-type>-<seq>.json`에 현재 run 계약을 남깁니다.
521
+
522
+ `manifests/run-manifest-<task-type>-<seq>.json`의 path 계열 필드는 모두 대상 프로젝트 루트 기준 상대경로만 저장합니다.
523
+ `okstra`가 Claude handoff를 시작한 직후에는 현재 run 상태가 보통 `in-progress`로 기록됩니다.
524
+ 이후 최종 결과 저장과 상태 갱신은 Claude가 이어서 수행합니다.
525
+ 또한 `okstra`는 launch 전에 session ID를 선할당하고, 같은 run의 `sessions/` 아래에 `claude-resume-<task-type>-<seq>.sh`를 생성합니다.
526
+
527
+ 주요 내용:
528
+
529
+ - task key
530
+ - task type
531
+ - work category
532
+ - run datetime segment
533
+ - task brief relative path
534
+ - analysis target
535
+ - related tasks
536
+ - selected workers
537
+ - worker model assignments
538
+ - claude session id
539
+ - resume command relative path
540
+ - expected report relative path
541
+ - expected status relative path
542
+ - prompt snapshot relative path
543
+ - `worker prompt directory relative path`
544
+ - `worker prompt relative path by worker id`
545
+ - current run status
546
+ - workflow snapshot
547
+ - team contract
548
+
549
+ ## Timeline contract
550
+
551
+ `history/timeline.json`은 task에 속한 run 이력을 누적합니다.
552
+
553
+ 이력에는 보통 아래가 포함됩니다.
554
+
555
+ - run timestamp
556
+ - run directory relative path
557
+ - run manifest relative path
558
+ - run time segment
559
+ - task type
560
+ - work category
561
+ - status
562
+ - worker prompt directory relative path
563
+ - report relative path
564
+ - resume command relative path
565
+ - related tasks
566
+ - workflow snapshot
567
+ 같은 task-type을 다시 실행하면 같은 `runs/<task-type>/` 폴더를 재사용하더라도 `run-manifest-<task-type>-<seq>.json`과 관련 artifact 경로가 per-category sequence suffix(`<task-type>-<seq>`)로 분리되므로 각 실행이 별도 이력으로 누적됩니다. cross-category 식별자는 manifest의 `runDateTimeSegment` ISO timestamp 필드입니다.
568
+
569
+ ## Claude operating contract
570
+
571
+ `okstra` 실행 후 Claude는 아래 순서로 현재 task를 읽는 것을 기본 규칙으로 삼아야 합니다.
572
+
573
+ 1. task browsing 또는 task-id disambiguation이 필요하면 `.project-docs/okstra/discovery/task-catalog.json`을 먼저 읽습니다.
574
+ 2. 현재 task key나 task path가 명시되지 않았다면 `.project-docs/okstra/discovery/latest-task.json`을 current-task pointer로 읽습니다.
575
+ 3. `task-manifest.json`을 읽습니다.
576
+ 4. `task-index.md`는 quick summary가 필요할 때만 선택적으로 읽습니다.
577
+ 5. `instruction-set/analysis-profile.md`를 읽습니다.
578
+ 6. `instruction-set/analysis-material.md`를 읽습니다.
579
+ 7. `instruction-set/reference-expectations.md`를 읽습니다.
580
+ 8. `instruction-set/task-brief.md`를 읽습니다.
581
+ 9. `instruction-set/final-report-template.md`를 읽습니다.
582
+ 10. current `manifests/run-manifest-<task-type>-<seq>.json`을 읽습니다.
583
+ 11. 필요하면 `history/timeline.json`과 이전 run 결과를 참고합니다.
584
+ 12. `Claude lead`로서 required worker `Claude worker`, `Codex worker`, `Gemini worker`, `Report writer worker`를 기준으로 역할을 구성합니다.
585
+ 13. 각 selected worker prompt를 assigned worker prompt history path로 현재 run의 `prompts/` 아래에 먼저 저장한 뒤 worker를 dispatch합니다.
586
+ 14. 각 required worker에 대해 결과 또는 terminal status를 수집합니다.
587
+ 15. brief이 더 구체적인 형식을 강제하지 않으면 `final-report-template.md` 구조로 Markdown 최종 보고서를 작성합니다.
588
+ 16. 결과를 현재 run의 `reports/final-report-<task-type>-<seq>.md`에 직접 저장하고, 필요하면 `status/final-<task-type>-<seq>.status`, `manifests/run-manifest-<task-type>-<seq>.json`, `task-manifest.json`, `task-index.md`도 현재 상태에 맞게 갱신합니다.
589
+
590
+ 권장 worker 상태값:
591
+
592
+ - `completed`
593
+ - `timeout`
594
+ - `error`
595
+ - `not-run`
596
+
597
+ ## Task brief usage
598
+
599
+ `okstra`는 brief-first 구조입니다. brief 가 분석의 정본 입력이며, 워커가 필요로 할 추가 자료(보고서, 코드 스니펫, 로그 등)는 brief 내부의 `Evidence and Source Materials` 섹션에 inline 또는 path 로 모두 포함시킵니다.
600
+
601
+ brief에는 보통 아래를 포함합니다.
602
+
603
+ - 문제 설명
604
+ - 요구사항
605
+ - 기존 분석
606
+ - raw sample 또는 log
607
+ - 관련 코드 경로
608
+ - 제약사항
609
+ - worker에게 줄 질문
610
+ - 기대 출력
611
+ - 이전 run 또는 연관 task 정보
612
+
613
+ 기본 템플릿:
614
+
615
+ - `templates/reports/quick-input.template.md`
616
+ - `templates/reports/task-brief.template.md`
617
+ - `templates/reports/error-analysis-input.template.md`
618
+ - `templates/reports/implementation-planning-input.template.md`
619
+ - `templates/reports/implementation-input.template.md`
620
+ - `templates/reports/final-verification-input.template.md`
621
+
622
+ 입력 템플릿에서는 최소한 아래 항목을 채우는 것을 권장합니다.
623
+
624
+ - `Project ID`
625
+ - `Task Group`
626
+ - `Task ID`
627
+ - `Related Tasks`
628
+ - `Task Type`
629
+ - `Requested Outcome`
630
+
631
+ ## Recommended workflow
632
+
633
+ ### 1. 초안 작성
634
+
635
+ 빠르게 메모를 정리할 때는 `okstra-quick-input.template.md`를 사용합니다.
636
+
637
+ ### 2. 정식 brief 작성
638
+
639
+ 최종 입력은 `okstra-task-brief.md`로 정리합니다.
640
+ 같은 task를 다시 이어갈 계획이면 같은 `task-group`과 `task-id`를 유지합니다.
641
+
642
+ ### 2.5. 필요 시 요구사항 triage
643
+
644
+ 요청이 버그 수정인지 신규 기능인지, 요구사항이 충분한지 먼저 분류해야 하면 같은 `okstra-task-brief.md`에 `Task Type: requirements-discovery`를 넣고 실행합니다.
645
+ 이 단계는 이후 phase를 자동 실행하지 않고, work category와 다음 권장 phase를 task lifecycle metadata에 남기는 역할만 합니다.
646
+
647
+ ```bash
648
+ scripts/okstra.sh --task-type requirements-discovery --project-id <project-id> --task-group <task-group> --task-id <task-id> --task-brief <brief-path>
649
+ ```
650
+
651
+ ### 3. Render-only 검증
652
+
653
+ ```bash
654
+ scripts/okstra.sh --render-only --task-type error-analysis --project-id <project-id> --task-group <task-group> --task-id <task-id> --task-brief <brief-path>
655
+ ```
656
+
657
+ ### 4. Claude 실행
658
+
659
+ 두 가지 진입 방식이 있으며 산출물은 동일합니다.
660
+
661
+ **Option A — 새 claude 프로세스를 띄움 (`okstra.sh`)**
662
+
663
+ ```bash
664
+ scripts/okstra.sh --task-type error-analysis --project-id <project-id> --task-group <task-group> --task-id <task-id> --task-brief <brief-path>
665
+ ```
666
+
667
+ 이 경로로 실행하면 `okstra.sh` 가 prepare 단계를 마친 뒤 대상 프로젝트 루트에서 새 Claude interactive session 을 `exec` 합니다. handoff 까지만 수행하고 최종 보고서 저장은 Claude lead 가 이어서 수행합니다. 실행 직전에 `sessions/claude-resume-<task-type>-<seq>.sh` 가 미리 작성되므로 세션이 중간에 끊겨도 같은 run 을 재개할 수 있습니다.
668
+
669
+ **Option B — 현재 claude 세션 안에서 인계 (`okstra-run` skill)**
670
+
671
+ 이미 Claude Code 세션을 사용 중이라면 새 프로세스를 띄우지 않고 같은 세션이 그대로 Claude lead 로 인계받게 할 수 있습니다. trigger 예: `"run okstra here"`, `"start error-analysis on this project"`.
672
+
673
+ skill 흐름:
674
+
675
+ 1. `okstra-run` skill 이 활성화되고 `AskUserQuestion` 으로 task 후보 / task-type / brief 경로를 받습니다.
676
+ 2. 사용자의 입력으로 `okstra_ctl.run.prepare_task_bundle(render_only=True)` 를 호출합니다 — `okstra.sh` 를 거치지 않고 같은 python 함수를 직접 호출합니다.
677
+ 3. 같은 instruction-set 산출물이 디스크에 만들어지면 현재 claude 가 그 prompt 를 읽어 lead 역할로 진입합니다.
678
+
679
+ 자세한 절차는 [`skills/okstra-run/SKILL.md`](skills/okstra-run/SKILL.md) 참조.
680
+
681
+ ### 5. 필요 시 에러 분석
682
+
683
+ ```bash
684
+ scripts/okstra.sh --task-type error-analysis --project-id <project-id> --task-group <task-group> --task-id <task-id> --task-brief <brief-path>
685
+ ```
686
+
687
+ 첫 진입 이후 같은 task에 추가 run이 필요하면 단축 형식 사용:
688
+
689
+ ```bash
690
+ scripts/okstra.sh --task-key <project-id>:<task-group>:<task-id> --task-type error-analysis
691
+ ```
692
+
693
+ ### 5.5. 답변 후 즉시 재실행
694
+
695
+ `requirements-discovery` 또는 `error-analysis` final report의 Section 5에 답변을 채워야 한다면, 경로를 손으로 들고 다닐 필요 없이 한 번에 처리합니다.
696
+
697
+ ```bash
698
+ scripts/okstra.sh --resume-clarification --task-key <project-id>:<task-group>:<task-id>
699
+ ```
700
+
701
+ `$EDITOR`로 최신 final report가 열리고, 저장 후 같은 phase가 자동으로 `--clarification-response` carry-in 으로 재실행됩니다.
702
+
703
+ ### 6. 필요 시 구현 계획 검토
704
+
705
+ ```bash
706
+ scripts/okstra.sh --task-type implementation-planning --workers claude,codex --project-id <project-id> --task-group <task-group> --task-id <task-id> --task-brief <brief-path>
707
+ ```
708
+
709
+ 후속 phase 단축 형식 (manifest의 `workflow.nextRecommendedPhase`가 `implementation-planning`이면 `--task-type` 도 생략 가능):
710
+
711
+ ```bash
712
+ scripts/okstra.sh --task-key <project-id>:<task-group>:<task-id> --workers claude,codex
713
+ ```
714
+
715
+ ### 7. 승인된 plan 기반 구현
716
+
717
+ `implementation-planning` final report의 `User Approval Request` 블록에 사용자 승인이 기록된 뒤에만 실행합니다. 승인된 plan 경로를 `--approved-plan`으로 carry-in해야 하며, plan이 없거나 승인 마커가 없으면 run은 `contract-violated`로 거부됩니다.
718
+
719
+ 승인 마커는 line-anchored, case-insensitive로 다음 중 하나와 일치해야 합니다(코드 진실: `scripts/okstra.sh`).
720
+
721
+ - `APPROVED` (라인 시작에 단독, 또는 뒤에 공백/콜론)
722
+ - `[x] Approved`
723
+ - `User Approval: APPROVED` / `User Approval: granted` / `User Approval: yes`
724
+
725
+ ```bash
726
+ scripts/okstra.sh --task-type implementation --workers claude,codex,gemini --project-id <project-id> --task-group <task-group> --task-id <task-id> --task-brief <brief-path> --approved-plan <runs/implementation-planning/.../reports/final-report.md>
727
+ ```
728
+
729
+ 단축 형식:
730
+
731
+ ```bash
732
+ scripts/okstra.sh --task-key <project-id>:<task-group>:<task-id> --task-type implementation --workers claude,codex,gemini --approved-plan <runs/implementation-planning/.../reports/final-report.md>
733
+ ```
734
+
735
+ ### 8. 구현 후 최종 검토
736
+
737
+ ```bash
738
+ scripts/okstra.sh --task-type final-verification --project-id <project-id> --task-group <task-group> --task-id <task-id> --task-brief <brief-path>
739
+ ```
740
+
741
+ 단축 형식:
742
+
743
+ ```bash
744
+ scripts/okstra.sh --task-key <project-id>:<task-group>:<task-id> --task-type final-verification
745
+ ```
746
+
747
+ ### 9. 같은 task 재개
748
+
749
+ 같은 bugfix나 same workstream을 다시 열면 기존과 같은 `task-group`과 `task-id`를 사용합니다.
750
+ 그러면 기존 task root 아래 `runs/`와 `history/timeline.json`에 이력이 계속 누적됩니다.
751
+ 첫 진입 이후에는 `--task-key <p>:<g>:<i>` 단축 형식이 가장 간결하며, 누락된 brief/task-type은 manifest에서 자동 채워집니다.
752
+
753
+ ## Lifecycle status and resume
754
+
755
+ 장기 작업에서는 `task-manifest.json`의 `workflow`가 canonical lifecycle 상태입니다.
756
+ 특히 아래 항목을 먼저 확인하면 현재 위치와 재개 지점을 빠르게 판단할 수 있습니다.
757
+
758
+ - `workflow.currentPhase`
759
+ - `workflow.currentPhaseState`
760
+ - `workflow.phaseStates`
761
+ - `workflow.lastCompletedPhase`
762
+ - `workflow.nextRecommendedPhase`
763
+ - `workflow.awaitingApproval`
764
+ - `workflow.routingStatus`
765
+ - `workflow.lastSafeCheckpoint`
766
+
767
+ 프로젝트 전체 상태를 훑을 때는 `.project-docs/okstra/discovery/task-catalog.json`을 사용합니다.
768
+ 특정 task의 최신 상태를 볼 때는 `.project-docs/okstra/discovery/latest-task.json`, `task-manifest.json`, 최신 `run-manifest`, `history/timeline.json` 순서로 확인합니다.
769
+
770
+ Claude에서는 seeded `okstra-status` skill을 사용해 아래 질문을 직접 처리할 수 있습니다.
771
+
772
+ - 전체 okstra task status 보여줘
773
+ - 특정 `task-key`의 current phase와 next phase 알려줘
774
+ - approval 대기 중인 task와 resume 가능한 task를 보여줘
775
+ - `<task-id>`의 `workStatus`를 `todo` / `in-progress` / `blocked` / `done`으로 업데이트해줘 (예: "okstra mark <task-id> done", "<task-id> 진행중") — skill이 해당 `task-manifest.json`의 `workStatus`, `workStatusUpdatedAt`, `workStatusNote`를 갱신합니다.
776
+
777
+ resume 판단 기준:
778
+
779
+ - 현재 run 재개: `latestResumeCommandPath`가 있으면 그 경로를 우선 사용합니다.
780
+ - 현재 phase 재시작: 같은 `task-key`와 현재 `task-type`으로 다시 실행합니다.
781
+ - 다음 phase 시작: `workflow.nextRecommendedPhase`가 구체적인 phase면 그 값으로 다음 `okstra.sh` 실행을 준비합니다.
782
+ - 추가 자료 필요: `routingStatus=pending` 또는 `nextRecommendedPhase=pending-routing-decision`이면 brief 보강이 먼저입니다.
783
+
784
+ ## Preferred final report structure
785
+
786
+ 기본 최종 보고서 템플릿은 `templates/reports/final-report.template.md`입니다.
787
+ Claude가 작성하는 최종 보고서는 brief에 더 구체적인 형식이 없다면 아래 구조를 우선 사용합니다.
788
+
789
+ 1. 문제 또는 검증 대상 요약
790
+ 2. 에이전트별 실행 현황
791
+ 3. Cross Verification 결과
792
+ 4. 최종 판단
793
+ 5. 근거 및 세부 분석
794
+ 6. 누락 정보 및 리스크
795
+ 7. 권장 다음 단계
796
+
797
+ 차이점이 실질적으로 없으면 억지로 대비를 만들지 말고, 차이가 없음을 명시합니다.
798
+ 저장 실패나 세션 제한에 대한 메타 설명 대신 실제 Markdown 보고서 본문을 파일에 작성해야 합니다.
799
+
800
+ ## Worker error collection (optional sidecar)
801
+
802
+ 워커(Claude/Codex/Gemini worker, Report writer, Claude lead) 실행 중 발생한 에러를 단일 시계열 로그로 수집해 사후 회고에 사용할 수 있습니다.
803
+
804
+ - 저장 위치: `runs/<task-type>/logs/errors-<task-type>-<seq>.jsonl`
805
+ - append-only JSON Lines, run 단위 격리이므로 별도 회전 정책은 두지 않습니다.
806
+ - **Single writer**: 동시 append 충돌을 피하기 위해 `Claude lead`만 직접 이 파일에 씁니다. `<seq>`는 카테고리(`logs/`, `manifests/`, `state/` 등) 디렉토리별로 독립 스캔되는 3-digit zero-padded counter (`001`, `002`, …)이므로 같은 run에서도 카테고리별 값이 다를 수 있습니다(이전 run이 일부 카테고리만 기록한 경우). 한 run의 cross-category 식별자는 manifest의 `runDateTimeSegment` ISO timestamp 필드입니다.
807
+ - 워커 내부 도구 실패는 워커 결과 매니페스트의 `errors[]`에 보고 → lead가 merge 직후 dump
808
+ - Codex/Gemini CLI 실패·타임아웃·rate-limit는 lead가 wrapper에서 직접 관찰
809
+ - resultContract 위반·스키마 mismatch·필수 필드 누락은 lead 검증 단계에서 직접 관찰
810
+ - `source` 필드(`worker-reported` | `lead-observed`)와 `errorType`(`tool-failure` | `cli-failure` | `contract-violation`)으로 발생원과 종류를 구분합니다.
811
+ - `stderrExcerpt`는 한 줄 jsonl 가독성을 위해 2KB 상한, `PIPE_BUF`(4096B) atomic append 가드를 강제합니다.
812
+ - run-manifest 또는 team-state의 `errorsLogPath` 필드에 `logs/errors-<task-type>-<seq>.jsonl` 경로를 1회 기록해 발견 가능하게 합니다.
813
+ - Helper CLI: `scripts/okstra-error-log.py`
814
+ - 단일 진입점으로 record를 append 합니다.
815
+ - 워커 sidecar dump(`append_observed`, schema version 가드)와 lead 관찰(`lead-observed`) 모두 동일 helper를 사용합니다.
816
+
817
+ 상세 설계 및 jq 회고 레시피는 `docs/superpowers/specs/2026-04-28-worker-error-collection-design.md`를 참고합니다.
818
+
819
+ ## Token usage and cost accounting
820
+
821
+ 각 run에 사용된 토큰을 lead/worker 세션 트랜스크립트에서 수집해 `team-state.json`의 `leadUsage` / `workers[].usage`에 다시 기록합니다.
822
+
823
+ - Helper CLI: `scripts/okstra-token-usage.py`
824
+ - 수집 소스:
825
+ - Claude lead/workers: `~/.claude/projects/<cwd-as-dashes>/<sessionId>.jsonl`의 per-message `message.usage`
826
+ - Codex CLI: `~/.codex/sessions/Y/M/D/rollout-*.jsonl`의 마지막 `total_token_usage.total_tokens`
827
+ - Gemini CLI: `~/.gemini/tmp/*/chats/session-*.json`의 per-message `tokens.total`
828
+ - billable-equivalent token math와 USD cost estimation을 함께 기록합니다. Anthropic billing ratio(`cache_creation=1.25x`, `cache_read=0.1x`, `output=5x`)를 반영합니다.
829
+ - 가격표는 helper 상단에서 중앙 관리합니다. 모델 가격이 바뀌면 helper의 `*_PRICING` 상수를 갱신해야 합니다.
830
+
831
+ ## Practical notes
832
+
833
+ - `okstra`는 brief 없이 쓰는 옛 방식이 아닙니다.
834
+ - brief이 분석의 정본 입력입니다. 추가 자료는 brief 내부의 `Evidence and Source Materials` 섹션에 inline 또는 path 로 포함시키며, 별도의 추가 자료 CLI 옵션은 제공하지 않습니다.
835
+ - brief의 `Configuration References and Expected Values`, `Deployment Manifests and Expected Values` 섹션은 task별 expected state의 canonical source입니다.
836
+ - `task-type`가 프로필 선택까지 결정합니다.
837
+ - `--render-only`는 dry-run 확인용이지만 task bundle과 run manifest는 생성합니다.
838
+ - `--refresh-assets`는 `.claude/skills/`와 `.claude/agents/`의 okstra mapped asset을 source 기준으로 다시 생성합니다.
839
+ - 기본 실행은 Claude print-mode 수집이 아니라 interactive handoff입니다.
840
+ - 기본 최종 보고서 템플릿은 task bundle의 `instruction-set/final-report-template.md`에 렌더링됩니다.
841
+ - task bundle의 `instruction-set/reference-expectations.md`는 config/deployment expected-state reference로 함께 생성됩니다.
842
+ - 현재 run 세션의 resume helper는 `runs/<task-type>/sessions/claude-resume-<task-type>-<seq>.sh`에 생성됩니다.
843
+ - run directory 내부는 `manifests/`, `state/`, `prompts/`, `reports/`, `status/`, `sessions/`, `worker-results/`처럼 유형별 하위 폴더로 구성되고, prompt snapshot은 `prompts/` 아래에 먼저 준비됩니다.
844
+ - worker 생성과 결과 취합은 Claude가 수행합니다.
845
+ - standard workflow는 `Claude lead` + required worker `Claude worker`, `Codex worker`, `Gemini worker`, `Report writer worker`를 사용합니다.
846
+ - worker 모델은 `--lead-model`, `--claude-model`, `--codex-model`, `--gemini-model`, `--report-writer-model`로 override할 수 있고, 기본값은 `OKSTRA_DEFAULT_*` 환경 변수에서 중앙 관리합니다. fallback 기본값은 `Claude lead`/`Report writer worker`=`opus`, `Claude worker`=`sonnet`, `Codex worker`=`gpt-5.5`, `Gemini worker`=`auto`입니다.
847
+ - project-level current-task convenience pointer는 `.project-docs/okstra/discovery/latest-task.json`입니다.
848
+ - project-level canonical task inventory는 `.project-docs/okstra/discovery/task-catalog.json`입니다.
849
+ - project-local okstra Claude asset은 `.claude/skills/`와 `.claude/agents/` 아래에 seed되며, 기본 rerun에서는 보존되고 `--refresh-assets`로 다시 생성할 수 있습니다.
850
+ - seeded okstra Claude assets는 Agent Teams 우선, sequential/background fallback 차선 규칙을 Claude에게 제공합니다.
851
+ - 최종 판단은 스크립트가 아니라 Claude가 수행합니다.
852
+ - stable task key를 유지해야 이후 bug 추적, 재수정, 재검증이 가능합니다.
853
+ - 워커 에러는 옵션 sidecar `runs/<task-type>/logs/errors-<task-type>-<seq>.jsonl`로 수집되며 lead가 단독 writer입니다. 진입점 helper는 `scripts/okstra-error-log.py`입니다.
854
+ - 토큰 사용 및 비용 집계는 `scripts/okstra-token-usage.py`가 담당하며.
855
+ - `okstra.sh`는 worker CLI 호출 anchoring을 위해 절대 projectRoot를 강제합니다.
856
+
857
+ ## Related documents
858
+
859
+ - `README.md`
860
+ - `templates/reports/task-brief.template.md`
861
+ - `templates/reports/final-report.template.md`
862
+ - `agents/SKILL.md`
863
+ - `docs/superpowers/specs/2026-04-28-worker-error-collection-design.md`
864
+ - `docs/superpowers/plans/2026-04-28-worker-error-collection.md`
865
+ - `scripts/okstra-error-log.py`
866
+ - `scripts/okstra-token-usage.py`
867
+
868
+
869
+ ---
870
+
871
+ ## okstra Control Center — 동작 모델 / 동시성 / 환경변수
872
+
873
+ ### 동작 모델
874
+
875
+ - `okstra.sh` 는 시작 시 1번 `record_start` hook 으로 인덱스에 메타와 invocation 을 기록한다.
876
+ - 종료 처리는 `okstra-ctl` 의 모든 진입점에서 호출되는 lazy reconcile 이 수행한다(타깃 프로젝트의 `final-report-*.md` 존재로 추론).
877
+ - 다중 rerun 은 대상 1건당 tmux 세션 1개를 detached 로 spawn 하고 즉시 반환한다(fire-and-forget). 사용자는 반환된 attach 명령으로 임의 세션에 접속한다.
878
+ - spawn 임계 기본값은 10. `--max-spawn N` 또는 `OKSTRA_CTL_MAX_SPAWN` 으로 변경 가능.
879
+ - runId 형식: `<project-id>/<task-group>/<task-id>/<task-type>/r<run-seq>` (예: `fontradar/payment/fail/error-analysis/r07`). 입력 시 prefix substring 매칭을 지원한다.
880
+
881
+ ### 동시성 제어 (두 단계 mutex)
882
+
883
+ `okstra-ctl` 과 `record_start` hook 은 두 가지 서로 다른 스코프의 fcntl `LOCK_EX` 를 사용한다. 둘은 책임이 분리되어 있어 함께 들고 있어도 데드락이 발생하지 않는다.
884
+
885
+ | Lock | 위치 | 스코프 | 보유 시점 | 목적 |
886
+ |---|---|---|---|---|
887
+ | central lock | `~/.okstra/.lock` | 전역(인덱스 단위) | `record_start` 의 `active.jsonl`/`recent.jsonl`/`projects/<id>/index.jsonl` 쓰기 구간, ctl 의 reconcile / reservation 쓰기 구간 | 인덱스 jsonl 의 read-modify-write 직렬화. 동시에 일어나는 record_start append 와 reconcile rotation 이 서로 leak 하지 않게 한다. |
888
+ | task lock | `~/.okstra/.locks/<projectId>-<taskGroup>-<taskId>-<taskType>.lock` | task-key + task-type 별 mutex | `okstra-ctl rerun` 의 seq 예측 + tmux spawn 구간 전체 | 동일 task 의 동시 rerun 이 같은 run-seq 를 받아 manifest/디렉토리 경합으로 깨지는 것을 막는다. central lock 보다 바깥에서 잡으므로, 다른 task 의 rerun 은 서로 블록하지 않는다. |
889
+
890
+ 호출 순서는 항상 `task lock` → `central lock` (ctl rerun) 또는 `central lock` 단독(record_start, reconcile). 역순 보유는 발생하지 않는다.
891
+
892
+ `task_lock_filename` 은 각 세그먼트를 fs-safe 슬러그로 정규화한 뒤 `-` 를 `--` 로 escape 해 `-` 로 join 하므로, `('p','feature-8','email','x')` 와 `('p','feature','8-email','x')` 가 같은 파일명으로 충돌해 mutex 가 공유되는 문제를 방지한다 ([scripts/okstra_ctl/locks.py](scripts/okstra_ctl/locks.py)).
893
+
894
+ ### 환경변수
895
+
896
+ - `OKSTRA_HOME`: 중앙 디렉터리 위치 override (기본 `~/.okstra`).
897
+ - `OKSTRA_CTL_MAX_SPAWN`: rerun 동시 spawn 임계 기본값.
898
+ - `OKSTRA_CTL_SKIP_BACKFILL=1`: 첫 호출 시 자동 백필 스킵.
899
+ - `OKSTRA_CTL_SKIP_RECONCILE=1`: lazy reconcile 스킵(테스트/디버깅용).
900
+ - `OKSTRA_RUN_SEQ_OVERRIDE`: rerun 시 okstra.sh 가 사용할 run-seq 강제값 (okstra-ctl 내부 자동 주입).