okstra 0.76.0 → 0.77.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.kr.md +5 -3
- package/README.md +5 -3
- package/bin/okstra +10 -2
- package/docs/kr/architecture.md +1 -1
- package/docs/kr/cli.md +20 -4
- package/docs/pr-template-usage.md +3 -3
- package/docs/superpowers/plans/2026-05-25-okstra-project-root-rename.md +1 -1
- package/docs/superpowers/specs/2026-06-12-codex-lead-adapter-design.md +358 -0
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/bin/lib/okstra/cli.sh +5 -1
- package/runtime/bin/lib/okstra/globals.sh +1 -0
- package/runtime/bin/lib/okstra/usage.sh +6 -4
- package/runtime/bin/okstra.sh +1 -0
- package/runtime/prompts/launch.template.md +4 -13
- package/runtime/prompts/profiles/error-analysis.md +6 -0
- package/runtime/prompts/profiles/improvement-discovery.md +5 -0
- package/runtime/prompts/profiles/release-handoff.md +2 -2
- package/runtime/python/okstra_ctl/analysis_packet.py +17 -0
- package/runtime/python/okstra_ctl/codex_dispatch.py +1484 -0
- package/runtime/python/okstra_ctl/lead_events.py +129 -0
- package/runtime/python/okstra_ctl/paths.py +3 -0
- package/runtime/python/okstra_ctl/pr_template.py +1 -1
- package/runtime/python/okstra_ctl/render.py +160 -29
- package/runtime/python/okstra_ctl/run.py +78 -15
- package/runtime/python/okstra_token_usage/codex.py +12 -7
- package/runtime/python/okstra_token_usage/collect.py +243 -54
- package/runtime/python/okstra_token_usage/gemini.py +12 -7
- package/runtime/skills/okstra-setup/SKILL.md +1 -1
- package/runtime/validators/validate-run.py +56 -22
- package/runtime/validators/validate_session_conformance.py +121 -4
- package/src/codex-dispatch.mjs +70 -0
- package/src/codex-run.mjs +68 -0
- package/src/doctor.mjs +40 -4
- package/src/install.mjs +122 -26
- package/src/paths.mjs +17 -3
- package/src/render-bundle.mjs +2 -0
- package/src/runtime-manifest.mjs +26 -0
- package/src/uninstall.mjs +26 -4
- /package/runtime/{skills/okstra-run/templates → templates/prd}/pr-body.template.md +0 -0
package/runtime/BUILD.json
CHANGED
|
@@ -82,6 +82,10 @@ while [[ $# -gt 0 ]]; do
|
|
|
82
82
|
REPORT_WRITER_MODEL_OVERRIDE="$(require_option_value --report-writer-model "${2-}")"
|
|
83
83
|
shift 2
|
|
84
84
|
;;
|
|
85
|
+
--lead-runtime)
|
|
86
|
+
LEAD_RUNTIME="$(require_option_value --lead-runtime "${2-}")"
|
|
87
|
+
shift 2
|
|
88
|
+
;;
|
|
85
89
|
--executor)
|
|
86
90
|
EXECUTOR_OVERRIDE="$(require_option_value --executor "${2-}")"
|
|
87
91
|
shift 2
|
|
@@ -208,7 +212,7 @@ while [[ $# -gt 0 ]]; do
|
|
|
208
212
|
printf ' hint: did you mean --task-id?\n' >&2
|
|
209
213
|
;;
|
|
210
214
|
esac
|
|
211
|
-
printf ' valid options: --render-only --resume-clarification --yes --workers --lead-model --claude-model --codex-model --gemini-model --report-writer-model --related-tasks --task-type --project-id --project-root --task-group --task-id --task-brief --directive --fix-cycle --clarification-response --approved-plan --approve --implementation-option --stage --qa-waiver --no-plan-verification -h|--help\n' >&2
|
|
215
|
+
printf ' valid options: --render-only --resume-clarification --yes --workers --lead-model --claude-model --codex-model --gemini-model --report-writer-model --lead-runtime --related-tasks --task-type --project-id --project-root --task-group --task-id --task-brief --directive --fix-cycle --clarification-response --approved-plan --approve --implementation-option --stage --qa-waiver --no-plan-verification -h|--help\n' >&2
|
|
212
216
|
usage
|
|
213
217
|
exit 1
|
|
214
218
|
;;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
usage() {
|
|
4
4
|
cat >&2 <<USAGE_EOF
|
|
5
5
|
usage:
|
|
6
|
-
$DISPLAY_COMMAND_NAME [--render-only] [--yes] [--no-plan-verification] --task-type <task-type> [--workers worker1,worker2] [--lead-model <model>] [--claude-model <model>] [--codex-model <model>] [--gemini-model <model>] [--report-writer-model <model>] [--executor claude|codex|gemini] [--critic off|claude|codex|gemini] [--related-tasks taskA,taskB] --project-id <project-id> [--project-root <path>] --task-group <task-group> --task-id <task-id> --task-brief <brief-path> [--directive <directive>] [--fix-cycle <yes|no>]
|
|
6
|
+
$DISPLAY_COMMAND_NAME [--render-only] [--yes] [--no-plan-verification] --task-type <task-type> [--workers worker1,worker2] [--lead-model <model>] [--claude-model <model>] [--codex-model <model>] [--gemini-model <model>] [--report-writer-model <model>] [--lead-runtime claude-code|codex] [--executor claude|codex|gemini] [--critic off|claude|codex|gemini] [--related-tasks taskA,taskB] --project-id <project-id> [--project-root <path>] --task-group <task-group> --task-id <task-id> --task-brief <brief-path> [--directive <directive>] [--fix-cycle <yes|no>]
|
|
7
7
|
|
|
8
8
|
summary:
|
|
9
9
|
$DISPLAY_TOOL_NAME prepares a task-keyed instruction bundle for Claude Code and launches an interactive Claude session by default.
|
|
@@ -27,7 +27,7 @@ required arguments:
|
|
|
27
27
|
optional arguments:
|
|
28
28
|
--project-root Absolute path to the target project root. Resolution order when omitted:
|
|
29
29
|
(1) ancestor of cwd that contains .okstra/project.json,
|
|
30
|
-
(2)
|
|
30
|
+
(2) \`git rev-parse --show-toplevel\` from cwd. Errors out if neither resolves.
|
|
31
31
|
--directive Free-form user-supplied directive carried into the run as a "## Directive" section
|
|
32
32
|
inside instruction-set/analysis-material.md. Lead, workers, and skills (e.g. okstra-schedule)
|
|
33
33
|
may treat this as a hard hint that overrides default heuristics. Use to express intent
|
|
@@ -87,13 +87,16 @@ options:
|
|
|
87
87
|
exclusive with --clarification-response and --approved-plan.
|
|
88
88
|
--yes Skip interactive prompting and confirmation. Requires all required arguments.
|
|
89
89
|
--workers Comma-separated worker list for this run. Default: claude,codex,report-writer
|
|
90
|
-
(Gemini worker is optional; add
|
|
90
|
+
(Gemini worker is optional; add \`gemini\` explicitly, e.g. --workers claude,codex,gemini,report-writer)
|
|
91
91
|
--lead-model Model for Claude lead. Default: OKSTRA_DEFAULT_LEAD_MODEL or opus
|
|
92
92
|
--claude-model Model for Claude worker. Default: OKSTRA_DEFAULT_CLAUDE_MODEL or opus
|
|
93
93
|
--codex-model Model for Codex worker. Default: OKSTRA_DEFAULT_CODEX_MODEL or gpt-5.5
|
|
94
94
|
--gemini-model Model for Gemini worker. Default: OKSTRA_DEFAULT_GEMINI_MODEL or auto
|
|
95
95
|
--report-writer-model
|
|
96
96
|
Model for report writer worker. Default: OKSTRA_DEFAULT_REPORT_WRITER_MODEL or lead model default
|
|
97
|
+
--lead-runtime Lead runtime adapter. Default: claude-code.
|
|
98
|
+
codex is currently render-only and records Codex adapter
|
|
99
|
+
metadata in prepared artifacts without dispatching workers.
|
|
97
100
|
--executor Provider that performs the Executor role during --task-type=implementation.
|
|
98
101
|
One of: claude | codex | gemini. Default: OKSTRA_DEFAULT_EXECUTOR or claude.
|
|
99
102
|
The Executor is the only worker allowed to mutate project files; the other two
|
|
@@ -143,4 +146,3 @@ interactive behavior:
|
|
|
143
146
|
If --yes is provided, $DISPLAY_TOOL_NAME skips prompting and confirmation and requires all required arguments up front.
|
|
144
147
|
USAGE_EOF
|
|
145
148
|
}
|
|
146
|
-
|
package/runtime/bin/okstra.sh
CHANGED
|
@@ -115,6 +115,7 @@ PY_ARGS=(
|
|
|
115
115
|
[[ -n "${CODEX_MODEL_OVERRIDE-}" ]] && PY_ARGS+=(--codex-model "$CODEX_MODEL_OVERRIDE")
|
|
116
116
|
[[ -n "${GEMINI_MODEL_OVERRIDE-}" ]] && PY_ARGS+=(--gemini-model "$GEMINI_MODEL_OVERRIDE")
|
|
117
117
|
[[ -n "${REPORT_WRITER_MODEL_OVERRIDE-}" ]] && PY_ARGS+=(--report-writer-model "$REPORT_WRITER_MODEL_OVERRIDE")
|
|
118
|
+
[[ -n "${LEAD_RUNTIME-}" ]] && PY_ARGS+=(--lead-runtime "$LEAD_RUNTIME")
|
|
118
119
|
[[ -n "${EXECUTOR_OVERRIDE-}" ]] && PY_ARGS+=(--executor "$EXECUTOR_OVERRIDE")
|
|
119
120
|
[[ -n "${CRITIC_CHOICE-}" ]] && PY_ARGS+=(--critic "$CRITIC_CHOICE")
|
|
120
121
|
[[ -n "${RELATED_TASKS_RAW-}" ]] && PY_ARGS+=(--related-tasks "$RELATED_TASKS_RAW")
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# okstra — {{TASK_KEY}}
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
{{LEAD_INTRO_LINE}}
|
|
4
|
+
{{LEAD_BOOTSTRAP_INSTRUCTION}}
|
|
5
5
|
|
|
6
6
|
## Progress reporting (BLOCKING)
|
|
7
7
|
|
|
@@ -28,13 +28,7 @@ Emit one `PROGRESS: <phase-id> <verb-phrase>` line as plain user-facing text at
|
|
|
28
28
|
- All other paths in this prompt are relative to this root unless they begin with `/`.
|
|
29
29
|
- When dispatching workers, you MUST include this absolute root in every worker prompt header so that workers do not depend on inherited cwd to resolve relative paths.
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
- The `runs/<phase>/prompts/<worker>-worker-prompt-*.md` files referenced in `task-manifest.json → artifacts.workerPromptPathByWorkerId` are **NOT** rendered by the okstra runtime. Those paths are the *assigned* locations where the prompt history MUST be written at dispatch time.
|
|
34
|
-
- Therefore: at the start of every phase the prompts/ directory is normally empty (or contains only previously-dispatched workers' files). This is expected. Do NOT narrate it as "missing", "누락", or "not yet rendered" — it just means dispatch has not happened yet.
|
|
35
|
-
- Before dispatching any required worker, **you (the lead) construct the worker prompt and persist it to the assigned absolute path using `Write`** (per `okstra-team-contract` rule 6). Only after persisting do you call the worker subagent (Agent tool / Codex / Gemini wrapper). The wrapper subagents will also re-write the same file on their end; the double-write is intentional and idempotent.
|
|
36
|
-
- Do not "check if the file exists and skip dispatch" — file presence is not a signal to skip. Worker selection and skipping rules come from team-state, never from prompts/ directory contents.
|
|
37
|
-
- **Worker Preamble Path (single anchor — replaces inlined `[Required reading]` and `[Error reporting]` blocks).** Every worker prompt you construct MUST include the anchor header `**Worker Preamble Path:** {{WORKER_PROMPT_PREAMBLE_PATH}}`. The file at that path is the canonical SSOT for Required Reading + Error Reporting + Output sections; workers Read it end-to-end before producing output. Do NOT re-inline those blocks into worker prompt bodies — that is the legacy ~80-line dispatch boilerplate that this anchor is designed to replace.
|
|
31
|
+
{{WORKER_DISPATCH_GUIDANCE}}
|
|
38
32
|
|
|
39
33
|
## Manifests
|
|
40
34
|
|
|
@@ -43,10 +37,7 @@ Emit one `PROGRESS: <phase-id> <verb-phrase>` line as plain user-facing text at
|
|
|
43
37
|
- Active run context: `{{ACTIVE_RUN_CONTEXT_RELATIVE_PATH}}`
|
|
44
38
|
- Analysis packet: `{{ANALYSIS_PACKET_RELATIVE_PATH}}`
|
|
45
39
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
- Session ID: `{{CLAUDE_SESSION_ID}}`
|
|
49
|
-
- Resume: `{{CLAUDE_RESUME_COMMAND_RELATIVE_PATH}}`
|
|
40
|
+
{{LEAD_SESSION_BLOCK}}
|
|
50
41
|
|
|
51
42
|
## Run Paths
|
|
52
43
|
|
|
@@ -13,6 +13,12 @@
|
|
|
13
13
|
- the reporter's symptom description in `Source Material` is the ground truth for what to reproduce. Do not paraphrase it when stating the symptom in the report; quote it.
|
|
14
14
|
- any `intent-inference` augmentation that re-characterises the symptom (e.g. classifying "가끔 안 됨" as "intermittent failure on a specific code path") is a **hypothesis**, not a confirmed symptom. If `[CONFIRMED …]` appears on the matching `intent-check:` row, treat the confirmation as the symptom; otherwise, follow the precondition's `skipped` branch above and keep the inference labelled as hypothesis in the root-cause analysis.
|
|
15
15
|
- `conversion-block:` rows mean the brief could not map a reporter statement to project vocabulary; never attempt to invent the missing mapping in this phase — the precondition above already handled them.
|
|
16
|
+
- Diagnosis loop:
|
|
17
|
+
- **Symptom lock:** state the reporter's symptom verbatim, then translate it into one observable failure condition. If the observable condition cannot be derived from the brief, make that the first blocker instead of guessing.
|
|
18
|
+
- **Reproduction status:** classify the run as `reproduced`, `not-reproduced`, or `blocked-before-repro`. Cite the command/log/file evidence used. If no command can be run safely in this phase, explain the read-only evidence path and the exact material needed next.
|
|
19
|
+
- **Falsifiable cause candidates:** every root-cause candidate must include supporting evidence, the strongest falsifying evidence checked, confidence, and the next diagnostic action that would disprove it. A candidate that cannot be falsified is too vague for this phase.
|
|
20
|
+
- **Sharp next diagnostic:** end with the single highest-value diagnostic command, log capture, or file inspection that should happen next, plus the expected signal that would confirm or reject the leading cause.
|
|
21
|
+
- **Fix-design boundary:** do not design the implementation fix beyond what is necessary to validate the cause. If the cause is credible, route to `implementation-planning` with the verified evidence; if the cause is still unclear, route to another `error-analysis` run with the next diagnostic.
|
|
16
22
|
- Primary focus areas:
|
|
17
23
|
- symptom and trigger clarification
|
|
18
24
|
- root-cause candidates
|
|
@@ -20,6 +20,11 @@
|
|
|
20
20
|
- per-candidate evidence (path:line) and scope mapping
|
|
21
21
|
- per-candidate severity / effort / recommended-next-phase
|
|
22
22
|
- convergence classification (full / partial / contested / worker-unique) across workers
|
|
23
|
+
- Worker diversity rule:
|
|
24
|
+
- every analyser inspects every priority lens, but each starts with a different primary pass so the run does not rely on model randomness for diversity. Order lenses exactly as they appear in the brief; `claude` starts at lens 1, `codex` at lens 2, and `gemini` at lens 3, wrapping around when fewer lenses are present.
|
|
25
|
+
- before broadening to the remaining lenses, each worker must either produce at least one candidate from its primary pass or record a no-candidate rationale with the highest-signal path:line evidence it inspected.
|
|
26
|
+
- two workers' candidates are the same candidate only when they cite the same underlying design/code problem and the same remediation direction. Shared evidence paths alone are not enough to merge; keep distinct failure modes distinct.
|
|
27
|
+
- when a candidate from one worker overlaps another worker's evidence, convergence must verify whether it is duplicate, broader/narrower, or conflicting. Do not collapse contested candidates just to meet the candidate cap.
|
|
23
28
|
- Phase 1.5 — Lead reflect-back grilling (runs after Phase 1 context loading and before Phase 4 worker dispatch):
|
|
24
29
|
- Lead inspects scan-scope paths via `ls` / `Grep` / `Read` to map modules, entry points, dependencies, approximate LOC, and recent commit patterns.
|
|
25
30
|
- Lead emits a single reflect-back message covering: (a) understood scope per path (one-line summary), (b) understood meaning of each priority lens in this scope, (c) understood out-of-scope rationale, (d) ordered list of N open questions.
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
- the lead MUST confirm `git log --oneline <base>..HEAD` contains at least one implementation commit. If it is empty, the run MUST end with status `blocked` and route back to `implementation`.
|
|
21
21
|
- User interaction protocol (Claude lead — performed in order, using `AskUserQuestion` or the equivalent interactive prompt):
|
|
22
22
|
1. **Action selection** — present three choices and capture exactly one:
|
|
23
|
-
- `local only` — record the accepted, already-committed branch and end without push or PR.
|
|
23
|
+
- `local only` — complete the handoff as a local delivery record: record the accepted, already-committed branch and end without push or PR.
|
|
24
24
|
- `push + PR` — push the feature branch, then open or reuse a pull request.
|
|
25
|
-
- `skip` — record
|
|
25
|
+
- `skip` — cancel delivery actions for now: record that release-handoff was intentionally skipped and end the run without any git command.
|
|
26
26
|
If the user picks `skip`, route directly to the final-report self-review pass.
|
|
27
27
|
- **stage-group mode order**: G1 base branch first (same options as Q2 — the dependency-closure check needs `origin/<base>`), then G2 stage confirmation, then assemble, then Q2b/Q3 as usual with the collector branch as the PR head.
|
|
28
28
|
1g. **G2 — stage confirmation**: the stage selection already happened before the run (wizard `handoff_stage_pick`, or the CLI `--stages` flag) and is fixed in `HANDOFF_STAGES`. Display it as a one-line confirmation (`PR 대상 stage: <csv> — 진행합니다`) and proceed; do NOT re-ask the multi-select. Only if `HANDOFF_MODE` is `stage-group` but `HANDOFF_STAGES` is empty (defensive, should not happen) run `okstra handoff eligible --plan-run-root <plan-run-root> --approved-plan <approved plan path>` and ask the user to pick from the eligible stages.
|
|
@@ -27,12 +27,28 @@ PROFILE_SECTIONS = (
|
|
|
27
27
|
"Clarification request policy",
|
|
28
28
|
)
|
|
29
29
|
PROFILE_SECTIONS_BY_TASK_TYPE = {
|
|
30
|
+
"requirements-discovery": (
|
|
31
|
+
"Fan-out",
|
|
32
|
+
"Decision-tree walk",
|
|
33
|
+
),
|
|
34
|
+
"error-analysis": (
|
|
35
|
+
"Diagnosis loop",
|
|
36
|
+
),
|
|
30
37
|
"implementation-planning": (
|
|
31
38
|
"Section heading contract",
|
|
32
39
|
"Required deliverable shape",
|
|
33
40
|
"No-placeholder rule",
|
|
34
41
|
"Self-review pass before finalising the report",
|
|
35
42
|
),
|
|
43
|
+
"final-verification": (
|
|
44
|
+
"Required deliverable shape",
|
|
45
|
+
"Self-review pass before finalising the report",
|
|
46
|
+
),
|
|
47
|
+
"improvement-discovery": (
|
|
48
|
+
"Phase 1.5 — Lead reflect-back grilling",
|
|
49
|
+
"Worker diversity rule",
|
|
50
|
+
"Decision-tree walk",
|
|
51
|
+
),
|
|
36
52
|
}
|
|
37
53
|
CLARIFICATION_SECTIONS = (
|
|
38
54
|
"Clarification Items",
|
|
@@ -261,6 +277,7 @@ def _top_level_bullet_heading(line: str) -> str:
|
|
|
261
277
|
if not line.startswith("- ") or ":" not in line:
|
|
262
278
|
return ""
|
|
263
279
|
label = line[2:].split(":", 1)[0].strip().strip("*")
|
|
280
|
+
label = label.split(" (", 1)[0].strip()
|
|
264
281
|
return label
|
|
265
282
|
|
|
266
283
|
|