okstra 0.19.1 → 0.20.1

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.kr.md CHANGED
@@ -28,7 +28,7 @@ okstra/ npm 패키지 = repo 루트
28
28
  ├── tools/build.mjs runtime/ 동기화 스크립트 (prepack 에서 호출)
29
29
  ├── runtime/ gitignored 빌드 산출물; ~/.okstra 로 배포되는 유일한 자산
30
30
  ├── scripts/ python + bash 런타임 소스
31
- ├── skills/ Claude Code 스킬 마크다운 소스 (스킬 11종)
31
+ ├── skills/ Claude Code 스킬 마크다운 소스 (스킬 12종)
32
32
  ├── agents/ lead SKILL.md + workers/
33
33
  ├── prompts/, templates/, validators/
34
34
  ├── docs/kr/ 한국어 상세 매뉴얼 (architecture.md, cli.md)
@@ -56,7 +56,7 @@ okstra/ npm 패키지 = repo 루트
56
56
  └── archive/ 완료된 run
57
57
 
58
58
  ~/.claude/skills/ Claude Code 가 자동 인식
59
- └── okstra-*/SKILL.md 스킬 11종 (§3.3 참조)
59
+ └── okstra-*/SKILL.md 스킬 12종 (§3.3 참조)
60
60
 
61
61
  ~/.claude/agents/ Claude Code 가 자동 인식 (subagent 디스커버리 경로)
62
62
  └── {claude,codex,gemini,report-writer}-worker.md worker subagent 정의
@@ -87,7 +87,7 @@ okstra/ npm 패키지 = repo 루트
87
87
  npx -y okstra@latest install
88
88
  ```
89
89
 
90
- `~/.okstra/{lib/python, bin, version}`, `~/.claude/skills/` 아래 스킬 마크다운 11개, `~/.okstra/installed-skills.json` 을 생성합니다. 재실행은 idempotent — 파일별 hash 를 비교하고 바뀐 파일만 갱신합니다.
90
+ `~/.okstra/{lib/python, bin, version}`, `~/.claude/skills/` 아래 스킬 마크다운 12개, `~/.okstra/installed-skills.json` 을 생성합니다. 재실행은 idempotent — 파일별 hash 를 비교하고 바뀐 파일만 갱신합니다.
91
91
 
92
92
  검증:
93
93
 
@@ -140,7 +140,7 @@ Claude Code 세션 안에서 사용하는 슬래시 커맨드:
140
140
  | `/okstra-schedule` | task-group 전체에 대한 작업 계획표 생성 |
141
141
  | `/okstra-setup` | 프로젝트별 부트스트랩 (§3.2) |
142
142
 
143
- 이 외에 `okstra-context-loader`, `okstra-team-contract`, `okstra-convergence`, `okstra-report-writer`, `okstra-time-summary`, `okstra-report-finder` 6종은 `user-invocable: false` 로 표시되어 슬래시 커맨드로 노출되지 않습니다. lead 또는 Claude 가 자연어 트리거(예: "이 task 얼마나 걸렸어?" → `okstra-time-summary`, "보고서 찾아줘" → `okstra-report-finder`)로 자동 호출합니다.
143
+ 이 외에 `okstra-context-loader`, `okstra-team-contract`, `okstra-convergence`, `okstra-report-writer`, `okstra-time-summary`, `okstra-report-finder`, `okstra-logs` 7종은 `user-invocable: false` 로 표시되어 슬래시 커맨드로 노출되지 않습니다. lead 또는 Claude 가 자연어 트리거(예: "이 task 얼마나 걸렸어?" → `okstra-time-summary`, "보고서 찾아줘" → `okstra-report-finder`, "codex/gemini 로그 용량 보여줘" → `okstra-logs` — wrapper 가 매 dispatch 마다 남기는 `<prompt>.log` sidecar 의 용량을 집계하고 task / phase / worker 별로 즉시 복사 가능한 `find … -delete` cleanup 명령을 제시하되 직접 실행하지는 않음)로 자동 호출합니다.
144
144
 
145
145
  ### 3.4 CLI 모드 (선택)
146
146
 
package/README.md CHANGED
@@ -28,7 +28,7 @@ okstra/ npm package = repo root
28
28
  ├── tools/build.mjs runtime/ sync script (invoked by prepack)
29
29
  ├── runtime/ gitignored build output; the only thing shipped to ~/.okstra
30
30
  ├── scripts/ python + bash runtime sources
31
- ├── skills/ Claude Code skill markdown sources (11 skills)
31
+ ├── skills/ Claude Code skill markdown sources (12 skills)
32
32
  ├── agents/ lead SKILL.md + workers/
33
33
  ├── prompts/, templates/, validators/
34
34
  ├── tests/, tests-e2e/
@@ -55,7 +55,7 @@ okstra/ npm package = repo root
55
55
  └── archive/ completed runs
56
56
 
57
57
  ~/.claude/skills/ discovered automatically by Claude Code
58
- └── okstra-*/SKILL.md 11 skills total (see §3.3)
58
+ └── okstra-*/SKILL.md 12 skills total (see §3.3)
59
59
 
60
60
  ~/.claude/agents/ discovered automatically by Claude Code
61
61
  └── {claude,codex,gemini,report-writer}-worker.md subagent definitions
@@ -86,7 +86,7 @@ okstra/ npm package = repo root
86
86
  npx -y okstra@latest install
87
87
  ```
88
88
 
89
- Provisions `~/.okstra/{lib/python, bin, version}`, the 11 skill markdown files under `~/.claude/skills/`, and `~/.okstra/installed-skills.json`. Re-running is idempotent — per-file hashes are compared and only changed files are touched.
89
+ Provisions `~/.okstra/{lib/python, bin, version}`, the 12 skill markdown files under `~/.claude/skills/`, and `~/.okstra/installed-skills.json`. Re-running is idempotent — per-file hashes are compared and only changed files are touched.
90
90
 
91
91
  Verify:
92
92
 
@@ -139,7 +139,7 @@ User-facing slash commands inside a Claude Code session:
139
139
  | `/okstra-schedule` | Generate a work schedule for an entire task-group |
140
140
  | `/okstra-setup` | Per-project bootstrap (§3.2) |
141
141
 
142
- Six additional skills — `okstra-context-loader`, `okstra-team-contract`, `okstra-convergence`, `okstra-report-writer`, `okstra-time-summary`, `okstra-report-finder` — are marked `user-invocable: false` and do not appear as slash commands. Claude still invokes them automatically via natural-language triggers (e.g. "이 task 얼마나 걸렸어?" routes to `okstra-time-summary`; "show me the report for X" routes to `okstra-report-finder`).
142
+ Seven additional skills — `okstra-context-loader`, `okstra-team-contract`, `okstra-convergence`, `okstra-report-writer`, `okstra-time-summary`, `okstra-report-finder`, `okstra-logs` — are marked `user-invocable: false` and do not appear as slash commands. Claude still invokes them automatically via natural-language triggers (e.g. "이 task 얼마나 걸렸어?" routes to `okstra-time-summary`; "show me the report for X" routes to `okstra-report-finder`; "codex/gemini 로그 용량 보여줘" routes to `okstra-logs`, which inventories the `<prompt>.log` sidecars produced by every CLI dispatch and emits ready-to-copy `find … -delete` cleanup lines without executing them).
143
143
 
144
144
  ### 3.4 CLI mode (optional)
145
145
 
@@ -149,7 +149,7 @@ okstra 의 prepare 책임은 단일 python 진입점 [`okstra_ctl.run.prepare_ta
149
149
  - [`agents/SKILL.md`](agents/SKILL.md) — main okstra skill (cross-verify 트리거).
150
150
  - [`skills/okstra-setup/SKILL.md`](skills/okstra-setup/SKILL.md) — **첫 실행 부트스트랩**. `okstra install` + `project.json` 생성.
151
151
  - [`skills/okstra-run/SKILL.md`](skills/okstra-run/SKILL.md) — **현재 claude 세션 안에서 okstra task 를 시작**하는 in-session 진입점. `prepare_task_bundle` 직접 호출.
152
- - `skills/okstra-{status,history,convergence,schedule,context-loader,team-contract,report-finder,report-writer,time-summary}/SKILL.md` — phase 진행·status·history 보조 skill.
152
+ - `skills/okstra-{status,history,convergence,schedule,context-loader,team-contract,report-finder,report-writer,time-summary,logs}/SKILL.md` — phase 진행·status·history 보조 skill. `okstra-logs` 는 codex/gemini wrapper 가 매 dispatch 마다 `runs/<task-type>/prompts/<worker>-prompt-<phase>-<seq>.log` 로 남기는 live-log sidecar 의 인벤토리·정리 안내 (read-only, find-delete cleanup 명령 제안만 함).
153
153
  - 플러그인 매니페스트: [`.claude-plugin/plugin.json`](.claude-plugin/plugin.json) — `npx skills@latest add Devonshin/okstra` 보조 채널이 참조. 0.3.0 부터는 `npx okstra install` 한 명령이 동일 결과를 보장하므로 일반 셋업에는 이 채널이 필요 없다.
154
154
  - 설치 위치: `~/.claude/skills/<name>/SKILL.md` (`okstra-install.sh` dev 설치, 또는 위 npx 채널).
155
155
  - 릴리스 절차: [`RELEASING.md`](RELEASING.md) — npm publish 흐름과 GitHub Actions 워크플로(`v*.*.*` tag → 자동 publish), 자동화 토큰 셋업, 검증/롤백.
@@ -828,10 +828,22 @@ Claude가 작성하는 최종 보고서는 brief에 더 구체적인 형식이
828
828
  - `source` 필드(`worker-reported` | `lead-observed`)와 `errorType`(`tool-failure` | `cli-failure` | `contract-violation`)으로 발생원과 종류를 구분합니다.
829
829
  - `stderrExcerpt`는 한 줄 jsonl 가독성을 위해 2KB 상한, `PIPE_BUF`(4096B) atomic append 가드를 강제합니다.
830
830
  - run-manifest 또는 team-state의 `errorsLogPath` 필드에 `logs/errors-<task-type>-<seq>.jsonl` 경로를 1회 기록해 발견 가능하게 합니다.
831
+ - 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 화 됐습니다.
831
832
  - Helper CLI: `scripts/okstra-error-log.py`
832
833
  - 단일 진입점으로 record를 append 합니다.
833
834
  - 워커 sidecar dump(`append_observed`, schema version 가드)와 lead 관찰(`lead-observed`) 모두 동일 helper를 사용합니다.
834
835
 
836
+ ### Live-log mirror (codex / gemini wrapper)
837
+
838
+ - `scripts/okstra-codex-exec.sh`, `scripts/okstra-gemini-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 를 탐지할 수 없는 문제를 해소합니다.
839
+ - `$TMUX` 가 셋팅된 lead 환경이면 wrapper 가 sibling pane 을 자동 분할해 `tail -F <log-path>` 를 띄웁니다. pane title 은 `<cli>-<role>-trace` (e.g. `codex-worker-trace`, `gemini-worker-trace`); role 은 wrapper 의 5번째 optional positional 인자이며, 누락 시 기본값 `worker` 로 떨어집니다. caller 가 다른 라벨(예: `executor`)을 원하면 5번째 인자로 명시해야 합니다. focus 는 caller pane 으로 복귀하고, CLI 종료 후 pane 은 유지돼 스크롤백 가능. `$TMUX` 미설정, split 실패, 구버전 tmux 등 모든 경로는 silent degrade.
840
+ - 디스크 누적은 `okstra-logs` skill 이 read-only 로 인벤토리 + cleanup 명령을 제안합니다 (실행은 사용자 copy-paste).
841
+
842
+ ### Linked-worktree `.git/` write 권한 (codex / gemini)
843
+
844
+ - `--executor codex|gemini` 의 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 하고 종료).
845
+ - 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 (gemini) 로 sandbox 에 함께 forward 합니다.
846
+
835
847
  상세 설계 및 jq 회고 레시피는 `docs/superpowers/specs/2026-04-28-worker-error-collection-design.md`를 참고합니다.
836
848
 
837
849
  ## Token usage and cost accounting
package/docs/kr/cli.md CHANGED
@@ -481,3 +481,21 @@ chmod +x ~/.local/bin/okstra-ctl
481
481
  | 활성 run 재조정 | `okstra-ctl reconcile [--project <id|all>]` |
482
482
  | 배치 진행 | `okstra-ctl batch status <batch-id>` |
483
483
 
484
+ ### `okstra` Node CLI — introspection subcommands
485
+
486
+ `okstra` Node CLI (`bin/okstra`) 가 skill / agent 에서 사용하는 read-only introspection subcommand 를 제공합니다. 모두 JSON 을 stdout 으로 emit 합니다. 별도 python heredoc 대신 단일 allowlisted command 로 호출 가능 — Claude Code 가 매 호출마다 permission prompt 를 띄우지 않습니다 (`Bash(okstra:*)` 가 runtime settings template 의 allow 룰에 포함).
487
+
488
+ | 명령 | 용도 |
489
+ |---|---|
490
+ | `okstra task-list [--project-root <path>]` | `list_project_tasks` + `read_latest_task` 결과를 합쳐 task 카탈로그 + 최근 task 를 JSON 으로 반환 |
491
+ | `okstra task-show <task-key> [--project-root <path>]` | task-manifest.json 의 workflow / phase / status 요약 |
492
+ | `okstra worktree-lookup <task-key>` | `worktree_registry.lookup` 결과 (예약된 path / branch / base ref / 현재 상태) |
493
+ | `okstra plan-validate <plan-path>` | `_validate_approved_plan` — approval marker 인식 결과와 sanitization 후 diff |
494
+ | `okstra render-bundle <args…>` | `prepare_task_bundle(render_only=True)` 의 thin shim — `python3 -m okstra_ctl.run --render-only` 와 동일 시그니처 |
495
+
496
+ > 모든 subcommand 는 `bin/okstra` 가 spawn 하는 python 헬퍼 (`src/_python-helper.mjs`) 가 `PYTHONPATH` 와 `~/.okstra/lib/python` 을 wire 합니다. 직접 `python3 -m okstra_ctl.*` 으로 호출하면 `PYTHONPATH` 를 사용자가 직접 셋업해야 합니다.
497
+
498
+ ### Live-log sidecar
499
+
500
+ codex / gemini wrapper 는 매 dispatch 마다 `runs/<task-type>/prompts/<worker>-prompt-<phase>-<seq>.log` sidecar 를 만들고 stdout / stderr 를 mirror 합니다. tmux 안에서 lead 를 띄우면 wrapper 가 자동으로 `tail -F` pane 을 분할합니다 (title: `<cli>-<role>-trace`). 사용량 인벤토리와 `find … -delete` cleanup 명령은 `okstra-logs` skill 이 read-only 로 제안합니다. 자세한 와이어링은 [`docs/kr/architecture.md`](architecture.md) 의 *Live-log mirror* 절 참고.
501
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "okstra",
3
- "version": "0.19.1",
3
+ "version": "0.20.1",
4
4
  "description": "Multi-agent cross-verification orchestrator runtime + Claude Code skills.",
5
5
  "license": "MIT",
6
6
  "author": "devonshin",
@@ -1,5 +1,5 @@
1
1
  {
2
- "package": "0.19.1",
3
- "builtAt": "2026-05-13T15:21:25.918Z",
2
+ "package": "0.20.1",
3
+ "builtAt": "2026-05-14T01:49:53.274Z",
4
4
  "repoRoot": "/home/runner/work/okstra/okstra"
5
5
  }
@@ -27,9 +27,11 @@ You are a Codex worker agent. Your job is to execute the OpenAI Codex CLI and re
27
27
 
28
28
  **Required form (uses the okstra wrapper to avoid redirect-triggered permission prompts):**
29
29
  ```bash
30
- $HOME/.okstra/bin/okstra-codex-exec.sh "<absolute-project-root>" "<assigned-model-execution-value>" "<absolute-prompt-history-path>" [<absolute-worktree-path>]
30
+ $HOME/.okstra/bin/okstra-codex-exec.sh "<absolute-project-root>" "<assigned-model-execution-value>" "<absolute-prompt-history-path>" [<absolute-worktree-path>] [<role>]
31
31
  ```
32
32
 
33
+ The fifth argument `<role>` is the trace-pane label suffix (`codex-<role>-trace`); pass the literal string `worker` for every dispatch from this subagent. The wrapper defaults to `worker` when the argument is omitted, but pass it explicitly so the dispatch is self-describing.
34
+
33
35
  The fourth argument is **mandatory for implementation phase** and optional otherwise. It must be the literal `EXECUTOR_WORKTREE_PATH` recorded in the run context; the wrapper forwards it to codex as `--add-dir`, which grants the codex sandbox write access to the worktree (where all implementation-phase mutations occur). Without it, codex's `workspace-write` sandbox is anchored only at `<project-root>` and rejects every Edit/Write that targets the worktree (EPERM), which is the failure pattern that originally motivated this argument.
34
36
 
35
37
  The wrapper internally runs:
@@ -73,7 +75,7 @@ The wrapper exists because Claude Code's Bash permission matcher rejects simple-
73
75
 
74
76
  **Dispatch (background, no foreground timeout):**
75
77
  ```bash
76
- $HOME/.okstra/bin/okstra-codex-exec.sh "<absolute-project-root>" "<assigned-model-execution-value>" "<absolute-prompt-history-path>" "<absolute-worktree-path>"
78
+ $HOME/.okstra/bin/okstra-codex-exec.sh "<absolute-project-root>" "<assigned-model-execution-value>" "<absolute-prompt-history-path>" "<absolute-worktree-path>" "worker"
77
79
  ```
78
80
  Call `Bash` with `run_in_background: true`. Capture the returned `bash_id` (a.k.a. `shell_id`). Pass the positional arguments verbatim — do NOT use environment variables, `cd`, `&&` chains, or pipes from `cat`. Substitute the literal extracted Project Root, model execution value, prompt-history path, and worktree path. The fourth argument is **mandatory for implementation phase** (extract from `EXECUTOR_WORKTREE_PATH` in the lead prompt's run context or the `**Worktree:**` / `cwd for every mutating command:` line) and **may be omitted only for non-implementation analysis phases** that do not mutate the worktree. Omitting it during implementation will cause every Edit/Write to fail with EPERM. The wrapper handles `-C`, `--add-dir`, `--model`, `--sandbox workspace-write`, the stdin redirect from the prompt file, and stderr suppression internally. Calling `codex exec` directly (without the wrapper) is an error in this skill: the redirect tokens disqualify the prefix match against `Bash(codex exec:*)` and produce a permission prompt every dispatch.
79
81
 
@@ -114,7 +116,7 @@ This wrapper does NOT invoke MCP tools directly. MCP availability inside the Cod
114
116
  - Include context (code, diff, file paths) if provided.
115
117
  - For long prompts, the wrapper script reads from the saved project-local prompt history file via stdin redirect internally. The caller invokes the wrapper with three required positional args + the worktree path for implementation phase:
116
118
  ```bash
117
- $HOME/.okstra/bin/okstra-codex-exec.sh "<literal-project-root>" "<assigned-model-execution-value>" "<literal-prompt-history-path>" "<literal-worktree-path>"
119
+ $HOME/.okstra/bin/okstra-codex-exec.sh "<literal-project-root>" "<assigned-model-execution-value>" "<literal-prompt-history-path>" "<literal-worktree-path>" "worker"
118
120
  ```
119
121
  - If the parent directory does not exist yet, create it before writing the prompt file.
120
122
 
@@ -184,7 +186,7 @@ and the run-level error log staying empty.
184
186
  --agent codex-worker --agent-role worker \
185
187
  --model "<assigned-model-execution-value>" \
186
188
  --error-type cli-failure \
187
- --command "$HOME/.okstra/bin/okstra-codex-exec.sh <project-root> <m> <prompt-path> <worktree-path>" \
189
+ --command "$HOME/.okstra/bin/okstra-codex-exec.sh <project-root> <m> <prompt-path> <worktree-path> worker" \
188
190
  --command-kind cli-invoke \
189
191
  --exit-code <N> --duration-ms <ms> \
190
192
  --message "<one-line summary>" \
@@ -27,9 +27,11 @@ You are a Gemini worker agent. Your job is to execute the Google Gemini CLI and
27
27
 
28
28
  **Required form (uses the okstra wrapper to avoid redirect-triggered permission prompts):**
29
29
  ```bash
30
- $HOME/.okstra/bin/okstra-gemini-exec.sh "<absolute-project-root>" "<assigned-model-execution-value>" "<absolute-prompt-history-path>" [<absolute-worktree-path>]
30
+ $HOME/.okstra/bin/okstra-gemini-exec.sh "<absolute-project-root>" "<assigned-model-execution-value>" "<absolute-prompt-history-path>" [<absolute-worktree-path>] [<role>]
31
31
  ```
32
32
 
33
+ The fifth argument `<role>` is the trace-pane label suffix (`gemini-<role>-trace`); pass the literal string `worker` for every dispatch from this subagent. The wrapper defaults to `worker` when the argument is omitted, but pass it explicitly so the dispatch is self-describing.
34
+
33
35
  The fourth argument is **mandatory for implementation phase** and optional otherwise. It must be the literal `EXECUTOR_WORKTREE_PATH` recorded in the run context; the wrapper appends it to gemini's `--include-directories` list so the model can both read and operate on the worktree alongside project-root.
34
36
 
35
37
  The wrapper internally runs:
@@ -73,7 +75,7 @@ The wrapper exists because Claude Code's Bash permission matcher rejects simple-
73
75
 
74
76
  **Dispatch (background, no foreground timeout):**
75
77
  ```bash
76
- $HOME/.okstra/bin/okstra-gemini-exec.sh "<absolute-project-root>" "<assigned-model-execution-value>" "<absolute-prompt-history-path>" "<absolute-worktree-path>"
78
+ $HOME/.okstra/bin/okstra-gemini-exec.sh "<absolute-project-root>" "<assigned-model-execution-value>" "<absolute-prompt-history-path>" "<absolute-worktree-path>" "worker"
77
79
  ```
78
80
  Call `Bash` with `run_in_background: true`. Capture the returned `bash_id` (a.k.a. `shell_id`). Pass the positional arguments verbatim — do NOT use environment variables, `cd`, `&&` chains, or pipes from `cat`. Substitute the literal extracted Project Root, model execution value, prompt-history path, and worktree path. The fourth argument is **mandatory for implementation phase** (extract from `EXECUTOR_WORKTREE_PATH` in the lead prompt's run context or the `**Worktree:**` / `cwd for every mutating command:` line) and **may be omitted only for non-implementation analysis phases** that do not mutate the worktree. The wrapper handles `-p -`, `-m`, `-o text`, `--include-directories`, the stdin redirect from the prompt file, and stderr suppression internally. Calling `gemini` directly (without the wrapper) is an error in this skill: the redirect tokens disqualify the prefix match against `Bash(gemini:*)` and produce a permission prompt every dispatch.
79
81
 
@@ -114,7 +116,7 @@ This wrapper does NOT invoke MCP tools directly. MCP availability inside the Gem
114
116
  - Include context (code, diff, file paths) if provided.
115
117
  - For long prompts, dispatch through the wrapper with literal absolute paths (plus the worktree path for implementation phase):
116
118
  ```bash
117
- $HOME/.okstra/bin/okstra-gemini-exec.sh "<literal-project-root>" "<assigned-model-execution-value>" "<literal-prompt-history-path>" "<literal-worktree-path>"
119
+ $HOME/.okstra/bin/okstra-gemini-exec.sh "<literal-project-root>" "<assigned-model-execution-value>" "<literal-prompt-history-path>" "<literal-worktree-path>" "worker"
118
120
  ```
119
121
  - If the parent directory does not exist yet, create it before writing the prompt file.
120
122
 
@@ -184,7 +186,7 @@ and the run-level error log staying empty.
184
186
  --agent gemini-worker --agent-role worker \
185
187
  --model "<assigned-model-execution-value>" \
186
188
  --error-type cli-failure \
187
- --command "$HOME/.okstra/bin/okstra-gemini-exec.sh <project-root> <m> <prompt-path> <worktree-path>" \
189
+ --command "$HOME/.okstra/bin/okstra-gemini-exec.sh <project-root> <m> <prompt-path> <worktree-path> worker" \
188
190
  --command-kind cli-invoke \
189
191
  --exit-code <N> --duration-ms <ms> \
190
192
  --message "<one-line summary>" \
@@ -53,10 +53,7 @@ project_root="$1"
53
53
  model="$2"
54
54
  prompt_path="$3"
55
55
  worktree_path="${4-}"
56
- role="${5-}"
57
- if [[ -z "$role" ]]; then
58
- if [[ -n "$worktree_path" ]]; then role="executor"; else role="worker"; fi
59
- fi
56
+ role="${5:-worker}"
60
57
 
61
58
  if [[ -z "$project_root" || ! -d "$project_root" ]]; then
62
59
  printf 'okstra-codex-exec: project-root is missing or not a directory: %q\n' "$project_root" >&2
@@ -127,8 +124,10 @@ log_path="${prompt_path%.md}.log"
127
124
  # for the wrapper to exit. This fires in every phase the wrapper is invoked
128
125
  # from (analysis, error-analysis, implementation-planning, implementation,
129
126
  # …) — long-running codex dispatches are not implementation-specific. The
130
- # new pane carries the title `codex-<role>-trace` (e.g. `codex-worker-trace`
131
- # in analysis, `codex-executor-trace` in implementation) and uses `tail -F`
127
+ # new pane carries the title `codex-<role>-trace` `role` is the optional
128
+ # 5th positional arg (defaults to `worker`); callers that dispatch a
129
+ # different role (e.g. `executor`) must pass it explicitly. The pane uses
130
+ # `tail -F`
132
131
  # (follow-by-name) so it survives any truncation a re-dispatch performs on
133
132
  # the same log path. Failures are tolerated silently: missing $TMUX, a tmux
134
133
  # that refuses to split (size constraints, locked client), or a stale socket
@@ -45,10 +45,7 @@ project_root="$1"
45
45
  model="$2"
46
46
  prompt_path="$3"
47
47
  worktree_path="${4-}"
48
- role="${5-}"
49
- if [[ -z "$role" ]]; then
50
- if [[ -n "$worktree_path" ]]; then role="executor"; else role="worker"; fi
51
- fi
48
+ role="${5:-worker}"
52
49
 
53
50
  if [[ -z "$project_root" || ! -d "$project_root" ]]; then
54
51
  printf 'okstra-gemini-exec: project-root is missing or not a directory: %q\n' "$project_root" >&2
@@ -112,10 +109,11 @@ log_path="${prompt_path%.md}.log"
112
109
  # When a tmux session is reachable, split a sibling pane tailing the log so
113
110
  # the operator can watch progress live. This fires in every phase the
114
111
  # wrapper is invoked from — long-running gemini dispatches are not
115
- # implementation-specific. Title `gemini-<role>-trace` (e.g.
116
- # `gemini-worker-trace` in analysis, `gemini-executor-trace` in
117
- # implementation). See the codex wrapper for the full design rationale and
118
- # the silent-degrade failure model.
112
+ # implementation-specific. Title `gemini-<role>-trace` — `role` is the
113
+ # optional 5th positional arg (defaults to `worker`); callers that
114
+ # dispatch a different role must pass it explicitly. See the codex
115
+ # wrapper for the full design rationale and the silent-degrade failure
116
+ # model.
119
117
  if [[ -n "${TMUX:-}" ]]; then
120
118
  trace_pane=$(tmux split-window -h -P -F '#{pane_id}' \
121
119
  -c "$(dirname "$log_path")" \
@@ -19,7 +19,6 @@ import json
19
19
  import os
20
20
  import re
21
21
  import shutil
22
- import subprocess
23
22
  from dataclasses import dataclass, field
24
23
  from datetime import datetime, timezone
25
24
  from pathlib import Path
@@ -819,11 +818,6 @@ def prepare_task_bundle(inp: PrepareInputs) -> PrepareOutputs:
819
818
  )
820
819
 
821
820
 
822
- def claude_is_available() -> bool:
823
- """`claude` CLI 가 PATH 에 있는지 확인."""
824
- return shutil.which("claude") is not None
825
-
826
-
827
821
  def main(argv: list[str]) -> int:
828
822
  """CLI dispatcher for bash thin-wrapper use. Parses a flat list of argv
829
823
  (the same flags `okstra.sh` accepts), runs prepare_task_bundle, prints
@@ -43,9 +43,6 @@ from .ids import _safe_fs_segment
43
43
  from . import worktree_registry
44
44
 
45
45
 
46
- OKSTRA_WORKTREES_RELATIVE = Path(".okstra/worktrees")
47
-
48
-
49
46
  # Project-root directories that hold okstra task state, ignored by git, or
50
47
  # otherwise required for the executor to operate but NOT carried across by
51
48
  # `git worktree add`. Each is symlinked from the MAIN worktree into the new
@@ -5,8 +5,6 @@ from .paths import utc_now
5
5
  from .pricing import (
6
6
  claude_billable_equivalent,
7
7
  claude_cost_usd,
8
- codex_cost_usd,
9
- gemini_cost_usd,
10
8
  )
11
9
 
12
10
 
@@ -15,8 +15,6 @@ def claude_session_totals(jsonl_path: Path) -> dict:
15
15
  model: str | None = None
16
16
  first_ts: str | None = None
17
17
  last_ts: str | None = None
18
- started_at: str | None = None
19
- ended_at: str | None = None
20
18
  for rec in iter_jsonl(jsonl_path):
21
19
  if agent_name is None and rec.get("agentName"):
22
20
  agent_name = rec["agentName"]