okstra 0.117.0 → 0.118.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +115 -104
- package/docs/architecture/storage-model.md +300 -0
- package/docs/architecture.md +802 -0
- package/docs/cli.md +658 -0
- package/docs/container.md +124 -0
- package/docs/contributor-change-matrix.md +5 -4
- package/docs/follow-ups/2026-07-10-final-report-option-3.md +51 -0
- package/docs/performance-improvement-plan-v2.md +374 -0
- package/docs/project-structure-overview.md +21 -10
- package/package.json +10 -5
- package/runtime/BUILD.json +2 -2
- package/runtime/python/okstra_ctl/recap.py +80 -3
- package/runtime/skills/okstra-inspect/SKILL.md +37 -2
- package/runtime/skills/okstra-pr-gen/SKILL.md +9 -8
- package/src/commands/inspect/recap.mjs +6 -1
- package/README.kr.md +0 -231
- package/docs/kr/architecture/storage-model.md +0 -297
- package/docs/kr/architecture.md +0 -815
- package/docs/kr/cli.md +0 -657
- package/docs/kr/container.md +0 -122
- package/docs/kr/follow-ups/2026-07-10-final-report-option-3.md +0 -51
- package/docs/kr/performance-improvement-plan-v2.md +0 -374
- package/docs/kr/performance-improvement-plan.md +0 -147
package/docs/kr/architecture.md
DELETED
|
@@ -1,815 +0,0 @@
|
|
|
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`, `release-handoff` 등 표준 task type 프로파일을 로드해 instruction-set을 렌더링합니다.
|
|
17
|
-
- **Run lifecycle**: 매 실행마다 `runs/<task-type>/` 아래에 manifests, prompts, state, reports, sessions, worker-results, logs를 누적하고, 파일명 suffix `-<task-type>-<seq>`로 같은 phase의 재실행을 분리합니다.
|
|
18
|
-
- **Single python authority**: 모든 prepare wiring(profile/workers/model 해소, path 계산, 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**: 각 phase profile의 `Required workers:` 블록이 roster의 권위입니다. 일반 분석 phase는 Claude/Codex analyser + report-writer를 기본으로 하고, Antigravity는 profile과 `--workers`가 허용할 때만 포함됩니다. `release-handoff`처럼 lead-only에 가까운 phase는 별도 roster를 가집니다.
|
|
21
|
-
- **User-home install + project-local task bundles**: `npx okstra@latest install` 한 명령이 런타임(`~/.okstra/{lib/python, bin, templates, prompts}`)을 설치하고, public skill 을 `~/.agents/skills/` 에 기본 설치합니다. `~/.claude` 가 있으면 Claude skills + worker agent 4종(`~/.claude/agents/*-worker.md`)도 함께 설치합니다. 사용자 진입점 스킬만 목록에 노출되고 lead/support 운영 계약은 `~/.okstra/prompts/` 아래 runtime resource 로 설치되어 skill discovery 대상이 아닙니다. 전역 대화 메모리는 프로젝트와 분리된 `~/.okstra/memory-book/` 에 저장됩니다. 대상 프로젝트에는 task bundle 과 discovery metadata 가 `.okstra/` 아래 저장되고, **추가로 `<PROJECT_ROOT>/.claude/settings.local.json` 이 `~/.okstra/templates/settings.local.json` 을 가리키는 symlink 로 provisioning** 됩니다 (`okstra setup` 또는 `okstra-ctl` prepare 가 idempotent 하게 관리; 기존에 일반 파일이 있었다면 `.bak.<timestamp>` 로 보존 후 교체).
|
|
22
|
-
- **Resume and clarification**: `--task-key`, `--resume-clarification`, `--clarification-response`로 같은 task 재개와 lead의 추가 질문 응답 흐름을 지원합니다.
|
|
23
|
-
- **Derived views and telemetry**: final-report data.json → Markdown → Report View Model → self-contained HTML view, worker error sidecar, wrapper log 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
|
-
- [Artifact-home rule](#artifact-home-rule)
|
|
39
|
-
- [Task type](#task-type)
|
|
40
|
-
- [표준 task type](#표준-task-type)
|
|
41
|
-
- [Phase 간 정보 전달](#phase-간-정보-전달)
|
|
42
|
-
- (CLI 인자 / 옵션 / 인터랙티브 입력은 [cli.md](cli.md) 참조)
|
|
43
|
-
- [Storage model & contracts](#storage-model--contracts) → [`architecture/storage-model.md`](architecture/storage-model.md)
|
|
44
|
-
- Stable task root / per-run artifacts / `~/.okstra` 인덱스
|
|
45
|
-
- Task manifest · task index · run manifest · timeline · Claude operating 계약
|
|
46
|
-
- [Task brief usage](#task-brief-usage)
|
|
47
|
-
- [Recommended workflow](#recommended-workflow)
|
|
48
|
-
- [1. 초안 작성](#1-초안-작성)
|
|
49
|
-
- [2. 정식 brief 작성](#2-정식-brief-작성)
|
|
50
|
-
- [2.5. 필요 시 요구사항 triage](#25-필요-시-요구사항-triage)
|
|
51
|
-
- [3. Render-only 검증](#3-render-only-검증)
|
|
52
|
-
- [4. Claude 실행](#4-claude-실행)
|
|
53
|
-
- [5. 필요 시 에러 분석](#5-필요-시-에러-분석)
|
|
54
|
-
- [5.5. 답변 후 즉시 재실행](#55-답변-후-즉시-재실행)
|
|
55
|
-
- [6. 필요 시 구현 계획 검토](#6-필요-시-구현-계획-검토)
|
|
56
|
-
- [7. 승인된 plan 기반 구현](#7-승인된-plan-기반-구현)
|
|
57
|
-
- [8. 구현 후 최종 검토](#8-구현-후-최종-검토)
|
|
58
|
-
- [9. 같은 task 재개](#9-같은-task-재개)
|
|
59
|
-
- [Lifecycle status and resume](#lifecycle-status-and-resume)
|
|
60
|
-
- [Final report structure](#final-report-structure)
|
|
61
|
-
- [Final report views (HTML)](#final-report-views-html)
|
|
62
|
-
- [Worker error collection (optional sidecar)](#worker-error-collection-optional-sidecar)
|
|
63
|
-
- [Token usage and cost accounting](#token-usage-and-cost-accounting)
|
|
64
|
-
- [Validators](#validators)
|
|
65
|
-
- [Practical notes](#practical-notes)
|
|
66
|
-
- [Related documents](#related-documents)
|
|
67
|
-
|
|
68
|
-
## Purpose
|
|
69
|
-
|
|
70
|
-
이 문서는 `Okstra` 기준의 `okstra` 사용법을 task-key 중심으로 정리한 운영 가이드입니다.
|
|
71
|
-
`README.md`가 빠른 진입점이라면, 이 문서는 `okstra`의 실행 계약과 storage model, lifecycle, Claude handoff 규칙을 설명하는 상세 기준 문서입니다.
|
|
72
|
-
|
|
73
|
-
`okstra`는 단일 파일 리뷰 도구가 아닙니다.
|
|
74
|
-
`okstra`는 Claude Code가 cross verify를 수행할 수 있도록 안정적인 task bundle, run history, project-level discovery metadata를 준비하는 보조 도구입니다.
|
|
75
|
-
|
|
76
|
-
## What okstra does
|
|
77
|
-
|
|
78
|
-
okstra 의 prepare 책임은 단일 python 진입점 [`okstra_ctl.run.prepare_task_bundle`](../../scripts/okstra_ctl/run.py) 에 모여 있습니다. 이 함수가 다음을 한 트랜잭션으로 수행합니다.
|
|
79
|
-
|
|
80
|
-
- okstra 설치 자산(`~/.agents/skills/okstra-*`, optional `~/.claude/skills/okstra-*` / `~/.claude/agents/*-worker.md`, `~/.okstra/bin/...`) 존재 확인
|
|
81
|
-
- `<PROJECT_ROOT>/.okstra/project.json` self-registration (또는 projectId 일치 검증)
|
|
82
|
-
- task type → `prompts/profiles/<task-type>.md` 로드 + 권장 workers 추출
|
|
83
|
-
- 사용자 worker/model 오버라이드 정규화 (Claude/Codex/Antigravity/Report-writer 각각 display ↔ execution-value 매핑)
|
|
84
|
-
- task brief / clarification response 경로 해석 (cwd 우선 → PROJECT_ROOT fallback)
|
|
85
|
-
- per-task mutex(`~/.okstra/.locks/<task-key>.lock`) 안에서 stable task root + 모든 path/seq 계산 후 `<run-dir>/manifests/run-context-<seq>.json` 으로 영속화
|
|
86
|
-
- 사용자 입력을 `<run-dir>/manifests/run-inputs-<seq>.json` 으로 영속화
|
|
87
|
-
- instruction-set 렌더 (`analysis-profile.md`, `analysis-packet.md`, `analysis-material.md`, `task-brief.md`, `reference-expectations.md`, `final-report-template.md`, `final-report-schema.json`, optional `clarification-response.md`, optional `directive.txt`, `claude-execution-prompt.md`) + run prompt snapshot 작성
|
|
88
|
-
- `task-manifest.json` · `task-index.md` · `run-manifest-*.json` · `history/timeline.json` · `discovery/{latest-task,task-catalog}.json` 갱신
|
|
89
|
-
- preassigned Claude session ID + `sessions/claude-resume-*.sh` 작성 (`--render-only` 가 아닐 때)
|
|
90
|
-
- 중앙 인덱스(`~/.okstra/{active,recent}.jsonl`, `projects/<id>/{index.jsonl, meta.json}`) record_start
|
|
91
|
-
|
|
92
|
-
`prepare_task_bundle` 의 두 caller:
|
|
93
|
-
|
|
94
|
-
1. **`scripts/okstra.sh`**: CLI 인자를 파싱·확인하고 → `prepare_task_bundle` 호출 → `--render-only` 가 아니면 `claude --model ... --session-id ... "$PROMPT"` 를 `exec` 으로 띄움. ~160 줄의 thin wrapper.
|
|
95
|
-
2. **`okstra-run` skill**: 같은 claude 세션 안에서 [`okstra_ctl.wizard`](../../scripts/okstra_ctl/wizard.py) 상태머신(`okstra wizard init|step|...` CLI)을 돌려 사용자 입력을 모은 뒤 → `okstra render-bundle` (즉 `prepare_task_bundle(render_only=True)`) 호출 → 렌더된 lead prompt 를 현재 세션이 그대로 읽어 lead 역할 수행. 새 claude 프로세스를 띄우지 않음. 분기/검증/순서는 모두 wizard 가 결정하므로 skill 본문은 `Prompt.kind` 에 맞춰 `AskUserQuestion`(`pick`) 또는 평문 메시지(`text`)를 띄우는 ~30 줄짜리 루프이다.
|
|
96
|
-
|
|
97
|
-
판단 정책과 worker orchestration 은 lead claude 가 담당하고, okstra 의 prepare 단계는 그 lead 가 정확한 입력 묶음과 출력 골격을 받아 일을 시작할 수 있게 정형화된 자산을 준비할 뿐입니다.
|
|
98
|
-
|
|
99
|
-
## Runtime assets vs support assets
|
|
100
|
-
|
|
101
|
-
런타임 진입점은 python 패키지에 모여 있고, bash 와 skill 은 거기로 호출만 보냅니다.
|
|
102
|
-
|
|
103
|
-
### Python module 진입점 (single authority)
|
|
104
|
-
|
|
105
|
-
> **호출 규약.** 아래 `python3 -m okstra_ctl.*` / `python3 -m okstra_project.*` 형태는 **모듈 식별자**일 뿐이며, 시스템 site-packages에 설치되지 않습니다. 직접 셸에서 호출하려면 먼저 `PYTHONPATH` 를 `~/.okstra/lib/python` 으로 export 해야 합니다:
|
|
106
|
-
>
|
|
107
|
-
> ```bash
|
|
108
|
-
> eval "$(okstra paths --shell)" # OKSTRA_PYTHONPATH 등을 export
|
|
109
|
-
> export PYTHONPATH="$OKSTRA_PYTHONPATH"
|
|
110
|
-
> python3 -m okstra_ctl.run --help # 이제 동작
|
|
111
|
-
> ```
|
|
112
|
-
>
|
|
113
|
-
> 위 두 줄을 생략하면 `ModuleNotFoundError: No module named 'okstra_ctl'` 로 즉시 실패합니다 (실제 implementation phase 워커가 docs 만 보고 직접 호출하다가 자주 겪는 패턴). 일반 사용자/워커는 모듈을 직접 부르지 말고 `scripts/okstra.sh` 또는 `/okstra-run` 진입점을 사용하세요 — 그 wrapper 들이 PYTHONPATH 세팅을 자동으로 해 줍니다.
|
|
114
|
-
|
|
115
|
-
- [`okstra_ctl.run`](../../scripts/okstra_ctl/run.py) — `prepare_task_bundle()` orchestrator + argparse CLI (`python3 -m okstra_ctl.run --workspace-root ... --project-root ... ...`, **PYTHONPATH 세팅 필요 — 위 호출 규약 참조**).
|
|
116
|
-
- [`okstra_ctl.paths`](../../scripts/okstra_ctl/paths.py) — `compute_run_paths()` pure path/seq 계산.
|
|
117
|
-
- [`okstra_ctl.run_context`](../../scripts/okstra_ctl/run_context.py) — `compute_and_write_run_context()`, `write_run_inputs()`, per-task mutex.
|
|
118
|
-
- [`okstra_ctl.render`](../../scripts/okstra_ctl/render.py) — task-manifest / run-manifest / timeline / task-index / team-state / launch.template / reference-expectations / discovery render 함수 + `python3 -m okstra_ctl.render <subcommand>` dispatcher (**PYTHONPATH 세팅 필요 — 위 호출 규약 참조**).
|
|
119
|
-
- [`okstra_ctl.workers`](../../scripts/okstra_ctl/workers.py) · [`okstra_ctl.models`](../../scripts/okstra_ctl/models.py) — worker / model 해소.
|
|
120
|
-
- [`okstra_ctl.workflow`](../../scripts/okstra_ctl/workflow.py) — phase rules (PHASE_ALLOWED_OUTPUTS / PHASE_FORBIDDEN_ACTIONS).
|
|
121
|
-
- [`okstra_ctl.material`](../../scripts/okstra_ctl/material.py) — `analysis-material.md` 본문 + related-tasks 빌더.
|
|
122
|
-
- [`okstra_ctl.session`](../../scripts/okstra_ctl/session.py) · [`okstra_ctl.seeding`](../../scripts/okstra_ctl/seeding.py) — Claude session id / resume command / 설치 검증 / runtime settings.
|
|
123
|
-
- [`okstra_ctl.{ids,index,invocation,jsonl,project_meta,reconcile,resolver,sequence,batch,backfill,listing,locks,tmux}`](../../scripts/okstra_ctl/) — 중앙 인덱스 (`~/.okstra`) 의 기존 모듈군.
|
|
124
|
-
- [`okstra_project.{resolver,state}`](../../scripts/okstra_project/) — PROJECT_ROOT 해석 + project.json upsert + task-catalog/manifest reader.
|
|
125
|
-
- [`okstra_ctl.manager_cli`](../../scripts/okstra_ctl/manager_cli.py), [`manager_store`](../../scripts/okstra_ctl/manager_store.py), [`manager_sync`](../../scripts/okstra_ctl/manager_sync.py), [`manager_launch`](../../scripts/okstra_ctl/manager_launch.py), [`manager_paths`](../../scripts/okstra_ctl/manager_paths.py) — `okstra manager` 의 cross-project manager state, one-way project snapshot sync, child launch packet/context 생성.
|
|
126
|
-
|
|
127
|
-
### Bash entry points (thin)
|
|
128
|
-
|
|
129
|
-
- [`scripts/okstra.sh`](../../scripts/okstra.sh) — CLI 파싱 / interactive prompt / confirm-execution-plan / `prepare_task_bundle` 호출 / `exec claude`.
|
|
130
|
-
- [`scripts/lib/okstra/{cli,globals,interactive,project-resolver,usage}.sh`](../../scripts/lib/okstra/) — CLI/인터랙티브 보조만. 산출물 생성 로직 보유 없음.
|
|
131
|
-
- [`scripts/okstra-ctl.sh`](../../scripts/okstra-ctl.sh) + [`scripts/lib/okstra-ctl/`](../../scripts/lib/okstra-ctl/) — 중앙 컨트롤 센터 CLI (list / show / open / rerun / reconcile / 등).
|
|
132
|
-
|
|
133
|
-
### Claude assets (templates + skills)
|
|
134
|
-
|
|
135
|
-
- `prompts/launch.template.md` — lead 프롬프트 템플릿.
|
|
136
|
-
- `prompts/profiles/*.md` — 6종 task-type profile (`requirements-discovery`, `error-analysis`, `implementation-planning`, `implementation`, `final-verification`, `release-handoff`).
|
|
137
|
-
- `templates/project-docs/task-index.template.md` · `templates/reports/final-report.template.md` · `templates/reports/settings.template.json` — 런타임 렌더 입력.
|
|
138
|
-
- `<PROJECT_ROOT>/.okstra/project.json` — 프로젝트 self-registration. okstra.sh 첫 실행 시 자동 생성/검증되며, `--project-root` 미지정 시 ancestor / `git toplevel` 로 PROJECT_ROOT 해석.
|
|
139
|
-
|
|
140
|
-
### Support assets (런타임 비참조)
|
|
141
|
-
|
|
142
|
-
- `templates/reports/*-input.template.md` — 사용자 입력 작성 보조.
|
|
143
|
-
- `validators/validate-workflow.sh`, `validators/validate-schedule.py`, `validators/validate-run.py` — 수동/CI 검증용. `validate-run.py` 의 경로는 run metadata 에 기록.
|
|
144
|
-
|
|
145
|
-
### Skills (`skills/`) and lead resources (`prompts/`)
|
|
146
|
-
|
|
147
|
-
- [`prompts/lead/okstra-lead-contract.md`](../../prompts/lead/okstra-lead-contract.md) — main okstra lead contract. 런타임 리소스(`~/.okstra/prompts/lead/`)이며 agent skill 이 아닙니다.
|
|
148
|
-
- [`skills/okstra-setup/SKILL.md`](../../skills/okstra-setup/SKILL.md) — **첫 실행 부트스트랩**. `okstra install` + `project.json` 생성.
|
|
149
|
-
- [`skills/okstra-run/SKILL.md`](../../skills/okstra-run/SKILL.md) — **현재 claude 세션 안에서 okstra task 를 시작**하는 in-session 진입점. `prepare_task_bundle` 직접 호출.
|
|
150
|
-
- 사용자 호출 가능 스킬은 `skills/okstra-setup/SKILL.md`, `skills/okstra-brief-gen/SKILL.md`, `skills/okstra-run/SKILL.md`, `skills/okstra-manager/SKILL.md`, `skills/okstra-memory/SKILL.md`, `skills/okstra-inspect/SKILL.md`, `skills/okstra-rollup/SKILL.md`, `skills/okstra-schedule/SKILL.md`, `skills/okstra-container-build/SKILL.md` 9종뿐이며, 이것만 agent skill home 으로 복사됩니다 — brief 작성, phase 진행, cross-project manager task 조정, 전역 Memory Book 저장/검색, status/history/report/time/logs/cost/errors/recap read-side, task-group 단위 run 결과 종합(rollup), schedule 보조, 그리고 `okstra-container-build` 는 검증 완료된 task 코드를 docker compose 그룹으로 배포하고 컨테이너별 watcher 로 감시하는 비선형(PHASE_SEQUENCE 외부) 컨테이너 배포/감시 스킬. `okstra-manager` 는 `okstra manager` CLI JSON/launch packet 을 source of truth 로 사용하며, manager-owned plan/assignment/directive/snapshot/event 는 `~/.okstra/managers/<manager-id>/` 아래에 저장합니다. `okstra-rollup` 은 단일 task 집계기(`okstra-inspect` 의 time/errors/recap)를 task-group(또는 프로젝트 전체 catalog)으로 fan-out 하는 read-side 레이어로, deterministic 집계는 `okstra rollup` CLI 가 맡고 report 본문 종합 요약만 스킬(LLM)이 작성합니다. `okstra-inspect` 의 read-side facet 은 `skills/okstra-inspect/SKILL.md` 의 sub-command 표가 정본입니다. `okstra-inspect logs` 는 codex/antigravity wrapper 가 매 dispatch 마다 `runs/<task-type>/prompts/<worker>-prompt-<phase>-<seq>.log` 로 남기는 live-log sidecar 의 인벤토리·정리 안내(read-only), `okstra-inspect cost` 는 `okstra context-cost` 결과 요약, `okstra-inspect errors` 는 task 의 okstra-run 에러 로그를 타임스탬프 markdown error-report 로 모아 렌더하고 요약을 출력, `okstra-inspect recap` 은 task 의 run 간 phase 전·후 요약에 더해 `.okstra` 산출물에 대한 자유 Q&A 까지 답합니다.
|
|
151
|
-
- 내부 운영 계약 — `context-loader` / `team-contract` / `convergence` / `report-writer` 와 lead 계약 — 은 `prompts/lead/*.md` 로, 구현/검증 워커의 언어별 coding preflight 는 `prompts/coding-preflight/*` (overview 라우터 + clean-code + languages/frameworks/architectures 3단계 선택) 로 이동했습니다. 모두 `~/.okstra/prompts/` 에 설치되는 런타임 리소스이며 skill discovery 대상이 아닙니다. generated launch prompt 가 lead 에게 절대 경로를 제공하고, 재설치 시 과거 `okstra-context-loader` / `okstra-team-contract` / `okstra-convergence` / `okstra-report-writer` / `okstra-coding-preflight` / `okstra` skill 디렉터리는 exact-name prune 됩니다.
|
|
152
|
-
- 플러그인 매니페스트: [`../../.claude-plugin/plugin.json`](../../.claude-plugin/plugin.json) — `npx skills@latest add Devonshin/okstra` 보조 채널이 참조. 일반 셋업에는 `npx okstra@latest install` 을 사용한다. 플러그인 매니페스트는 사용자 진입점 9개(`okstra-setup`, `okstra-brief-gen`, `okstra-run`, `okstra-manager`, `okstra-memory`, `okstra-inspect`, `okstra-rollup`, `okstra-schedule`, `okstra-container-build`)만 노출한다.
|
|
153
|
-
- 설치 위치: `~/.claude/skills/<name>/SKILL.md` 또는 `~/.agents/skills/<name>/SKILL.md`.
|
|
154
|
-
- 릴리스 절차: [`../../RELEASING.md`](../../RELEASING.md) — npm publish 흐름과 release-please / manual fallback.
|
|
155
|
-
|
|
156
|
-
## Architecture: python authority + thin callers
|
|
157
|
-
|
|
158
|
-
okstra 의 prepare 단계는 디스크 권위 + 단일 python 진입점 모델을 따릅니다. 이 설계가 두 가지 목표를 동시에 만족합니다.
|
|
159
|
-
|
|
160
|
-
1. **Claude Code 의 병렬 실행과 호환**: 같은 claude 세션이 subagent / 병렬 Bash tool / 백그라운드 작업으로 여러 자식을 띄워도 환경 변수가 공유 변경되지 않으므로 race 가 발생하지 않습니다.
|
|
161
|
-
2. **bash CLI 와 in-session skill 의 동작 동일성**: `okstra.sh` 와 `okstra-run` skill 이 같은 `prepare_task_bundle()` 을 부르기 때문에 산출물·중앙 인덱스 등록·검증 경로가 같습니다.
|
|
162
|
-
|
|
163
|
-
```
|
|
164
|
-
┌────────────────────────────────────────────────────────────────┐
|
|
165
|
-
│ Two callers, one authority │
|
|
166
|
-
├────────────────────────────────────────────────────────────────┤
|
|
167
|
-
│ │
|
|
168
|
-
│ scripts/okstra.sh skills/okstra-run/SKILL.md │
|
|
169
|
-
│ (CLI: bash 인자 파싱) (okstra_ctl.wizard 상태머신 루프) │
|
|
170
|
-
│ │ │ │
|
|
171
|
-
│ └─────────────┬────────────────┘ │
|
|
172
|
-
│ ▼ │
|
|
173
|
-
│ okstra_ctl.run.prepare_task_bundle() │
|
|
174
|
-
│ (single python function — 산출물 전부 책임) │
|
|
175
|
-
│ │ │
|
|
176
|
-
│ ┌────────────┴────────────────┐ │
|
|
177
|
-
│ ▼ ▼ │
|
|
178
|
-
│ on-disk authority ~/.okstra (central index) │
|
|
179
|
-
│ <PROJECT_ROOT>/.okstra/ per-task mutex + record_start │
|
|
180
|
-
└────────────────────────────────────────────────────────────────┘
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
### State authority on disk
|
|
184
|
-
|
|
185
|
-
per-process 환경 변수에 task 정체성·경로·workflow 상태를 보관하지 않습니다. 모든 reader 는 다음 파일에서 매번 계산합니다.
|
|
186
|
-
|
|
187
|
-
| 데이터 | 권위 파일 |
|
|
188
|
-
|---|---|
|
|
189
|
-
| projectId, projectRoot | `<PROJECT_ROOT>/.okstra/project.json` |
|
|
190
|
-
| task identity / workflow | `<task-root>/task-manifest.json` |
|
|
191
|
-
| task 후보 목록 | `<PROJECT_ROOT>/.okstra/discovery/task-catalog.json` |
|
|
192
|
-
| 최신 task 포인터 | `<PROJECT_ROOT>/.okstra/discovery/latest-task.json` |
|
|
193
|
-
| run 입력값 | `<run-dir>/manifests/run-inputs-<task-type>-<seq>.json` |
|
|
194
|
-
| run path hints / seq | `<run-dir>/manifests/run-context-<task-type>-<seq>.json` |
|
|
195
|
-
| run 이력 | `<task-root>/history/timeline.json` |
|
|
196
|
-
| 글로벌 인덱스 | `~/.okstra/{active,recent}.jsonl`, `~/.okstra/projects/<id>/{index.jsonl, meta.json}` |
|
|
197
|
-
|
|
198
|
-
### Concurrency
|
|
199
|
-
|
|
200
|
-
두 종류의 파일 락이 모든 동시성을 처리합니다.
|
|
201
|
-
|
|
202
|
-
- `~/.okstra/.locks/<task-key>.lock` — per-task mutex. `compute_and_write_run_context` 가 seq 계산과 compact `run-context.json` 영속화를 한 트랜잭션으로 묶음. 같은 task 의 두 호출은 직렬화.
|
|
203
|
-
- `~/.okstra/.lock` — 중앙 인덱스 mutex. `record_start` / `reconcile` / `rotate_recent_if_needed` 에서 사용.
|
|
204
|
-
|
|
205
|
-
다른 (project, task-group, task-id) 사이에는 직렬화가 없습니다 — 디스크 경로가 분리되므로 충돌 자체가 없음. 환경 변수 race 가 사라졌으므로 같은 claude 세션이 여러 task 를 병렬 진행해도 안전.
|
|
206
|
-
|
|
207
|
-
### Allowed env vars (사용자 knob 한정)
|
|
208
|
-
|
|
209
|
-
상태 전달 용도가 아닌, 사용자 설정용으로만 다음 env var 를 읽습니다.
|
|
210
|
-
|
|
211
|
-
- `OKSTRA_HOME` — 중앙 디렉터리 위치 override (기본 `~/.okstra`).
|
|
212
|
-
- `OKSTRA_DEFAULT_LEAD_MODEL`, `OKSTRA_DEFAULT_CLAUDE_MODEL`, `OKSTRA_DEFAULT_CODEX_MODEL`, `OKSTRA_DEFAULT_ANTIGRAVITY_MODEL`, `OKSTRA_DEFAULT_REPORT_WRITER_MODEL` — 모델 default.
|
|
213
|
-
- `OKSTRA_TOOL_NAME`, `OKSTRA_COMMAND_NAME` — usage 출력의 표시 이름.
|
|
214
|
-
- `OKSTRA_RUN_SEQ_OVERRIDE` — okstra-ctl rerun / 테스트 hook 이 강제하는 run-seq (per-process).
|
|
215
|
-
|
|
216
|
-
이 외의 `PROJECT_ID`, `TASK_GROUP`, `RUN_*`, `FINAL_*`, `CLAUDE_*` 등은 export 하지 않으며, 자식 프로세스로 leak 되지 않습니다.
|
|
217
|
-
|
|
218
|
-
## Claude execution behavior
|
|
219
|
-
|
|
220
|
-
현재 구현 기준으로 `okstra`의 Claude 실행 방식은 아래와 같습니다.
|
|
221
|
-
|
|
222
|
-
**Mode A — `okstra.sh` 가 새 claude 프로세스를 띄움**
|
|
223
|
-
- `--render-only`를 사용하면 Claude를 실행하지 않고 instruction-set 만 만든 뒤 종료합니다.
|
|
224
|
-
- `--render-only`가 없으면 prepare 단계가 Claude session ID 를 선할당하고 current run 의 `sessions/` 아래에 `claude-resume-<task-type>-<seq>.sh` 를 생성합니다.
|
|
225
|
-
- 이후 대상 프로젝트 루트에서 resolved `Claude lead` model execution value 로 `claude --model <lead> --session-id "$CLAUDE_SESSION_ID" "$PROMPT"` 를 `exec` 합니다. (이전 버전의 `--settings <runtime-settings>` 인자는 0.14.0 부터 제거됨 — 권한은 `<PROJECT_ROOT>/.claude/settings.local.json` symlink 가 담당.)
|
|
226
|
-
- `okstra.sh` 는 handoff 까지만 수행하고, 최종 보고서 저장과 run/task 상태 갱신은 Claude lead 가 이어서 수행합니다.
|
|
227
|
-
|
|
228
|
-
**Mode B — `okstra-run` skill 이 현재 claude 세션 안에서 인계**
|
|
229
|
-
- 사용자가 이미 claude 세션에 있고 거기서 새 okstra task 를 시작하고 싶을 때 사용합니다.
|
|
230
|
-
- skill 이 `AskUserQuestion` 으로 task 후보·task-type·brief 등을 받고 `prepare_task_bundle(render_only=True)` 를 호출해 동일한 instruction-set 을 디스크에 만듭니다.
|
|
231
|
-
- 새 claude 프로세스는 띄우지 않고, 현재 세션이 렌더된 lead prompt 를 읽어 lead 역할로 즉시 진입합니다.
|
|
232
|
-
|
|
233
|
-
두 모드 모두 동일한 산출물(task-manifest, run-manifest, timeline, instruction-set, central index 등록) 을 만들며, `okstra-ctl` 의 후속 명령(list / show / rerun / reconcile)은 산출물 차이를 알지 못한 채 일관되게 동작합니다.
|
|
234
|
-
- handoff된 메인 Claude는 `Claude lead`로 동작하며 orchestration과 final synthesis를 담당합니다.
|
|
235
|
-
- standard workflow의 기본 worker role은 `Claude worker`, `Codex worker`, `Report writer worker`이며, `Antigravity worker`는 `--workers` 또는 프로필에서 명시할 때만 포함되는 옵션입니다.
|
|
236
|
-
- worker 역할 분담과 최종 판단은 Claude가 task bundle을 읽고 수행합니다.
|
|
237
|
-
- 사용자 홈에 설치된 okstra Claude assets(`~/.claude/skills`, `~/.claude/agents`) 는 `Agent(name: ...)` 로 워커를 dispatch 하도록 Claude 를 유도합니다 — 워커는 세션의 implicit team 에 자동 합류합니다.
|
|
238
|
-
- **팀 lifecycle (Claude Code v2.1.178+)**: v2.1.178 이 `TeamCreate` / `TeamDelete` 도구와 `Agent(...)` 의 `team_name` 파라미터를 제거했습니다. `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`(`okstra install` 이 `settings.json` 에 시드) 이면 세션마다 implicit team 1개가 시작 시점에 자동 생성됩니다. lead 는 Phase 3 에서 팀을 만드는 도구를 호출하지 않고, `teamName` audit 라벨과 `teamCreate: { attempted: false, status: "implicit", splitPane: <$TMUX 유무> }` 만 기록한 뒤 워커를 `Agent(name: "<role>-worker", run_in_background: true)`(team_name 없음)로 dispatch 합니다. split-pane teammate 는 `$TMUX` 가 설정돼 있고 `teammateMode: auto` 일 때 나타나며, tmux 밖이면 in-process 로 돕니다(둘 다 정상). run 종료 시 Phase 7 토큰 집계 이후 잔여 tmux pane 정리를 확인하고, split-pane run 에서만 worker teammate 를 정리할지 확인합니다. 승인 시 `okstra-team-reconcile.sh` 로 dead-pane stale-active 멤버를 inactive 로 정리하고 각 완료 teammate 에 `SendMessage` shutdown_request 를 보냅니다 — implicit team 자체를 지우는 도구는 없으며, 팀은 세션 종료와 함께 사라집니다. 사용자가 유지하면 teammate 는 FleetView roster 에 남고, lead 는 Teams/FleetView 에서 제거하라고 안내합니다 (`prompts/profiles/_common-contract.md` 의 *Run-end teammate teardown*). Phase 7 토큰 집계는 `teamCreate.status` 가 `implicit`/`skipped`/`error` 일 때 top-level `agentName` 또는 nested `subagents/agent-a<name>-<hash>.jsonl` 파일명 기반으로 워커 세션을 찾습니다.
|
|
239
|
-
|
|
240
|
-
## Claude prompt contract
|
|
241
|
-
|
|
242
|
-
Claude launch prompt 본문은 항상 `prompts/launch.template.md` 템플릿에서만 렌더링됩니다.
|
|
243
|
-
|
|
244
|
-
- 프롬프트 치환은 task key, session ID, 절대/상대 경로 같은 scalar placeholder 값으로만 제한합니다.
|
|
245
|
-
- 선택된 profile 본문은 `instruction-set/analysis-profile.md`로 렌더링합니다.
|
|
246
|
-
- 분석 자료 본문은 `instruction-set/analysis-material.md`로 렌더링합니다.
|
|
247
|
-
- config/deployment expected-state 본문은 `instruction-set/reference-expectations.md`로 렌더링합니다.
|
|
248
|
-
- Claude는 위 artifact 파일들을 직접 읽어야 하며, 긴 task-specific 본문이 launch prompt 안에 inline으로 복제되면 안 됩니다.
|
|
249
|
-
|
|
250
|
-
## Required team contract
|
|
251
|
-
|
|
252
|
-
표준 `okstra` workflow는 아래 팀 계약을 runtime prompt, profile, manifest, skill 문서에 공통으로 반영합니다.
|
|
253
|
-
|
|
254
|
-
- 메인 Claude는 항상 `Claude lead`이며 synthesis-only로 동작합니다.
|
|
255
|
-
- 기본 required worker role은 `Claude worker`, `Codex worker`, `Report writer worker`입니다. `Antigravity worker`는 옵션 워커로, `--workers` 또는 프로필의 `- Workers:` 섹션에 명시될 때만 required 로 포함됩니다.
|
|
256
|
-
- `Report writer worker`는 보고서 구조화와 근거 정리에 집중하지만 최종 synthesis owner는 여전히 `Claude lead`입니다.
|
|
257
|
-
- 기본 모델 계약은 중앙 기본값에서 계산합니다. 기본 fallback은 `Claude lead`=`opus`, `Claude worker`=`opus`, `Codex worker`=`gpt-5.5`, `Antigravity worker`=`auto`(opt-in 시 적용)이며, `Report writer worker`는 별도 override가 없으면 `Claude lead` 모델을 따릅니다(즉, 기본값에서는 `opus`).
|
|
258
|
-
- `Antigravity worker`는 옵션이므로 명시 포함된 run에 한해서만 시도 대상이 됩니다.
|
|
259
|
-
- 최종 판단 전에는 현재 run의 worker roster 에 포함된 각 required role별로 결과 또는 명시적인 terminal status(`completed`, `timeout`, `error`, `not-run`)가 필요합니다.
|
|
260
|
-
- 시도된 worker(`completed`, `timeout`, `error`)는 현재 run의 `prompts/` 아래 assigned worker prompt history file을 반드시 가져야 합니다.
|
|
261
|
-
- 이름 없는 generic parallel worker는 required role 대체 수단으로 허용하지 않습니다.
|
|
262
|
-
|
|
263
|
-
## Stable task identity
|
|
264
|
-
|
|
265
|
-
`okstra`의 기본 식별자는 아래 조합입니다.
|
|
266
|
-
|
|
267
|
-
- `project-id`
|
|
268
|
-
- `task-group`
|
|
269
|
-
- `task-id`
|
|
270
|
-
|
|
271
|
-
논리적 task key는 아래 형식입니다.
|
|
272
|
-
|
|
273
|
-
```text
|
|
274
|
-
<project-id>:<task-group>:<task-id>
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
같은 버그를 다시 열거나 같은 작업을 이어서 진행할 때는 같은 `task-group`과 `task-id`를 재사용합니다.
|
|
278
|
-
새로운 unrelated 작업이면 새 `task-group` 또는 새 `task-id`를 사용합니다.
|
|
279
|
-
|
|
280
|
-
## Project self-registration
|
|
281
|
-
|
|
282
|
-
`okstra.sh` 는 외부 등록 디렉토리(과거 `examples/projects/*.conf.sh` 모델은 폐기됨) 없이 동작합니다. 매 실행 시작 시 PROJECT_ROOT 를 다음 우선순위로 해석한 뒤 그 위치의 `.okstra/project.json` 을 권위 소스로 자기 등록합니다.
|
|
283
|
-
|
|
284
|
-
해석 우선순위:
|
|
285
|
-
|
|
286
|
-
1. CLI 인자 `--project-root <path>`.
|
|
287
|
-
2. cwd 또는 그 조상 디렉토리 중 `.okstra/project.json` 보유 위치.
|
|
288
|
-
3. cwd 의 `git rev-parse --show-toplevel`.
|
|
289
|
-
|
|
290
|
-
셋 다 실패하면 `okstra.sh` 는 즉시 에러로 종료합니다 (자동 추정 없음).
|
|
291
|
-
|
|
292
|
-
`<PROJECT_ROOT>/.okstra/project.json` 스키마:
|
|
293
|
-
|
|
294
|
-
```json
|
|
295
|
-
{
|
|
296
|
-
"projectId": "sample-project-v2-api",
|
|
297
|
-
"projectRoot": "/Volumes/Workspaces/workspace/projects/sample-project",
|
|
298
|
-
"createdAt": "2026-05-10T00:00:00Z",
|
|
299
|
-
"updatedAt": "2026-05-10T00:00:00Z",
|
|
300
|
-
"worktreeSyncDirs": [".project-docs", ".scratch", "graphify-out", ".claude"]
|
|
301
|
-
}
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
처음 실행이면 위 4-필드(`projectId`, `projectRoot`, `createdAt`, `updatedAt`)를 새로 작성합니다. 이미 존재하면 `--project-id` 인자값과 저장된 `projectId` 가 일치하는지 검증한 뒤 `projectRoot`/`updatedAt` 만 갱신하고, 사용자가 추가한 알 수 없는 필드(`worktreeSyncDirs`, 향후 `mcpServers` 등)는 upsert 과정에서 보존됩니다. 불일치 시 즉시 종료해 동일 디렉토리에서 두 개의 ID 가 혼용되는 것을 막습니다.
|
|
305
|
-
|
|
306
|
-
`worktreeSyncDirs` (선택) 는 task worktree 로 symlink 할 project-root-relative 디렉토리 목록을 per-project 로 override 합니다. 해석 우선순위는 `OKSTRA_WORKTREE_SYNC_DIRS` 환경변수 → `project.json` → built-in default (`.project-docs`, `.scratch`, `graphify-out`, `.claude`). 빈 배열을 지정하면 sync 자체를 비활성화합니다. sync 는 filesystem continuity 용도일 뿐이며, okstra context/write boundary 는 계속 `<PROJECT_ROOT>/.okstra/**` 입니다.
|
|
307
|
-
|
|
308
|
-
`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` 환경변수도 함께 폐기되었습니다.
|
|
309
|
-
|
|
310
|
-
## Artifact-home rule
|
|
311
|
-
|
|
312
|
-
okstra 의 project artifact root 는 `<PROJECT_ROOT>/.okstra/` 하나뿐입니다. 이 root 밖은 okstra memory 가 아닙니다. brief 의 `Source Material` 또는 `Reporter Confirmations` 가 명시적으로 cite 한 경우에만 read-only source material 로 읽고, 자체 판단으로 root 밖에 쓰지 않습니다.
|
|
313
|
-
|
|
314
|
-
유일한 예외: brief 의 `Source Material` 또는 `Reporter Confirmations` 섹션에서 사용자가 **verbatim** 으로 특정 non-okstra 파일 편집을 요청한 경우. 해당 편집을 수행하는 phase 는 자신의 final-report 에 사용자 원문 인용을 함께 남겨야 합니다.
|
|
315
|
-
|
|
316
|
-
okstra 는 자기 subtree 안에 자체 institutional memory 를 유지합니다.
|
|
317
|
-
|
|
318
|
-
- `<PROJECT_ROOT>/.okstra/glossary.md` — run 을 가로지르며 누적되는 okstra 용어집.
|
|
319
|
-
- `<PROJECT_ROOT>/.okstra/decisions/<NNNN>-<slug>.md` — okstra 의 결정 기록. 평가 시점은 `implementation-planning` phase 이며 `okstra-brief-gen` 단계에서는 후보만 표시합니다.
|
|
320
|
-
|
|
321
|
-
okstra phase 는 PRD / issue file 을 직접 쓰지 않습니다. 동등한 결정 산출물은 `requirements-discovery` 와 `implementation-planning` 이 `.okstra/` 내부에 만듭니다.
|
|
322
|
-
|
|
323
|
-
## Task type
|
|
324
|
-
|
|
325
|
-
`task-type`은 이번 run의 목적과 profile 선택, 그리고 lifecycle phase 라우팅을 동시에 결정합니다.
|
|
326
|
-
|
|
327
|
-
선택 규칙:
|
|
328
|
-
|
|
329
|
-
- `--task-type <name>`을 주면 `prompts/profiles/<name>.md`가 task bundle의 `instruction-set/analysis-profile.md`로 렌더링됩니다.
|
|
330
|
-
- 외부 인터페이스 기준 단일 선택자는 `task-type`입니다.
|
|
331
|
-
- 선택된 task type은 task-manifest.json의 `taskType`, `workflow.currentPhase`, `workflow.nextRecommendedPhase`에 그대로 반영됩니다.
|
|
332
|
-
- run directory 경로 세그먼트로도 사용됩니다(`runs/<task-type>/...`).
|
|
333
|
-
|
|
334
|
-
### 표준 task type
|
|
335
|
-
|
|
336
|
-
각 task type은 phase별 허용/금지 행동을 강제하며, 한 run은 자기 task type의 산출물만 만들고 다음 phase로 이행하지 않습니다. 다음 phase는 항상 새로운 `okstra.sh` 실행에서 시작합니다.
|
|
337
|
-
|
|
338
|
-
| task type | 목적 | 핵심 산출물 | 다음 권장 phase | 코드 변경 허용 여부 |
|
|
339
|
-
|---|---|---|---|---|
|
|
340
|
-
| `requirements-discovery` | 요청을 bugfix/feature/refactor/ops/improvement 중 하나로 분류하고 안전한 다음 phase로 라우팅 | work category, routing decision, missing-input list, clarification requests | `pending-routing-decision` (사용자 답변 후 결정) | 금지 |
|
|
341
|
-
| `error-analysis` | 보고된 에러/사고의 증상·원인·재현 갭을 증거 기반으로 분석 | symptom/trigger 정리, root-cause 가설, reproduction gap, validation 경로 | `implementation-planning` | 금지 |
|
|
342
|
-
| `implementation-planning` | 코딩 시작 전 안전한 구현 방향과 옵션을 평가 | 최소 2개 구현 옵션, 영향 파일 목록, trade-off, validation/rollback, YAML frontmatter `approved: false` / `implementation-option:`, **§5.5.9 Plan Body Verification** (Phase 6 워커 사후 검증 라운드 — 합성된 plan 의 내적 일관성을 워커가 `AGREE` / `DISAGREE(a-e)` / `SUPPLEMENT` 로 cross-verify; gate 결과가 `passed` / `passed-with-dissent` 일 때만 사용자가 frontmatter 를 `approved: true` 로 뒤집을 수 있고, `blocked-by-disagreement` / `aborted-non-result` 일 때는 majority DISAGREE 항목이 `## 1. Clarification Items` 의 `Blocks=approval` row 로 변환됨). **산출 구조**: 항상 `## 5.5 Stage Map` + N 개의 `## 5.5.<i> Stage <i>` 섹션. 각 stage 의 effective step ≤ 8. `depends-on (none)` 인 stage 들은 별도 `implementation` run 으로 병렬 실행 가능 | `implementation` (사용자 승인 후) | 금지 |
|
|
343
|
-
| `implementation` | 승인된 `implementation-planning` final report의 단계대로 소스 코드를 수정. **한 run 에 한 stage 만 실행** (`--stage <auto\|N>` 인수로 stage 선택) | commit list, diff summary, out-of-plan edits 블록, validation/TDD evidence, rollback 검증, verifier 결과(Antigravity/Codex/Claude), `carry/stage-<N>.json` evidence sidecar | `final-verification` | 허용 (승인된 plan의 파일 목록 한정, `git push`/publish/deploy/실제 migration 금지) |
|
|
344
|
-
| `final-verification` | 완료된 작업의 잔존 결함·회귀 위험을 점검하고 release 판단 | acceptance verdict, residual risk, follow-up 라우팅(`error-analysis`/`implementation-planning`/`release-handoff`) | `pending-release-handoff` (verdict 가 `accepted` 일 때만 `release-handoff` 로 진입; 그 외에는 `error-analysis` 또는 `implementation-planning` 으로 리라우팅) | 금지 (read-only 테스트만 허용) |
|
|
345
|
-
| `release-handoff` | `accepted` 받은 변경을 사용자가 선택한 방식대로 커밋·푸시·PR 로 전달 | 사용자 메뉴 응답(H1 action / H2 PR base / H3 message handling) 기록, 실행한 git/gh 명령 로그, commit SHA 목록, PR URL | `done-or-follow-up` | 허용 — 단 **사용자가 메뉴로 선택한 mutating 명령만** 실행. `git push --force*`, base 브랜치 직접 push, `--no-verify`, `gh release`, publish/deploy 는 금지. source code 자체는 수정 금지(이전 `implementation` 의 diff 를 그대로 패키징). |
|
|
346
|
-
|
|
347
|
-
공통 제약:
|
|
348
|
-
|
|
349
|
-
- `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는 여전히 금지됩니다.
|
|
350
|
-
- **모든 task-type 격리 worktree (BLOCKING)**: 모든 task-type 의 첫 번째 phase prepare 단계에서 `okstra-ctl` 이 자동으로 task-key 단위 `git worktree` 를 생성하고, 같은 task-key 의 이후 phase (`requirements-discovery` → `error-analysis` → `implementation-planning` → `implementation`) 는 동일한 worktree·브랜치를 재사용합니다. 위치는 `~/.okstra/worktrees/<project-id>/<task-group-segment>/<task-id-segment>/` (segment 의 `/`·`:` 등 특수문자는 `-` 로 정규화) 이고, 브랜치 이름은 `<work-category-namespace>/<task-id-segment>` (예: `feature/dev-9436`, `fix/dev-7311`) 입니다. 네임스페이스는 work_category 로 결정됩니다(`feature`·`improvement`→`feature/`, `bugfix`→`fix/`, `refactor`→`refactor/`, `ops`→`ops/`, 미지정→`task/`). base ref 는 첫 phase prepare 시점의 main worktree `HEAD`. `~/.okstra/worktrees/registry.json` (flock-guarded) 가 task-key → path/branch 매핑을 전역 관리해 동시 실행 시 path·branch 충돌을 방지합니다. configured sync dirs 는 main worktree 에서 symlink 로 연결되어 task checkout 사이의 filesystem continuity 를 제공합니다 (sync 대상 목록은 `project.json` 의 `worktreeSyncDirs` 또는 `OKSTRA_WORKTREE_SYNC_DIRS` 환경변수로 override 가능; 빈 배열이면 sync 비활성화). 이 sync 는 okstra context/write boundary 를 확장하지 않습니다. caller 가 이미 다른 worktree 안에 있거나 project_root 가 git repo 가 아니면 provisioning 은 skip 되고 executor 는 project_root 에서 그대로 작업합니다. worktree 는 run 종료 후 자동 삭제되지 않으며 후속 phase·PR 작성·rollback 검증의 권위 artefact 입니다. 수동 cleanup: `git -C <main-worktree> worktree remove <path>` → `git -C <main-worktree> branch -D <branch>` + registry 항목 삭제. 자세한 동작은 `prompts/profiles/implementation.md` 의 *Task worktree* 블록과 `prompts/lead/okstra-lead-contract.md` 의 *Task worktree (BLOCKING for every task-type)* 섹션 참고.
|
|
351
|
-
- **implementation stage 격리 worktree (동시 병렬)**: 위 task-key 단위 worktree 는 `requirements-discovery`~`implementation-planning` 의 모델입니다. `implementation` task 는 **stage 격리** 로 동작합니다 — **한 run = 한 stage**, 각 run 이 `.../<task-id-segment>/stage-<N>/` (브랜치 `<work-category-namespace>/<task-id-segment>-s<N>`) 격리 worktree 를 발급받습니다. registry 가 task-key 와 **stage-key** (`<task-key>#stage-<N>`) 를 함께 flock 예약하고, Stage Lifecycle Snapshot 이 `consumers.jsonl` 의 `done`/`started`, carry sidecar backfill, registry 예약 stage 를 함께 읽어 ready 집합에서 제외하므로(점유 SSOT = registry), 사용자가 두 `implementation` run 을 동시에 띄우면 서로 다른 독립 stage 를 충돌 없이 진행합니다. base 결정: 독립 = 공통 anchor(첫 stage 진입 HEAD 고정), 단일 의존 = 선행 done commit, 다중 의존 = 선행이 모두 ancestor 인 task worktree HEAD(`git merge-base --is-ancestor`; 미머지 시 `PrepareError`). cost-aware-design 의 ready-set batch 는 stage 마다 격리 branch 가 필요해 의미를 잃으므로(같은 branch 에 두 stage-key reserve 시 branch-uniqueness 충돌) 폐기되었고, 순차 진행은 stage done 후 다음 run, 동시 진행은 별도 run 으로 — cost 등가. `--stage <auto|N>` 또는 wizard `stage_pick` 으로 stage 를 선택합니다. wizard `stage_pick` 은 각 stage 의 상태(`[완료]`/`[진행중]`/`[준비됨]`/`[대기]`)를 라벨에 표시하는 멀티선택이며, 선택분의 의존성 closure 를 Kahn 위상정렬(`stage_targets.order_stage_closure`)해 render-args 의 `chain-stages` CSV 로 내보냅니다. `okstra-run` SKILL 이 이 큐를 받아 의존성 순서대로 단일-stage run 을 N 회 순차 실행(무인 연쇄)하되, 각 stage 의 Phase 6 `done` 행을 확인한 뒤 다음으로 넘어갑니다. 이는 오케스트레이션 계층일 뿐이며 wizard·prepare 의 **한 run = 한 stage** 격리 불변은 그대로입니다. worktree 뿐 아니라 **run 산출물(report·state·worker-results·manifest)도 `runs/implementation/stage-<N>/` 로 stage 별 격리**되므로 동시 실행하는 두 stage 의 보고서·상태가 섞이지 않습니다. 반면 `consumers.jsonl` 과 worktree registry 는 stage 간 공유되는 조율 SSOT 라 task-type 루트(`runs/implementation/`)에 그대로 둡니다.
|
|
352
|
-
- **단일-stage final-verification 의 run 산출물 격리 (동시 병렬)**: 단독-stage `final-verification`(`--stage <N>`)도 implementation 과 동일하게 run 산출물을 `runs/final-verification/stage-<N>/` 하위에 격리하고(seq 도 stage 별 독립), 팀 이름에 `-fv-s<N>` 접미사를 붙입니다 — `-fv-` 구분자로 같은 stage 의 implementation 팀(`-s<N>`)과도, 전체-task 검증의 기본 이름과도 충돌하지 않습니다. 따라서 여러 stage 의 final-verification 을 동시에 띄워도 state·worker-results·보고서·팀이 섞이지 않습니다. worktree 는 새로 만들지 않고 해당 implementation stage worktree 를 registry 에서 read-only 로 재사용하며, 그래서 registry stage-key 예약도 하지 않습니다. `teamName` 라벨에 `-fv-s<N>` 접미사를 붙이는 것은 audit/표시용 구분일 뿐이며, 실제 팀은 세션별 implicit team(`session-<leadSid>`)이라 v2.1.178 이전의 `TeamCreate` 이름 충돌 hard-fail 은 더 이상 발생하지 않습니다. 전체-task 검증(stage 빈 값)은 기존 평면 `runs/final-verification/` 구조를 유지합니다.
|
|
353
|
-
- `implementation` 과 `release-handoff` 를 제외한 모든 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 는 여전히 금지됩니다. `release-handoff` 는 source code 자체는 수정하지 않고, 사용자가 메뉴로 선택한 commit / push / PR 명령만 실행합니다 (force push, base 브랜치 직접 push, hook bypass, release publish 는 여전히 금지).
|
|
354
|
-
- 사용자가 "다음 단계 진행해" 같은 표현을 보내도, 그 발화만으로 다음 phase가 자동 시작되지 않습니다. 다음 phase는 새 `okstra.sh` 실행으로만 시작합니다.
|
|
355
|
-
- **Authority & permissions assumption (모든 task-type 및 `okstra-schedule` 공통)**: 사용자(및 팀)는 예상되는 모든 작업에 대해 완전한 권한·승인 권한을 보유한다고 가정합니다. 외부 승인, 서드파티 액세스, 역할/IAM 권한, 조직적 sign-off, 법무·보안 검토, 벤더 협의, "권한 보유 여부 확인" 같은 항목을 routing 결정·missing inputs·clarification questions·risk·dependency·open questions·effort/day 추정에 포함하지 않습니다. okstra 내부 phase 핸드오프(`implementation-planning`의 `approved:` frontmatter 등)는 사용자 본인이 즉시 승인 가능한 내부 게이트이므로 영향 없으며, `implementation`의 forbidden actions(`git push`, prod deploy, shared-DB migration 등)도 권한 사유가 아닌 **안전 사유**로 계속 적용됩니다.
|
|
356
|
-
- Phase별 상세 규칙은 `prompts/profiles/<task-type>.md`에 정의되어 있고, 그 본문이 그대로 `instruction-set/analysis-profile.md`로 렌더링됩니다.
|
|
357
|
-
|
|
358
|
-
### Phase 간 정보 전달
|
|
359
|
-
|
|
360
|
-
- `requirements-discovery`, `error-analysis`, 또는 `implementation-planning` 이 남긴 final report 의 `## 1. Clarification Items` 섹션에 사용자가 답변을 채운 뒤, 다음 run 에서 `--clarification-response <previous-final-report.md>` 로 그 파일을 carry-in합니다.
|
|
361
|
-
- carry-in된 파일은 현재 run의 `instruction-set/clarification-response.md`로 복사되고, lead가 Section 0에서 prior `Q*` 행의 `Status`(`resolved` / `obsolete`)를 갱신한 뒤 진행합니다.
|
|
362
|
-
- 답변 편집과 재실행을 한 번에 처리하려면 `--resume-clarification` 모드를 사용합니다. 자세한 동작은 `### --resume-clarification` 섹션을 참고합니다.
|
|
363
|
-
- **Stage carry-in (`implementation` → 다음 stage)**: 각 `implementation` run 은 `runs/implementation/carry/stage-<N>.json` evidence sidecar 를 남깁니다. 다음 stage 가 실행될 때 이 파일을 자동으로 carry-in 합니다. 어떤 `implementation` run 이 어떤 stage 를 소비했는지는 `runs/implementation-planning/consumers.jsonl` 에 역링크로 누적됩니다.
|
|
364
|
-
|
|
365
|
-
### Fix cycle (사후 버그 핫픽스 이력)
|
|
366
|
-
|
|
367
|
-
release-handoff 까지 완료된 task 의 산출물에서 버그가 발견되면, 같은 task-id 에 entry phase (`requirements-discovery` / `error-analysis` / `implementation-planning`) 로 재진입해 고칩니다 — 전용 hotfix task-type 은 없고 phase gate 는 그대로입니다. 이 재진입 run 묶음이 **fix cycle** 이며, SSOT 는 `<task_root>/history/fix-cycles.jsonl` 의 append-only 이벤트 행 (`opened` / `run` / `closed`, 모듈 `scripts/okstra_ctl/fix_cycles.py` 단독 소유) 입니다. entry phase 목록은 `fix_cycles.FIX_CYCLE_ENTRY_PHASES` 한 곳에서만 정의되고 prepare 게이트와 wizard 감지 술어가 공유합니다.
|
|
368
|
-
|
|
369
|
-
- **진입**: okstra-run wizard 가 완료 task + entry phase 재진입을 감지해 `fix_cycle_confirm` 단계로 확인합니다. CLI 는 `--fix-cycle <yes|no>` (미지정 시 기록하지 않음). `--fix-cycle yes` 는 두 가드를 모두 통과해야 cycle 을 엽니다 — task-type 이 entry phase 이고, manifest 의 `workflow.lastCompletedPhase` 가 `release-handoff` 여야 하며, 위반 시 `PrepareError`. open cycle 은 task 당 동시 1개입니다.
|
|
370
|
-
- **부착**: cycle 이 open 인 동안 같은 task 의 모든 run 이 (이후 `--fix-cycle` 플래그 없이도) `run` 행으로 부착되고, run-manifest / timeline 항목에 `fixCycleId` 가 찍힙니다.
|
|
371
|
-
- **종료**: open cycle 에 release-handoff run 이 부착된 뒤 manifest 의 `workflow.lastCompletedPhase` 가 `release-handoff` 가 되면, 다음 prepare 가 `closed` 행을 lazy-append 합니다.
|
|
372
|
-
- **소비처 (전부 파생 뷰)**: ① 후속 run 의 analysis-packet `## Fix History` 섹션 ② okstra-brief-gen 의 Task Continuity Notes 인용 ③ final-report `## 5.10 Fix History` (run-manifest 에 `fixCycleId` 가 있으면 data.json `fixCycle` 블록을 validator `_validate_fix_cycle` 가 강제) ④ task-manifest `fixCycles` 요약 + task-index / task-catalog 한 줄. 네 소비처 모두 `fix_cycles.summarize()` / `packet_summary()` 파생 뷰만 읽습니다.
|
|
373
|
-
|
|
374
|
-
### release-handoff stage-group 모드
|
|
375
|
-
|
|
376
|
-
`release-handoff` 는 두 모드로 동작합니다.
|
|
377
|
-
|
|
378
|
-
- **whole-task (기본)**: task 전체를 1개 PR 로 내보냅니다. 기존 동작입니다.
|
|
379
|
-
- **stage-group**: 단독-stage final-verification 에서 `accepted` 를 받은 stage 들 중 일부를 골라, 수집(collector) 브랜치로 묶어 1개 PR 로 내보냅니다. task 전체가 끝나기를 기다리지 않고 검증 완료된 stage 묶음 단위로 PR 을 낼 수 있습니다.
|
|
380
|
-
|
|
381
|
-
진입은 brief 없이 **task-id 기반**입니다 — brief 는 entry phase 의 입력물이고, release-handoff 는 prepare 가 approved plan 의 Stage Map + Stage Lifecycle Snapshot 으로 자격을 판정한 뒤 검증 보고서를 인용하는 input 문서(`<task_root>/release-handoff-input.md`)를 자동 생성합니다. stage 선택은 okstra-run wizard 의 `handoff_stage_pick` 멀티선택(eligible stage 묶음 / accepted whole-task 보고서가 있으면 전체 task) 또는 CLI `--stages <csv>` 로 들어오고, run-context 의 `HANDOFF_MODE` / `HANDOFF_STAGES` 로 lead 에 노출됩니다.
|
|
382
|
-
|
|
383
|
-
stage-group 의 상호작용 순서: **G1 base 선택 → G2 stage 확인(선택은 prepare 전에 끝남 — 재질문 없음) → assemble(수집 브랜치 생성 + 선택 stage 머지) → 충돌 프로브 → PR 초안 → push/PR**.
|
|
384
|
-
|
|
385
|
-
- 자격 판정의 SSOT 는 Stage Lifecycle Snapshot 입니다. Snapshot 은 `consumers.jsonl` 의 `verified`(어떤 stage 가 단독-stage final-verification 에서 accepted 됨), `pr`(어떤 stage 들이 어느 PR 로 나갔는지), done rows 를 읽어 `verified` 인데 아직 `pr` 에 안 들어간 stage 를 후보로 계산합니다.
|
|
386
|
-
- worktree registry 는 stage-group 점유를 `<task-key>#group-<id>` 키로 예약하고, 수집 브랜치 이름은 `<work-category-namespace>/<task-id-segment>-g2-3` (예: 선택한 stage 가 2·3 이면 `-g2-3`) 형태입니다.
|
|
387
|
-
- 강제 지점은 선언이 아니라 Python 모듈 `okstra_ctl.handoff` 입니다 (`okstra handoff <subcommand>`). 서브커맨드 4종: `eligible`(자격 stage 조회) / `assemble`(수집 브랜치 생성·머지) / `record-verified`(`verified` 행 기록) / `record-pr`(`pr` 행 기록). 수집 단계의 머지는 isolation spec 의 "okstra 자동 머지 없음" 비목표에 대한 명시적 예외입니다.
|
|
388
|
-
|
|
389
|
-
### improvement-discovery (sidetrack entry-point)
|
|
390
|
-
|
|
391
|
-
````
|
|
392
|
-
[brief: scope=codebase + priority-lenses]
|
|
393
|
-
↓ okstra-run --task-type improvement-discovery
|
|
394
|
-
[improvement-discovery]
|
|
395
|
-
↓ final-report (## 5.9 Improvement Candidates 후보 N개)
|
|
396
|
-
↓ (사용자가 후보 K개 선택, 각각 새 brief 작성)
|
|
397
|
-
[requirements-discovery | implementation-planning | error-analysis] (선택된 후보별로 새 task-id 로)
|
|
398
|
-
````
|
|
399
|
-
|
|
400
|
-
`PHASE_SEQUENCE` 의 정식 멤버에 들어가지 않는 sidetrack entry-point. 단방향 라이프사이클을 깨지 않으면서 코드베이스 발견 시나리오를 흡수한다. lens 화이트리스트와 candidate-cap 은 `scripts/okstra_ctl/improvement_lenses.py` SSOT 1개에서 통일된다. final-report 의 `## 5.9 Improvement Candidates` 표 (10 column) 는 `validators/validate_improvement_report.py` 의 11항목 contract 가 강제한다. 양방향 grilling 두 지점 (`okstra-brief-gen` Step 4 강화 budget 8 + lead 의 Phase 1.5 reflect-back budget 12) 으로 사용자와 AI 의 이해도를 일치시킨다.
|
|
401
|
-
|
|
402
|
-
### requirements-discovery fan-out
|
|
403
|
-
|
|
404
|
-
혼합/다항목 요청은 requirements-discovery 가 도메인(work-category 5-enum)별 packet 으로
|
|
405
|
-
분해해 `runs/requirements-discovery/fan-out/unit-*.md` 에 발행한다. 각 packet 은
|
|
406
|
-
`okstra-run --task-brief <경로>` 로 새 task-key 가 된다. 순서는 `index.md` 의 depends-on
|
|
407
|
-
위상정렬이 담고, task 화 이후의 통합 일정은 okstra-schedule 이 맡는다. okstra-brief-gen 는
|
|
408
|
-
이 경로에 개입하지 않는다. 검증: `validators/validate_fanout.py`(validate-run 훅).
|
|
409
|
-
|
|
410
|
-
### confirm 단계의 worktree 미리보기
|
|
411
|
-
|
|
412
|
-
okstra-run wizard 는 별도 분기 확인 단계를 두지 않고, 최종 `confirm` 직전 요약 블록
|
|
413
|
-
(`confirmation_block`)에 "새 브랜치/worktree 생성 vs 현재 worktree 재사용"을 `worktree` 한 줄로
|
|
414
|
-
보여준다. 결정은 `worktree.preview_worktree_decision()`(부수효과 없음)으로 미리보고, 같은 헬퍼를
|
|
415
|
-
`provision_task_worktree` 가 실행에 쓰므로 미리보기와 실제가 일치한다. `implementation` 은 stage
|
|
416
|
-
격리로 동작하므로 task-key 디렉터리가 아니라 이번 run 이 실제 쓸 stage worktree 관점으로
|
|
417
|
-
미리본다(`preview_stage_worktree_decision` / stage `auto` 는 `compute_worktree_path`).
|
|
418
|
-
`final-verification` 은 stage worktree 를 읽기 전용 재사용하므로 worktree 줄을 생략한다.
|
|
419
|
-
`confirm` 옵션은 `Proceed`/`Edit`/`중단` 3-옵션이다 — `Edit` 은 임의 step 으로 되감기(base-ref
|
|
420
|
-
재선택 포함), `중단` 은 터미널이다: state 가 `aborted` 로 고정되고 이후 `next_prompt` 는
|
|
421
|
-
`kind: "aborted"` 만 반환하며 `render-args` 는 `ok: false` 로 거부한다.
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
---
|
|
425
|
-
|
|
426
|
-
## Storage model & contracts
|
|
427
|
-
|
|
428
|
-
`okstra` 산출물의 3개 저장 영역(stable task root / per-run artifacts / `~/.okstra` 인덱스)과 task manifest · task index · run manifest · timeline · Claude operating 계약의 전체 스펙은 분리된 문서로 옮겼습니다 — [`architecture/storage-model.md`](architecture/storage-model.md).
|
|
429
|
-
|
|
430
|
-
## Task brief usage
|
|
431
|
-
|
|
432
|
-
`okstra`는 brief-first 구조입니다. brief 는 외부 입력과 okstra 보강을 보존하는 정본 source material 이며, 워커가 필요로 할 추가 자료(보고서, 코드 스니펫, 로그 등)는 brief 내부의 `Evidence and Source Materials` 섹션에 inline 또는 path 로 모두 포함시킵니다.
|
|
433
|
-
|
|
434
|
-
brief 의 **입력 시점은 entry phase 전용**입니다 — 사용자가 brief 경로를 직접 대는 것은 `requirements-discovery` / `error-analysis` / `improvement-discovery` 뿐이고, downstream phase(implementation-planning / implementation / final-verification)는 task manifest 의 `taskBriefPath` 를 자동 carry-in 합니다 (okstra-run wizard 가 묻지 않음; 미등록 시 entry 전환을 추천하는 fallback picker). `release-handoff` 는 brief 자체가 없으며 prepare 가 검증 보고서 인용 input 문서를 생성합니다.
|
|
435
|
-
|
|
436
|
-
brief 는 **translation layer** 입니다 — 외부 입력 (이슈 트래커 ticket, 요구사항 문서, 사용자 메시지) 을 okstra-readable 형식으로 옮기되, 원문은 verbatim 으로 보존하고 okstra 가 추가한 부분은 labelled augmentation 으로 명확히 구분합니다. `okstra-brief-gen` skill 의 산출이 source SSOT 이고, `prepare_task_bundle()` 은 분석 phase 마다 여기서 필요한 frontmatter, task-specific brief 섹션, reference expectations, carry-in clarification, directive 를 추출해 `instruction-set/analysis-packet.md` 를 만듭니다. 분석 워커의 1차 입력은 이 compact packet 이며, 원본 brief 와 profile/material 파일은 근거 확인이나 누락 보완이 필요할 때만 여는 fallback evidence 입니다.
|
|
437
|
-
|
|
438
|
-
brief에는 보통 아래를 포함합니다.
|
|
439
|
-
|
|
440
|
-
- 문제 설명
|
|
441
|
-
- 요구사항
|
|
442
|
-
- 기존 분석
|
|
443
|
-
- raw sample 또는 log
|
|
444
|
-
- 관련 코드 경로
|
|
445
|
-
- 제약사항
|
|
446
|
-
- worker에게 줄 질문
|
|
447
|
-
- 기대 출력
|
|
448
|
-
- 이전 run 또는 연관 task 정보
|
|
449
|
-
- (선택) glossary 추가 후보 — okstra-brief-gen Step 4.5 가 `<PROJECT_ROOT>/.okstra/glossary.md` 에 직접 기록
|
|
450
|
-
- (선택) decisions 후보 — `implementation-planning` phase 에서 평가 후 `.okstra/decisions/<NNNN>-<slug>.md` 로 승격
|
|
451
|
-
|
|
452
|
-
okstra-brief-gen 의 Step 6.5 는 **reporter batch confirmation** 입니다. brief 가 외부 입력을 옮기는 도중 의미 변화가 발생했는지를 사용자에게 일괄 확인받고 그 결과를 `Reporter Confirmations` 섹션에 기록합니다. 모든 분석 profile 은 이 섹션의 존재를 phase 분석 진입의 precondition 으로 강제합니다 (validator: `validators/validate-brief.py`).
|
|
453
|
-
|
|
454
|
-
기본 템플릿:
|
|
455
|
-
|
|
456
|
-
- `templates/reports/quick-input.template.md`
|
|
457
|
-
- `templates/reports/task-brief.template.md`
|
|
458
|
-
- `templates/reports/error-analysis-input.template.md`
|
|
459
|
-
- `templates/reports/implementation-planning-input.template.md`
|
|
460
|
-
- `templates/reports/implementation-input.template.md`
|
|
461
|
-
- `templates/reports/final-verification-input.template.md`
|
|
462
|
-
|
|
463
|
-
입력 템플릿에서는 최소한 아래 항목을 채우는 것을 권장합니다.
|
|
464
|
-
|
|
465
|
-
- `Project ID`
|
|
466
|
-
- `Task Group`
|
|
467
|
-
- `Task ID`
|
|
468
|
-
- `Related Tasks`
|
|
469
|
-
- `Task Type`
|
|
470
|
-
- `Requested Outcome`
|
|
471
|
-
|
|
472
|
-
## Recommended workflow
|
|
473
|
-
|
|
474
|
-
### 1. 초안 작성
|
|
475
|
-
|
|
476
|
-
빠르게 메모를 정리할 때는 `okstra-quick-input.template.md`를 사용합니다.
|
|
477
|
-
|
|
478
|
-
### 2. 정식 brief 작성
|
|
479
|
-
|
|
480
|
-
최종 입력은 `okstra-task-brief.md`로 정리합니다.
|
|
481
|
-
같은 task를 다시 이어갈 계획이면 같은 `task-group`과 `task-id`를 유지합니다.
|
|
482
|
-
|
|
483
|
-
### 2.5. 필요 시 요구사항 triage
|
|
484
|
-
|
|
485
|
-
요청이 버그 수정인지 신규 기능인지, 요구사항이 충분한지 먼저 분류해야 하면 같은 `okstra-task-brief.md`에 `Task Type: requirements-discovery`를 넣고 실행합니다.
|
|
486
|
-
이 단계는 이후 phase를 자동 실행하지 않고, work category와 다음 권장 phase를 task lifecycle metadata에 남기는 역할만 합니다.
|
|
487
|
-
|
|
488
|
-
```bash
|
|
489
|
-
scripts/okstra.sh --task-type requirements-discovery --project-id <project-id> --task-group <task-group> --task-id <task-id> --task-brief <brief-path>
|
|
490
|
-
```
|
|
491
|
-
|
|
492
|
-
### 3. Render-only 검증
|
|
493
|
-
|
|
494
|
-
```bash
|
|
495
|
-
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>
|
|
496
|
-
```
|
|
497
|
-
|
|
498
|
-
### 4. Claude 실행
|
|
499
|
-
|
|
500
|
-
두 가지 진입 방식이 있으며 산출물은 동일합니다.
|
|
501
|
-
|
|
502
|
-
**Option A — 새 claude 프로세스를 띄움 (`okstra.sh`)**
|
|
503
|
-
|
|
504
|
-
```bash
|
|
505
|
-
scripts/okstra.sh --task-type error-analysis --project-id <project-id> --task-group <task-group> --task-id <task-id> --task-brief <brief-path>
|
|
506
|
-
```
|
|
507
|
-
|
|
508
|
-
이 경로로 실행하면 `okstra.sh` 가 prepare 단계를 마친 뒤 대상 프로젝트 루트에서 새 Claude interactive session 을 `exec` 합니다. handoff 까지만 수행하고 최종 보고서 저장은 Claude lead 가 이어서 수행합니다. 실행 직전에 `sessions/claude-resume-<task-type>-<seq>.sh` 가 미리 작성되므로 세션이 중간에 끊겨도 같은 run 을 재개할 수 있습니다.
|
|
509
|
-
|
|
510
|
-
**Option B — 현재 claude 세션 안에서 인계 (`okstra-run` skill)**
|
|
511
|
-
|
|
512
|
-
이미 Claude Code 세션을 사용 중이라면 새 프로세스를 띄우지 않고 같은 세션이 그대로 Claude lead 로 인계받게 할 수 있습니다. trigger 예: `"run okstra here"`, `"start error-analysis on this project"`.
|
|
513
|
-
|
|
514
|
-
skill 흐름:
|
|
515
|
-
|
|
516
|
-
1. `okstra-run` skill 이 활성화되고 `AskUserQuestion` 으로 task 후보 / task-type / brief 경로를 받습니다.
|
|
517
|
-
2. 사용자의 입력으로 `okstra_ctl.run.prepare_task_bundle(render_only=True)` 를 호출합니다 — `okstra.sh` 를 거치지 않고 같은 python 함수를 직접 호출합니다.
|
|
518
|
-
3. 같은 instruction-set 산출물이 디스크에 만들어지면 현재 claude 가 그 prompt 를 읽어 lead 역할로 진입합니다.
|
|
519
|
-
|
|
520
|
-
자세한 절차는 [`skills/okstra-run/SKILL.md`](../../skills/okstra-run/SKILL.md) 참조.
|
|
521
|
-
|
|
522
|
-
### 5. 필요 시 에러 분석
|
|
523
|
-
|
|
524
|
-
```bash
|
|
525
|
-
scripts/okstra.sh --task-type error-analysis --project-id <project-id> --task-group <task-group> --task-id <task-id> --task-brief <brief-path>
|
|
526
|
-
```
|
|
527
|
-
|
|
528
|
-
첫 진입 이후 같은 task에 추가 run이 필요하면 단축 형식 사용:
|
|
529
|
-
|
|
530
|
-
```bash
|
|
531
|
-
scripts/okstra.sh --task-key <project-id>:<task-group>:<task-id> --task-type error-analysis
|
|
532
|
-
```
|
|
533
|
-
|
|
534
|
-
### 5.5. 답변 후 즉시 재실행
|
|
535
|
-
|
|
536
|
-
`requirements-discovery` 또는 `error-analysis` final report의 Section 5에 답변을 채워야 한다면, 경로를 손으로 들고 다닐 필요 없이 한 번에 처리합니다.
|
|
537
|
-
|
|
538
|
-
```bash
|
|
539
|
-
scripts/okstra.sh --resume-clarification --task-key <project-id>:<task-group>:<task-id>
|
|
540
|
-
```
|
|
541
|
-
|
|
542
|
-
`$EDITOR`로 최신 final report가 열리고, 저장 후 같은 phase가 자동으로 `--clarification-response` carry-in 으로 재실행됩니다.
|
|
543
|
-
|
|
544
|
-
#### Incremental re-verification (implementation-planning 재실행 한정)
|
|
545
|
-
|
|
546
|
-
`implementation-planning` clarification 재실행은 기본이 **full 재검증**입니다. 다만 답변의 파급이 국소적이고 코드가 그대로라면, lead 가 영향 stage 의 하류 폐포만 재검증하고 나머지 stage 의 plan-item verdict 는 직전 run 에서 carry-forward 합니다. 판정은 결정적 CLI 와 lead 재량으로 나뉩니다.
|
|
547
|
-
|
|
548
|
-
- **C1 (CLI 판정, 결정적)**: 직전 run 의 `state/active-run-context-implementation-planning-<prev-seq>.json` 의 `executorWorktree.baseRef` 와 이번 run 의 base-ref SHA 가 같아야 합니다. 다르면 코드가 바뀐 것이므로 즉시 `full`.
|
|
549
|
-
- **C2 (lead 재량)**: 답변이 건드리는 Stage Map stage 번호 집합. Stage Map 에 없는 번호는 절대 넣지 않고, 매핑에 확신이 없거나 답변이 선택 Option/접근법을 뒤집으면 **빈 집합**을 넘겨 `full` 로 폴백합니다.
|
|
550
|
-
- **폐포 컷오프**: `okstra incremental-scope` 가 `implementationPlanning.stageMap` 의 의존성 그래프에서 영향 stage 의 `downstream_stage_closure` 를 구하고, 그 크기가 전체 stage 의 **과반을 넘으면** `full`. 그 외에는 `{mode, reverify_stages, carry_stages, reason}` JSON 을 출력합니다.
|
|
551
|
-
|
|
552
|
-
```bash
|
|
553
|
-
okstra incremental-scope --prev-data <prev data.json> --cur-base-sha <sha> --prev-base-sha <sha> --impacted 2,3
|
|
554
|
-
okstra incremental-carry --prev-data <prev data.json> --cur-data <cur data.json> --prev-seq <prev-seq> --out <cur data.json>
|
|
555
|
-
```
|
|
556
|
-
|
|
557
|
-
`mode == "incremental"` 이면 worker dispatch 는 `reverify_stages` 로만 범위가 좁혀지고(`prompts/profiles/implementation-planning.md` 의 *Cross-verification mode*), 워커는 `carry_stages` 를 재개봉·재판정하지 않습니다. 재실행이 끝나면 `okstra incremental-carry` 가 직전 run 의 plan-item verdict 중 이번 run 에 없는 항목을 `carriedForwardFromSeq` 태그와 함께 병합합니다. 두 run 의 `schemaVersion` 이 다르면 `CarryError` 로 비영 종료하고 full 로 폴백합니다. 재검증 stage 에서 plan item 이 **삭제**돼야 한다는 결론이 나오면 파급이 국소적이지 않다는 신호이므로 역시 full 로 재실행합니다. `verdictCard` / `finalVerdict` 는 절대 carry 되지 않고 매 run 재계산합니다.
|
|
558
|
-
|
|
559
|
-
판정 결과는 report-writer 가 data.json 의 `implementationPlanning.incrementalDecision` 에 그대로 기록하고, 렌더러가 `### 0.1 Incremental Re-Verification Scope` 감사 블록으로 노출합니다. 절차 원문은 `prompts/launch.template.md` §"Incremental re-verification" 입니다.
|
|
560
|
-
|
|
561
|
-
### 6. 필요 시 구현 계획 검토
|
|
562
|
-
|
|
563
|
-
```bash
|
|
564
|
-
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>
|
|
565
|
-
```
|
|
566
|
-
|
|
567
|
-
후속 phase 단축 형식 (manifest의 `workflow.nextRecommendedPhase`가 `implementation-planning`이면 `--task-type` 도 생략 가능):
|
|
568
|
-
|
|
569
|
-
```bash
|
|
570
|
-
scripts/okstra.sh --task-key <project-id>:<task-group>:<task-id> --workers claude,codex
|
|
571
|
-
```
|
|
572
|
-
|
|
573
|
-
### 7. 승인된 plan 기반 구현
|
|
574
|
-
|
|
575
|
-
`implementation-planning` final report 의 YAML frontmatter `approved` field 가 `true` 일 때에만 실행합니다. 승인된 plan 경로를 `--approved-plan`으로 carry-in해야 하며, plan 이 없거나 frontmatter `approved: true` 가 아니면 run 은 `contract-violated` 로 거부됩니다.
|
|
576
|
-
|
|
577
|
-
승인 형식 (코드 진실: `scripts/okstra_ctl/run.py` 의 `APPROVED_FRONTMATTER_PATTERN`):
|
|
578
|
-
|
|
579
|
-
- final-report 의 leading `---` YAML 펜스 안에 정확히 한 줄: `approved: true` 또는 `approved: false`
|
|
580
|
-
- 대소문자 무관. report-writer 는 항상 `approved: false` 로 발행하고, 사용자가 `true` 로 toggle 하면 implementation 진입 가능
|
|
581
|
-
|
|
582
|
-
승인 라인을 직접 편집하지 않고 CLI 호출 자체를 승인 행위로 처리하려면 `--approve` 플래그를 함께 줍니다. okstra 는 `--approved-plan` 파일의 frontmatter `approved` 를 `true` 로 toggle 하고 audit 라인을 append 한 뒤 implementation phase 를 이어 실행합니다 (이전 `--ack-approved` alias 는 0.8.0 에서 제거됨). 자세한 동작은 [`docs/kr/cli.md`](cli.md#--approve) 참고.
|
|
583
|
-
|
|
584
|
-
```bash
|
|
585
|
-
scripts/okstra.sh --task-type implementation --workers claude,codex,antigravity --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>
|
|
586
|
-
```
|
|
587
|
-
|
|
588
|
-
단축 형식:
|
|
589
|
-
|
|
590
|
-
```bash
|
|
591
|
-
scripts/okstra.sh --task-key <project-id>:<task-group>:<task-id> --task-type implementation --workers claude,codex,antigravity --approved-plan <runs/implementation-planning/.../reports/final-report.md>
|
|
592
|
-
```
|
|
593
|
-
|
|
594
|
-
### 8. 구현 후 최종 검토
|
|
595
|
-
|
|
596
|
-
```bash
|
|
597
|
-
scripts/okstra.sh --task-type final-verification --project-id <project-id> --task-group <task-group> --task-id <task-id> --task-brief <brief-path>
|
|
598
|
-
```
|
|
599
|
-
|
|
600
|
-
단축 형식:
|
|
601
|
-
|
|
602
|
-
```bash
|
|
603
|
-
scripts/okstra.sh --task-key <project-id>:<task-group>:<task-id> --task-type final-verification
|
|
604
|
-
```
|
|
605
|
-
|
|
606
|
-
### 9. 같은 task 재개
|
|
607
|
-
|
|
608
|
-
같은 bugfix나 same workstream을 다시 열면 기존과 같은 `task-group`과 `task-id`를 사용합니다.
|
|
609
|
-
그러면 기존 task root 아래 `runs/`와 `history/timeline.json`에 이력이 계속 누적됩니다.
|
|
610
|
-
첫 진입 이후에는 `--task-key <p>:<g>:<i>` 단축 형식이 가장 간결하며, 누락된 brief/task-type은 manifest에서 자동 채워집니다.
|
|
611
|
-
|
|
612
|
-
## Lifecycle status and resume
|
|
613
|
-
|
|
614
|
-
장기 작업에서는 `task-manifest.json`의 `workflow`가 canonical lifecycle 상태입니다.
|
|
615
|
-
특히 아래 항목을 먼저 확인하면 현재 위치와 재개 지점을 빠르게 판단할 수 있습니다.
|
|
616
|
-
|
|
617
|
-
- `workflow.currentPhase`
|
|
618
|
-
- `workflow.currentPhaseState`
|
|
619
|
-
- `workflow.phaseStates`
|
|
620
|
-
- `workflow.lastCompletedPhase`
|
|
621
|
-
- `workflow.nextRecommendedPhase`
|
|
622
|
-
- `workflow.awaitingApproval`
|
|
623
|
-
- `workflow.routingStatus`
|
|
624
|
-
- `workflow.lastSafeCheckpoint`
|
|
625
|
-
- `phaseOutcome`
|
|
626
|
-
|
|
627
|
-
프로젝트 전체 상태를 훑을 때는 `.okstra/discovery/task-catalog.json`을 사용합니다.
|
|
628
|
-
특정 task의 최신 상태를 볼 때는 `.okstra/discovery/latest-task.json`, `task-manifest.json`, 최신 `run-manifest`, `history/timeline.json` 순서로 확인합니다.
|
|
629
|
-
|
|
630
|
-
Claude에서는 seeded `okstra-inspect` skill의 `status` 하위 흐름을 사용해 아래 질문을 직접 처리할 수 있습니다.
|
|
631
|
-
|
|
632
|
-
- 전체 okstra task status 보여줘
|
|
633
|
-
- 특정 `task-key`의 current phase와 next phase 알려줘
|
|
634
|
-
- approval 대기 중인 task와 resume 가능한 task를 보여줘
|
|
635
|
-
- `<task-id>`의 `workStatus`를 `todo` / `in-progress` / `blocked` / `done`으로 업데이트해줘 (예: "okstra mark <task-id> done", "<task-id> 진행중") — skill이 해당 `task-manifest.json`의 `workStatus`, `workStatusUpdatedAt`, `workStatusNote`를 갱신합니다.
|
|
636
|
-
|
|
637
|
-
resume 판단 기준:
|
|
638
|
-
|
|
639
|
-
- 현재 run 재개: `latestResumeCommandPath`가 있으면 그 경로를 우선 사용합니다.
|
|
640
|
-
- 현재 phase 재시작: 같은 `task-key`와 현재 `task-type`으로 다시 실행합니다.
|
|
641
|
-
- 다음 phase 시작: `workflow.nextRecommendedPhase`가 구체적인 phase면 그 값으로 다음 `okstra.sh` 실행을 준비합니다.
|
|
642
|
-
- 추가 자료 필요: `routingStatus=pending` 또는 `nextRecommendedPhase=pending-routing-decision`이면 brief 보강이 먼저입니다.
|
|
643
|
-
|
|
644
|
-
## Final report structure
|
|
645
|
-
|
|
646
|
-
기본 최종 보고서 템플릿은 `templates/reports/final-report.template.md`입니다.
|
|
647
|
-
Claude가 작성하는 최종 보고서는 아래 구조를 우선 사용합니다 (brief 의 augmentation 이 더 구체적인 형식을 요구할 때만 그것을 따릅니다).
|
|
648
|
-
|
|
649
|
-
- `## Verdict Card` — **최상단 의무 섹션**. Final Conclusion / Verdict Token / Direction / Approval Required? / Next Step 5 행. Verdict Token / Direction / Next Step 셀은 본문 §2 (실행 현황) 와 §6 (다음 단계) 의 권위 셀과 byte-match 해야 합니다.
|
|
650
|
-
- (선택) `## Reader Summary` — data.json 의 `readerSummary` 가 있을 때만 Verdict Card 바로 아래 렌더되는 5행 표: 결정(`decision`) / 사람이 해야 할 행동(`humanActionRequired`) / 차단 항목(`blockingItems`) / 건너뛰어도 되는 것(`safeToSkip`) / 추천 명령(`recommendedCommand`). 존재하면 5개 필드 전부 필수이며 (schema `required`), raw evidence table 을 반복하지 않고 요약만 담습니다. 없는 과거 data.json 도 그대로 렌더됩니다.
|
|
651
|
-
- `## 작업 배경과 근거` — **모든 task-type 의무 섹션** (data.json `rationale`). 검토자용 서술로 네 질문에 순서대로 답합니다: 왜 이 작업을 하는가(`motivation`) / 왜 이게 문제인가(`problem`) / 그래서 어떤 작업이 필요한가(`approach`) / 왜 이게 합리적 선택인가(`justification`). 표가 아니라 프로즈이며, 각 필드는 `path:line` · 보고서 ID(`C-001`) · `§5.4` 같은 증거 참조나 명시적 불충분 표시(`근거 불충분`) 중 하나를 반드시 포함해야 합니다 — `validators/validate-run.py` 의 `_validate_rationale_evidence` 가 둘 다 없는 필드를 fail 합니다.
|
|
652
|
-
- (선택) `## 0. Clarification Response Carried In From Previous Run` — 직전 run 에서 응답이 carry-in 된 경우에만 렌더링. 빈 carry-in 일 때는 헤딩 자체를 출력하지 않습니다.
|
|
653
|
-
- (선택) `### 0.1 Incremental Re-Verification Scope` — data.json 의 `implementationPlanning.incrementalDecision` 이 있을 때만 렌더링. `mode == "incremental"` 이면 `Re-verified stages` / `Carried-forward stages` 두 행이 반드시 포함되며, `validators/validate-run.py` 가 누락을 `contract-violated` 로 차단합니다. carry 된 plan item 은 `carriedForwardFromSeq` 태그로 어느 run 에서 검증됐는지 남깁니다.
|
|
654
|
-
- `## 1. 문제 또는 검증 대상 요약` — §6.1 Consensus / §6.2 Differences 표 각각 `Source items (worker:item)` 컬럼 보존 (cross-worker traceability).
|
|
655
|
-
- `## 2. 에이전트별 실행 현황`
|
|
656
|
-
- `## 3. Cross Verification 결과` — §2.1 Primary Evidence 에 `Source items (worker:item)` + `Source (path:line / log)` 컬럼.
|
|
657
|
-
- `## 4. 최종 판단` — `implementation-planning` 의 §5.5.9 Plan Body Verification 은 plan item 별로 그룹핑해 emit: 각 항목의 `subject`(무엇을 검증했는지 한 줄) 를 헤딩으로, 그 아래 워커별 `Worker / Verdict / Breakage kind / Note` 표를 붙이고, gate 값·verdict 토큰·breakage kind(a–f) 범례 3종을 함께 렌더한다.
|
|
658
|
-
- `## 1. Clarification Items` — 통합 8-열 표 한 곳. 기존 §6.1 / §6.2 / §5.5.8 / §5.5.9 Open Questions 는 deprecated 되어 validator 가 등장 시 fail.
|
|
659
|
-
- `## 6. 권장 다음 단계`
|
|
660
|
-
- `## Token Usage Summary` — sentinel (`pending` / `N/A` / `--` / `?` / 빈 셀) 또는 zero (`0` / `$0.00`) 박제 시 validator 가 출고를 차단합니다. `Codex/Antigravity CLI 추가 비용` 행만 "CLI 미사용" 의미로 `$0.00` 허용.
|
|
661
|
-
|
|
662
|
-
워커 출력의 `## 0. Reading Confirmation` 블록은 본문에 두지 않고 `runs/<task-type>/worker-results/<worker>-audit-<task-type>-<seq>.md` 사이드카에 작성합니다 (validator 강제).
|
|
663
|
-
|
|
664
|
-
차이점이 실질적으로 없으면 억지로 대비를 만들지 말고, 차이가 없음을 명시합니다.
|
|
665
|
-
저장 실패나 세션 제한에 대한 메타 설명 대신 실제 Markdown 보고서 본문을 파일에 작성해야 합니다.
|
|
666
|
-
|
|
667
|
-
## Final report views (HTML)
|
|
668
|
-
|
|
669
|
-
Phase 7 step 1.5 가 final-report MD 한 본을 입력으로 self-contained HTML view 를 결정론적으로 자동 생성합니다.
|
|
670
|
-
|
|
671
|
-
- `reports/final-report-<task-type>-<seq>.html` — 사람 reviewer 용 self-contained HTML. CSS / JS 인라인 임베드 (외부 URL 0), system color 다크모드, sticky header, 인쇄 대응. §1 `C-*` 행의 의사결정 입력 (체크박스 / 셀렉트 / textarea) 을 화면에서 채우고 `Export user response` 버튼으로 사이드카 markdown 을 생성합니다.
|
|
672
|
-
- **Reader Summary dashboard + reader mode**: 최상단에 `readerSummary`(없으면 `verdictCard` fallback) 기반 dashboard 를 렌더하고, `Action` / `Audit` / `Full` 세 reader mode 토글을 제공합니다. 기본은 `Action` — Reader Summary / Verdict Card / Clarification Items / Recommended Next Steps / Follow-up Tasks 만 보이고, Evidence · Cross Verification · Execution Status · Token Usage · Plan Body Verification · Round History 같은 감사용 섹션은 `Audit` / `Full` 에서 펼칩니다.
|
|
673
|
-
- **`C-*` 셀렉트 옵션 순서**: `Expected form` 의 `Recommended:` 답이 항상 **첫 옵션**으로 렌더되고, 이어지는 `Alternatives:` 항목이 `(a)`, `(b)`, ... 순으로 연속 재부여됩니다 (원본 문자 라벨을 그대로 쓰지 않음).
|
|
674
|
-
|
|
675
|
-
진입점:
|
|
676
|
-
|
|
677
|
-
- Python 단일 reference: `scripts/okstra_ctl/report_views.py` (`build_report_view_model(...)`, `render_report_view_model(..., css, js)`, `render_html(..., css, js)`, `serialize_user_response(...)`). HTML 내 JS `buildUserResponseMarkdown` 은 Python `serialize_user_response` 와 **byte-identical** (Node `vm.runInThisContext` 단위 테스트로 자동 검증).
|
|
678
|
-
- CLI: `scripts/okstra-render-report-views.py <final-report.md>` 또는 Node 위임 wrapper `bin/okstra render-views <md>`.
|
|
679
|
-
- 검증: `validators/validate-report-views.py` — HTML 내 form control 위치, 외부 URL 부재, stale source digest, Response ID parity (`C-*` ↔ HTML) 를 검사.
|
|
680
|
-
- 사용자 응답 사이드카 스키마 SSOT: `templates/reports/user-response.template.md`.
|
|
681
|
-
|
|
682
|
-
원본 final-report MD 는 어떤 경우에도 view 생성으로 인해 수정되지 않습니다.
|
|
683
|
-
|
|
684
|
-
## Worker error collection (optional sidecar)
|
|
685
|
-
|
|
686
|
-
워커(Claude/Codex/Antigravity worker, Report writer, Claude lead) 실행 중 발생한 에러를 단일 시계열 로그로 수집해 사후 회고에 사용할 수 있습니다.
|
|
687
|
-
|
|
688
|
-
- 저장 위치: `runs/<task-type>/logs/errors-<task-type>-<seq>.jsonl`
|
|
689
|
-
- append-only JSON Lines, run 단위 격리이므로 별도 회전 정책은 두지 않습니다.
|
|
690
|
-
- **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 필드입니다.
|
|
691
|
-
- 워커 내부 도구 실패는 워커 결과 매니페스트의 `errors[]`에 보고 → lead가 merge 직후 dump
|
|
692
|
-
- Codex/Antigravity CLI 실패·타임아웃·rate-limit는 lead가 wrapper에서 직접 관찰
|
|
693
|
-
- resultContract 위반·스키마 mismatch·필수 필드 누락은 lead 검증 단계에서 직접 관찰
|
|
694
|
-
- `source` 필드(`worker-reported` | `lead-observed`)와 `errorType`(`tool-failure` | `cli-failure` | `contract-violation`)으로 발생원과 종류를 구분합니다.
|
|
695
|
-
- `stderrExcerpt`는 한 줄 jsonl 가독성을 위해 2KB 상한, `PIPE_BUF`(4096B) atomic append 가드를 강제합니다.
|
|
696
|
-
- run-manifest 또는 team-state의 `errorsLogPath` 필드에 `logs/errors-<task-type>-<seq>.jsonl` 경로를 1회 기록해 발견 가능하게 합니다.
|
|
697
|
-
- Path delivery 와이어링 (`f6f9f69`): `scripts/okstra_ctl/paths.py` 가 `RUN_ERRORS_LOG_FILE` / `RUN_ERRORS_LOG_RELATIVE_PATH` 와 worker 별 sidecar 경로를 export 하고, `scripts/okstra_ctl/render.py` 가 `{{RUN_ERRORS_LOG_PATH}}` / `{{<WORKER>_ERRORS_SIDECAR_PATH}}` 템플릿 토큰을 노출합니다. `prompts/launch.template.md` 의 `## Run Logs (error-log wiring)` 섹션이 resolved absolute path 를 lead 에 전달하고, lead 는 이를 worker dispatch prompt 의 `**Errors log path:**` / `**Errors sidecar path:**` 라인으로 forward 해야 합니다 — literal `<runDir>/logs/...` template fragment 만 들고 있을 때 worker 가 argparse-exit 으로 entry 를 흘리는 회귀가 있어 path delivery 가 정식 contract 화 됐습니다.
|
|
698
|
-
- Helper CLI: `scripts/okstra-error-log.py`
|
|
699
|
-
- 단일 진입점으로 record를 append 합니다.
|
|
700
|
-
- 워커 sidecar dump(`append_observed`, schema version 가드)와 lead 관찰(`lead-observed`) 모두 동일 helper를 사용합니다.
|
|
701
|
-
|
|
702
|
-
### Live-log mirror (codex / antigravity wrapper)
|
|
703
|
-
|
|
704
|
-
- `scripts/okstra-codex-exec.sh`, `scripts/okstra-antigravity-exec.sh` 는 dispatch 마다 prompt path 옆에 `<prompt>.log` sidecar 를 만들고 stdout 을 거기로 mirror 합니다 (`tee`, `PIPESTATUS[0]` 로 종료코드 보존). stderr 은 같은 파일에 append (subagent stderr 캡처 contract 보존), 매 dispatch 시 truncate. 호출 subagent 의 `BashOutput` 폴링은 60s 간격이라 long-running run (analysis 의 large-codebase scan, implementation 의 cargo / pytest) 동안 사용자가 stalled state 를 탐지할 수 없는 문제를 해소합니다.
|
|
705
|
-
- tmux 가 reachable 한 lead 환경이면 wrapper 가 sibling pane 을 자동 분할해 `tail -F <log-path>` 를 띄웁니다. trace pane title 은 caller (worker) pane title 에 `-tail` 을 붙인 `<cli>-<role>-<pid>-tail` (e.g. `codex-worker-93421-tail`); 동일 시점에 caller (worker) pane title 은 `<cli>-<role>-<pid>` 로 셋팅됩니다. `<pid>` 는 wrapper 자기 자신의 PID 라서 동일 role 의 worker 가 둘 이상 동시에 spawn 돼도 서로 구분되고, 운영자는 `<caller> ↔ <caller>-tail` 로 시각적으로 매핑할 수 있습니다. **caller pane 해석** — Claude Code Bash tool 은 이제 `$TMUX` 와 `$TMUX_PANE` 를 둘 다 환경에서 제거하므로 env 변수에 의존하지 않습니다. wrapper 는 (1) prompt path 로부터 `<RUN_DIR>` (= `dirname(dirname(prompt_path))`, paths.py SSOT) 를 도출하고, (2) lead 가 자기 foreground pane 에서 1회 기록한 `<RUN_DIR>/state/lead-pane.id` 를 읽어 split anchor 로 씁니다 (background dispatch 에서도 신뢰 가능 — active-pane 추정과 달리 사용자가 pane 을 옮겨도 안전). 기록 파일이 없거나 pane 이 stale 이면 `tmux display-message -p '#{pane_id}'` (active pane) 으로 fallback. trace pane split 은 그 caller pane 을 `-t` 로 명시 anchor 합니다. role 은 wrapper 의 5번째 optional positional 인자이며, 누락 시 기본값 `worker`. caller pane title 은 capture 해두고 EXIT trap 에서 복원하므로 dispatch 사이의 stale title 이 남지 않습니다. focus 는 caller pane 으로 복귀하고, CLI 종료 후 pane 은 유지돼 스크롤백 가능. tmux 미reachable, split 실패, 구버전 tmux 등 모든 경로는 silent degrade.
|
|
706
|
-
- **run-scoped 태깅으로 정리**: trace pane 의 `tail -F` 는 tmux 셸의 자식이라 Claude 가 종료돼도 살아남습니다. wrapper 는 spawn 한 pane 을 `tmux set-option -p @okstra_trace_run=<RUN_DIR>` 로 태깅하고, `okstra-trace-cleanup.sh` 는 `tmux list-panes -a` 에서 그 태그로 pane 을 server-wide 발견해 `tmux kill-pane` 합니다. tmux env 변수·pane-id registry 없이 동작하며, run-scoped 태그라 동시에 도는 다른 okstra run 의 trace pane 을 죽이지 않습니다. cleanup 은 두 진입 형태를 가집니다 — lead 가 `--run-dir <RUN_DIR>` 로 호출(해당 run 의 trace + worker-agent pane 정리)하거나, `templates/reports/settings.template.json` 의 `hooks.SessionEnd` 가 `--reap` 로 호출(`$CLAUDE_PROJECT_DIR/.okstra/` 하위 태그를 가진 trace pane 일괄 정리; 단일 run-dir 이 없는 종료 시점용). tmux 가 없거나 stale pane id 인 경우 silent degrade.
|
|
707
|
-
- **phase 전환 시 자동 정리 + worker-agent pane 포함**: `okstra-trace-cleanup.sh --run-dir <RUN_DIR>` 는 태깅된 trace pane 뿐 아니라 dispatch 된 서브에이전트가 점유하는 worker-agent pane(title `claude-worker` / `codex-worker` / `antigravity-worker` / `report-writer-worker`)도 lead 세션(`tmux list-panes -s -t <lead-pane>`) 범위에서 title allowlist 로 식별해 닫습니다(worker-agent pane 은 harness 소유라 태깅 불가). implementation role title(`claude-executor` / `codex-verifier` / `agy-executor-tail` 등)과 FleetView teammate prefix(`✳ ` / `⠂ `)도 같은 okstra pane 으로 취급합니다. 세션 scope 와 lead 자기 pane 제외는 `<RUN_DIR>/state/lead-pane.id` 로 결정되며, lead 자신의 pane 은 title 이 걸려도 절대 죽이지 않습니다. lead 는 새 phase 의 worker 를 dispatch 하기 직전(`PROGRESS: phase-5.5-convergence` / `phase-6-synthesis` 마커 직전) 이 스크립트를 `--run-dir` 로 호출해 이전 phase 의 pane 을 prompt 없이 정리합니다.
|
|
708
|
-
- **Phase 종료 시 사용자 확인**: run 최종 종료 시점(마지막 단계)에 lead 가 `okstra-trace-cleanup.sh --list --run-dir <RUN_DIR>` 로 잔여 okstra pane(worker-agent + trace) 목록을 출력한 뒤 사용자에게 "모두 닫고 팀원 정리 / 그대로 두기" 양자택일을 한 번만 묻고 응답대로 처리합니다 (`prompts/profiles/_common-contract.md` 의 *Phase wrap-up* 항목). 승인 시 lead 는 pane cleanup 을 실행한 뒤, split-pane run 이면 `okstra-team-reconcile.sh` 로 dead-pane 멤버를 inactive 로 정리하고 각 완료 teammate 에 `SendMessage` shutdown_request 를 보냅니다(`TeamDelete` 는 v2.1.178 에서 제거 — implicit team 은 세션 종료와 함께 사라짐). lead 는 이 pane 단계를 `lead-pane.id` 를 직접 해석해 게이트하지 않고 **항상** 스크립트를 호출하며, tmux 밖이면 스크립트가 빈 pane 목록으로 안전하게 no-op 합니다. teammate 단계는 `teamCreate.status` 가 아니라 on-disk team config(`~/.claude/teams/session-*/config.json` 의 `leadSessionId` 매칭) 존재로 판단합니다. `--list` 모드는 pane 을 죽이지 않고 `<pane_id>\t<pane_title>` 만 출력하므로 사용자가 무엇이 닫힐지 시각적으로 확인할 수 있습니다.
|
|
709
|
-
- 디스크 누적은 `okstra-inspect logs` 흐름이 read-only 로 인벤토리 + cleanup 명령을 제안합니다 (실행은 사용자 copy-paste).
|
|
710
|
-
|
|
711
|
-
### Linked-worktree `.git/` write 권한 (codex / antigravity)
|
|
712
|
-
|
|
713
|
-
- `--executor codex|antigravity` 의 worktree 안에서 `git add` / `git commit` 은 main repo 의 per-worktree metadata (`<main-repo>/.git/worktrees/<name>/index`, refs, HEAD) 와 shared object DB (`<main-repo>/.git/objects/`) 에 써야 하지만, 이 경로는 worktree directory 밖이라 단순히 worktree path 만 sandbox 에 열어주면 index.lock 생성 시 EPERM 으로 실패합니다 (executor 가 step commit contract 를 만족하지 못해 edit 을 revert 하고 종료).
|
|
714
|
-
- wrapper 가 worktree 안에서 `git -C <worktree> rev-parse --git-common-dir` 로 main repo `.git/` 절대경로를 해석하고 `--add-dir <main-repo>/.git` (codex) 또는 `--include-directories <main-repo>/.git` append (antigravity) 로 sandbox 에 함께 forward 합니다.
|
|
715
|
-
|
|
716
|
-
## Token usage and cost accounting
|
|
717
|
-
|
|
718
|
-
각 run에 사용된 토큰을 lead/worker 세션 트랜스크립트에서 수집해 `team-state.json`의 `leadUsage` / `workers[].usage`에 다시 기록합니다.
|
|
719
|
-
|
|
720
|
-
- Helper CLI: `scripts/okstra-token-usage.py`
|
|
721
|
-
- 수집 소스:
|
|
722
|
-
- Claude lead/workers: `~/.claude/projects/<cwd-as-dashes>/<sessionId>.jsonl` 또는 `~/.claude/projects/<cwd-as-dashes>/<lead-session>/subagents/agent-a<worker-name>-<hash>.jsonl` 의 per-message `message.usage`. nested subagent 파일은 파일명에서 worker name 을 복원하고, 현재 run 의 `team-state.lead.sessionId` 디렉터리 아래만 집계합니다.
|
|
723
|
-
- Codex CLI: `~/.agent/sessions/Y/M/D/rollout-*.jsonl`의 마지막 `total_token_usage.total_tokens`
|
|
724
|
-
- Antigravity CLI: `~/.antigravity/tmp/*/chats/session-*.json`의 per-message `tokens.total`
|
|
725
|
-
- billable-equivalent token math와 USD cost estimation을 함께 기록합니다. Anthropic billing ratio(`cache_creation_5m=1.25x`, `cache_creation_1h=2.0x`, `cache_read=0.1x`, `output=5x`)를 반영합니다. transcript 의 `usage.cache_creation.ephemeral_5m_input_tokens` / `ephemeral_1h_input_tokens` 분해가 있으면 분리 집계합니다.
|
|
726
|
-
- 가격표는 `scripts/okstra_token_usage/pricing.py` 에서 중앙 관리합니다. 모델 가격이 바뀌면 거기서 갱신합니다. 가격 매칭에 실패한 모델 id 는 `usageSummary.unmatchedModels` 필드로 사용자에게 노출됩니다 (silent zero 사고 방지).
|
|
727
|
-
- **증분 스캔 캐시 (P6)**: 세션 jsonl 재스캔을 피하기 위해 `$OKSTRA_HOME/cache/token-usage/<transcript-dir>/<sessionId>.json` 에 파일별 byte cursor + 윈도우 적용 전 usage 이벤트 추출본을 보존합니다 (`scripts/okstra_token_usage/cursor.py`). run 윈도우(since/until)는 매 호출 시 이벤트 위에서 재평가하므로 재실행으로 윈도우가 좁아져도 합계는 전체 스캔과 동일합니다. 캐시는 파생 데이터라 식별자 불일치·truncate·손상 시 자동으로 전체 재스캔으로 폴백하며, `okstra-token-usage.py --no-cache` 로 강제 우회할 수 있습니다.
|
|
728
|
-
- **단계 타임라인 (P0 계측)**: 수집기가 lead 세션 jsonl 의 `PROGRESS: phase-*` 체크포인트 라인(prompts/lead/okstra-lead-contract.md "Progress reporting")을 run 윈도우로 스코핑해 추출하고, team-state 에 `phaseTimeline` 블록(`{source, phases: [{phase, firstAt, lastAt, markerCount, wallMsToNext}]}`)으로 기록합니다 (`scripts/okstra_token_usage/collect.py :: phase_timeline`). run 내부 단계별 wall-clock 의 측정 지점이며, `okstra-inspect` time facet 의 "Per-run phase breakdown" 이 소비합니다. 마커가 없는 run 은 `phases: []` 로 측정 불가를 명시합니다.
|
|
729
|
-
|
|
730
|
-
## Validators
|
|
731
|
-
|
|
732
|
-
phase 산출물의 출고 가능 여부를 강제하는 진입점:
|
|
733
|
-
|
|
734
|
-
- `validators/validate-workflow.sh` — phase contract 통합 검증.
|
|
735
|
-
- `validators/validate-run.py` — run-level final-report 본문 contract (Verdict Card 존재, `rationale` 4개 필드의 증거-앵커 강제(`_validate_rationale_evidence`), deprecated §6.1/§6.2/§5.5.8/§5.5.9 Open Questions 부재, Plan Body Verification gate × Approval 마커 cross-check, Token Usage sentinel/zero 차단, 워커-결과 audit 사이드카 존재, 증분 재검증 감사 블록 존재(`_check_incremental_audit_block` — data.json 이 `incrementalDecision.mode == "incremental"` 이면 `### 0.1 Incremental Re-Verification Scope` + `Re-verified stages` / `Carried-forward stages` 행 필수)).
|
|
736
|
-
- `validators/validate-report-views.py` — self-contained HTML view 의 form-control 위치, 외부 URL 부재, stale source digest, Response ID parity(`C-*` ↔ HTML) 검사.
|
|
737
|
-
- `validators/validate-brief.py` — brief schema (front-matter, `Reporter Confirmations` 섹션 존재, root parent-id self 규칙, slug 컨벤션 등) 강제. `bash validators/validate-brief.sh <brief.md>` 가 thin wrapper.
|
|
738
|
-
|
|
739
|
-
각 validator 는 contract 위반 시 `contract-violated` exit code 로 phase 를 차단합니다. 위반은 다음 phase 실행 시점에 적용되므로 이전 산출물은 그대로 둡니다.
|
|
740
|
-
|
|
741
|
-
`contractValidation.status=failed`는 run artifact contract 실패를 뜻하며, 구현 결과 자체가 항상 미완이라는 뜻은 아닙니다. implementation run 은 `runs/implementation/carry/stage-<N>.json`, `runs/implementation-planning/consumers.jsonl`, 승인된 Stage Map 을 함께 읽어 `phaseOutcome.implementation`을 도출합니다. 모든 Stage Map stage 가 pass-grade carry evidence 를 가지면 contract failure 는 감사 정보로 유지하면서 `workflow.nextRecommendedPhase`를 `final-verification`으로 보정할 수 있습니다.
|
|
742
|
-
|
|
743
|
-
## Practical notes
|
|
744
|
-
|
|
745
|
-
- `okstra`는 brief 없이 쓰는 옛 방식이 아닙니다.
|
|
746
|
-
- brief이 분석의 정본 입력입니다. 추가 자료는 brief 내부의 `Evidence and Source Materials` 섹션에 inline 또는 path 로 포함시키며, 별도의 추가 자료 CLI 옵션은 제공하지 않습니다.
|
|
747
|
-
- brief의 `Configuration References and Expected Values`, `Deployment Manifests and Expected Values` 섹션은 task별 expected state의 canonical source입니다.
|
|
748
|
-
- `task-type`가 프로필 선택까지 결정합니다.
|
|
749
|
-
- `--render-only`는 dry-run 확인용이지만 task bundle과 run manifest는 생성합니다.
|
|
750
|
-
- 기본 실행은 Claude print-mode 수집이 아니라 interactive handoff입니다.
|
|
751
|
-
- 기본 최종 보고서 템플릿은 task bundle의 `instruction-set/final-report-template.md`에 렌더링됩니다.
|
|
752
|
-
- task bundle의 `instruction-set/reference-expectations.md`는 config/deployment expected-state reference로 함께 생성됩니다.
|
|
753
|
-
- 현재 run 세션의 resume helper는 `runs/<task-type>/sessions/claude-resume-<task-type>-<seq>.sh`에 생성됩니다.
|
|
754
|
-
- run directory 내부는 `manifests/`, `state/`, `prompts/`, `reports/`, `status/`, `sessions/`, `worker-results/`처럼 유형별 하위 폴더로 구성되고, prompt snapshot은 `prompts/` 아래에 먼저 준비됩니다.
|
|
755
|
-
- worker 생성과 결과 취합은 Claude가 수행합니다.
|
|
756
|
-
- standard workflow는 `Claude lead` + 기본 worker `Claude worker`, `Codex worker`, `Report writer worker`를 사용하고, `Antigravity worker`는 명시할 때만 포함되는 옵션입니다.
|
|
757
|
-
- worker 모델은 `--lead-model`, `--claude-model`, `--codex-model`, `--antigravity-model`, `--report-writer-model`로 override할 수 있고, 기본값은 `OKSTRA_DEFAULT_*` 환경 변수에서 중앙 관리합니다. fallback 기본값은 `Claude lead`/`Report writer worker`=`opus`, `Claude worker`=`opus`, `Codex worker`=`gpt-5.5`, `Antigravity worker`=`auto`입니다.
|
|
758
|
-
- `--task-type implementation` 에서는 Executor 역할을 맡을 provider 를 `--executor <claude|codex|antigravity>` (또는 `OKSTRA_DEFAULT_EXECUTOR`, fallback `claude`) 로 선택합니다. Executor 만 프로젝트 파일을 mutate 할 수 있고, 나머지 두 provider 와 자기 자신의 provider 가 모두 별도 CLI 세션으로 verifier 로 dispatch 됩니다 (세션 분리만으로도 self-review 안전장치 유지). Executor 의 모델은 선택된 provider 의 worker 모델 플래그(`--claude-model` / `--codex-model` / `--antigravity-model`) 를 그대로 재사용하며, run-manifest 의 `teamContract.executor` 블록에 provider / displayName / workerAgent / model 이 기록됩니다.
|
|
759
|
-
- Executor 별 worktree cwd 주입: codex / antigravity executor 는 wrapper(`okstra-codex-exec.sh -C` / `okstra-antigravity-exec.sh --include-directories`) 가 CLI layer 에서 cwd 를 worktree 로 고정합니다. Claude executor 는 Bash tool 에 per-call cwd 인자가 없어 cwd 민감 toolchain (`cargo`/`npm`/`pnpm`/`bun`/`pytest`/`make`/`go`) 호출을 같은 Bash invocation 안에서 `cd {{EXECUTOR_WORKTREE_PATH}} && <cmd>` 로 prefix 합니다 — `bash -lc`/`bash -c` 래핑은 금지되며 (`cd` leading token 이 가려져 permission auto-allow 우회 실패), 작업 디렉터리 플래그 (`git -C`, `cargo --manifest-path` 등) 가 있으면 그것을 우선합니다. 자세한 규약은 `prompts/profiles/implementation.md` 의 *Executor Worktree* 블록과 `agents/workers/claude-worker.md` 의 Executor exception 항목 참고.
|
|
760
|
-
- project-level current-task convenience pointer는 `.okstra/discovery/latest-task.json`입니다.
|
|
761
|
-
- project-level canonical task inventory는 `.okstra/discovery/task-catalog.json`입니다.
|
|
762
|
-
- okstra skill asset은 `okstra install` 시점에 `~/.agents/skills/` 로 기본 seed 되고, `~/.claude` 가 있으면 `~/.claude/skills/` + `~/.claude/agents/` 도 함께 seed 됩니다(per-project seeding은 더 이상 수행되지 않음).
|
|
763
|
-
- seeded okstra Claude assets는 세션의 implicit team 에 `Agent(name: ...)` 로 워커를 dispatch 하는 규칙을 Claude에게 제공합니다(v2.1.178 이 `TeamCreate`/`TeamDelete` 제거). Agent targets 는 skill markdown 만 받습니다.
|
|
764
|
-
- 최종 판단은 스크립트가 아니라 Claude가 수행합니다.
|
|
765
|
-
- stable task key를 유지해야 이후 bug 추적, 재수정, 재검증이 가능합니다.
|
|
766
|
-
- 워커 에러는 옵션 sidecar `runs/<task-type>/logs/errors-<task-type>-<seq>.jsonl`로 수집되며 lead가 단독 writer입니다. 진입점 helper는 `scripts/okstra-error-log.py`입니다.
|
|
767
|
-
- 토큰 사용 및 비용 집계는 `scripts/okstra-token-usage.py`와 Node wrapper `okstra token-usage`가 담당합니다.
|
|
768
|
-
- `okstra.sh`는 worker CLI 호출 anchoring을 위해 절대 projectRoot를 강제합니다.
|
|
769
|
-
- `okstra wizard step` 은 `--answer <val>` 을 **필수** 로 받습니다. 응답을 줄 차례가 아니라 다음 prompt 만 미리 보고 싶다면 `--no-submit` 으로 peek 합니다.
|
|
770
|
-
- `/okstra-inspect history`는 task manifest fallback / 페이지네이션 / 필터를 지원하고, `--base-ref`는 워크트리 registry에서 해석합니다.
|
|
771
|
-
- 사용자 프로젝트에 대한 모든 쓰기는 `<PROJECT_ROOT>/.okstra/` 안에만 발생합니다 (Artifact-home rule 참조).
|
|
772
|
-
|
|
773
|
-
## Related documents
|
|
774
|
-
|
|
775
|
-
- `README.md`
|
|
776
|
-
- `templates/reports/task-brief.template.md`
|
|
777
|
-
- `templates/reports/final-report.template.md`
|
|
778
|
-
- `prompts/lead/okstra-lead-contract.md`
|
|
779
|
-
- `scripts/okstra-error-log.py`
|
|
780
|
-
- `scripts/okstra-token-usage.py`
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
---
|
|
784
|
-
|
|
785
|
-
## okstra Control Center — 동작 모델 / 동시성 / 환경변수
|
|
786
|
-
|
|
787
|
-
### 동작 모델
|
|
788
|
-
|
|
789
|
-
- `okstra.sh` 는 시작 시 1번 `record_start` hook 으로 인덱스에 메타와 invocation 을 기록한다.
|
|
790
|
-
- 종료 처리는 `okstra-ctl` 의 모든 진입점에서 호출되는 lazy reconcile 이 수행한다(타깃 프로젝트의 `final-report-*.md` 존재로 추론).
|
|
791
|
-
- 다중 rerun 은 대상 1건당 tmux 세션 1개를 detached 로 spawn 하고 즉시 반환한다(fire-and-forget). 사용자는 반환된 attach 명령으로 임의 세션에 접속한다.
|
|
792
|
-
- spawn 임계 기본값은 10. `--max-spawn N` 또는 `OKSTRA_CTL_MAX_SPAWN` 으로 변경 가능.
|
|
793
|
-
- runId 형식: `<project-id>/<task-group>/<task-id>/<task-type>/r<run-seq>` (예: `sample-project/payment/fail/error-analysis/r07`). 입력 시 prefix substring 매칭을 지원한다.
|
|
794
|
-
|
|
795
|
-
### 동시성 제어 (두 단계 mutex)
|
|
796
|
-
|
|
797
|
-
`okstra-ctl` 과 `record_start` hook 은 두 가지 서로 다른 스코프의 fcntl `LOCK_EX` 를 사용한다. 둘은 책임이 분리되어 있어 함께 들고 있어도 데드락이 발생하지 않는다.
|
|
798
|
-
|
|
799
|
-
| Lock | 위치 | 스코프 | 보유 시점 | 목적 |
|
|
800
|
-
|---|---|---|---|---|
|
|
801
|
-
| 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 하지 않게 한다. |
|
|
802
|
-
| 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 은 서로 블록하지 않는다. |
|
|
803
|
-
|
|
804
|
-
호출 순서는 항상 `task lock` → `central lock` (ctl rerun) 또는 `central lock` 단독(record_start, reconcile). 역순 보유는 발생하지 않는다.
|
|
805
|
-
|
|
806
|
-
`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)).
|
|
807
|
-
|
|
808
|
-
### 환경변수
|
|
809
|
-
|
|
810
|
-
- `OKSTRA_HOME`: 중앙 디렉터리 위치 override (기본 `~/.okstra`).
|
|
811
|
-
- `OKSTRA_CTL_MAX_SPAWN`: rerun 동시 spawn 임계 기본값.
|
|
812
|
-
- `OKSTRA_CTL_SKIP_BACKFILL=1`: 첫 호출 시 자동 백필 스킵.
|
|
813
|
-
- `OKSTRA_CTL_SKIP_RECONCILE=1`: lazy reconcile 스킵(테스트/디버깅용).
|
|
814
|
-
- `OKSTRA_SKIP_INSTALL_CHECK=1`: `verify_installation` 의 설치 자산 검사 스킵(테스트용; workspace 존재 검증은 유지).
|
|
815
|
-
- `OKSTRA_RUN_SEQ_OVERRIDE`: rerun 시 okstra.sh 가 사용할 run-seq 강제값 (okstra-ctl 내부 자동 주입).
|