okstra 0.111.0 → 0.112.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 +2 -2
- package/README.md +2 -2
- package/bin/okstra +7 -1
- package/docs/for-ai/README.md +2 -2
- package/docs/for-ai/skills/okstra-brief.md +2 -3
- package/docs/for-ai/skills/okstra-container-build.md +2 -3
- package/docs/for-ai/skills/okstra-inspect.md +5 -12
- package/docs/for-ai/skills/okstra-rollup.md +3 -4
- package/docs/for-ai/skills/okstra-run.md +3 -5
- package/docs/for-ai/skills/okstra-schedule.md +2 -7
- package/docs/for-ai/skills/okstra-setup.md +1 -1
- package/docs/kr/architecture/storage-model.md +1 -2
- package/docs/kr/architecture.md +2 -2
- package/docs/kr/cli.md +4 -2
- package/docs/project-structure-overview.md +5 -3
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/prompts/coding-preflight/overview.md +3 -1
- package/runtime/prompts/launch.template.md +1 -5
- package/runtime/prompts/lead/context-loader.md +2 -4
- package/runtime/prompts/lead/convergence.md +11 -240
- package/runtime/prompts/lead/okstra-lead-contract.md +70 -34
- package/runtime/prompts/lead/plan-body-verification.md +240 -0
- package/runtime/prompts/lead/report-writer.md +7 -7
- package/runtime/prompts/lead/team-contract.md +15 -17
- package/runtime/prompts/profiles/_common-contract.md +1 -37
- package/runtime/prompts/profiles/_implementation-executor.md +2 -2
- package/runtime/prompts/profiles/_implementation-verifier.md +1 -1
- package/runtime/prompts/profiles/final-verification.md +1 -1
- package/runtime/prompts/profiles/implementation-planning.md +2 -2
- package/runtime/prompts/profiles/implementation.md +1 -1
- package/runtime/python/okstra_ctl/path_hints.py +1 -0
- package/runtime/python/okstra_ctl/paths.py +3 -0
- package/runtime/python/okstra_ctl/render.py +8 -0
- package/runtime/python/okstra_ctl/set_work_status.py +147 -0
- package/runtime/python/okstra_ctl/team_reconcile.py +1 -1
- package/runtime/skills/okstra-brief/SKILL.md +32 -176
- package/runtime/skills/okstra-brief/references/reporter-confirmations.md +71 -0
- package/runtime/skills/okstra-brief/references/tracker-recursion.md +90 -0
- package/runtime/skills/okstra-container-build/SKILL.md +7 -20
- package/runtime/skills/okstra-graphify/SKILL.md +8 -8
- package/runtime/skills/okstra-inspect/SKILL.md +27 -43
- package/runtime/skills/okstra-rollup/SKILL.md +6 -6
- package/runtime/skills/okstra-run/SKILL.md +7 -16
- package/runtime/skills/okstra-schedule/SKILL.md +64 -419
- package/runtime/skills/okstra-setup/SKILL.md +25 -223
- package/runtime/skills/okstra-setup/references/project-config.md +188 -0
- package/runtime/templates/reports/schedule.template.md +2 -2
- package/runtime/templates/worker-prompt-preamble.md +1 -1
- package/runtime/validators/validate-run.py +7 -7
- package/src/cli-registry.mjs +14 -0
- package/src/commands/inspect/set-work-status.mjs +31 -0
- package/src/commands/lifecycle/check-project.mjs +68 -56
- package/src/commands/lifecycle/install.mjs +1 -0
- package/src/commands/lifecycle/preflight.mjs +82 -0
|
@@ -117,26 +117,15 @@ as source material, and never writes them. Decision files (when raised by
|
|
|
117
117
|
via `implementation`):
|
|
118
118
|
`<PROJECT_ROOT>/.okstra/decisions/<NNNN>-<slug>.md`.
|
|
119
119
|
|
|
120
|
-
## Step 0:
|
|
120
|
+
## Step 0: Preflight
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
Every Bash command in this skill is a **separate Bash tool call** starting with the literal token `okstra` (never wrapped in `if`/`eval`/`export`/`$(...)`/`VAR=...`/`||`/`&&`/`npx` — a non-literal leading token defeats the `Bash(okstra:*)` permission match).
|
|
123
123
|
|
|
124
124
|
```bash
|
|
125
|
-
okstra
|
|
125
|
+
okstra preflight --runtime claude-code --json
|
|
126
126
|
```
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
```bash
|
|
131
|
-
okstra check-project --json
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
Parse the JSON from stdout:
|
|
135
|
-
|
|
136
|
-
- `ok: true` → use `projectRoot` from the JSON output. Carry it as a literal string into the steps below.
|
|
137
|
-
- `ok: false` → tell the user: "this project has no okstra setup. Run `/okstra-setup` first." Then stop.
|
|
138
|
-
|
|
139
|
-
> If the `okstra` binary is not on `PATH` at all, the commands above will not run. In that case tell the user verbatim: "okstra not installed — run `/okstra-setup` first." Do **not** try to invoke `npx -y okstra@latest ...` from this skill — `npx` is not on the literal-token allow-list this skill targets and will force a confirmation prompt on every subsequent call.
|
|
128
|
+
Parse the stdout JSON. `ok: true` → carry `projectRoot` as a literal string into the steps below. `ok: false` (or `okstra` not on `PATH` at all) → tell the user: "okstra not set up — run `/okstra-setup` first." Then stop. If the call fails with `unknown command: preflight`, the `okstra` binary on PATH predates this skill — tell the user to update it (`npm i -g okstra@latest`), then stop (`/okstra-setup` does not update the binary). Do **not** try `npx -y okstra@latest ...` as a fallback.
|
|
140
129
|
|
|
141
130
|
## Step 1: Choose input source
|
|
142
131
|
|
|
@@ -234,86 +223,15 @@ Order of operations:
|
|
|
234
223
|
preserved)`).
|
|
235
224
|
|
|
236
225
|
6. **Sub-ticket / child-issue / sub-task handling — recursive**:
|
|
237
|
-
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
Capture each as a child candidate.
|
|
247
|
-
2. **tracked / sub-issue GraphQL** — for GitHub Projects v2
|
|
248
|
-
"tracked issues" / sub-issue relations, the REST `gh issue view`
|
|
249
|
-
response does NOT carry them. Query GraphQL explicitly, e.g.
|
|
250
|
-
`gh api graphql -f query='query($o:String!,$r:String!,$n:Int!){repository(owner:$o,name:$r){issue(number:$n){trackedIssues(first:50){nodes{number repository{nameWithOwner}}} subIssues:trackedInIssues(first:50){nodes{number repository{nameWithOwner}}}}}}' -f o=<owner> -f r=<repo> -F n=<num>`.
|
|
251
|
-
If the GraphQL request fails (auth scope missing, feature
|
|
252
|
-
unavailable on this repo, network error), **do NOT silently
|
|
253
|
-
continue with full recursion**. Disable the "Generate the full
|
|
254
|
-
tree recursively" option for this branch, default to
|
|
255
|
-
`Parent only; list children in Related Artifacts and Related Task
|
|
256
|
-
Graph`, and surface the GraphQL failure to the user in one line so
|
|
257
|
-
they can decide whether to paste child bodies manually.
|
|
258
|
-
- Notion: child pages / sub-pages
|
|
259
|
-
- If there is **one or more** child, ask **once at the top parent**:
|
|
260
|
-
- `AskUserQuestion` (single-select)
|
|
261
|
-
- **Label**: `"This ticket has sub-tickets. How should the child tree be handled?"`
|
|
262
|
-
- **Options**:
|
|
263
|
-
1. `Full tree` (recommended) — walk children, grandchildren, …
|
|
264
|
-
via BFS/DFS and emit one brief per node.
|
|
265
|
-
2. `Parent only` — single brief. Children are not fetched; their
|
|
266
|
-
keys/URLs are recorded under Related Artifacts and as `parent-of`
|
|
267
|
-
rows in Related Task Graph.
|
|
268
|
-
3. `Selected` — multi-select the direct children; for each chosen
|
|
269
|
-
child, apply option-1 policy recursively to that branch.
|
|
270
|
-
- For options 1 / 3, **recurse into Step 1b sub-steps 3–5** for every
|
|
271
|
-
descendant. No depth limit. Maintain a visited set of
|
|
272
|
-
`<tracker>:<ticket-id>` to prevent cycles; on revisit, do not emit a
|
|
273
|
-
new brief — only add a link back to the existing brief.
|
|
274
|
-
- **Visited-set across re-runs (rebuild from disk)** — the in-memory
|
|
275
|
-
visited set is per-run and disappears between invocations. When this
|
|
276
|
-
skill runs again over a tree that already has briefs on disk, it MUST
|
|
277
|
-
reseed the visited set by scanning
|
|
278
|
-
`<PROJECT_ROOT>/.okstra/briefs/<task-group>/` recursively
|
|
279
|
-
and reading each brief's frontmatter `ticket-id` + `source-type`.
|
|
280
|
-
Reseed precedence:
|
|
281
|
-
1. On-disk frontmatter (`ticket-id` ≠ "") populates visited entries
|
|
282
|
-
as `<source-type>:<ticket-id>` — these win.
|
|
283
|
-
2. Step 2c collision policy (`Skip` / `Append timestamp` /
|
|
284
|
-
`Overwrite`) applies to any node whose path is already taken.
|
|
285
|
-
3. The fresh in-memory walk fills any gaps for tickets not yet on
|
|
286
|
-
disk.
|
|
287
|
-
A ticket present on disk is NOT refetched unless the user explicitly
|
|
288
|
-
answers `Overwrite` for that path.
|
|
289
|
-
- Each descendant's brief file at depth N is created under
|
|
290
|
-
`<task-group>/<sub/ nested N times>/<ticket-id>-<file-title>.md` per
|
|
291
|
-
Step 2b.
|
|
292
|
-
- Each node's `Related Artifacts` should list:
|
|
293
|
-
- The parent brief's relative path (`../<ticket-id>-<file-title>.md`)
|
|
294
|
-
- All direct children briefs' relative paths
|
|
295
|
-
(`sub/<ticket-id>-<file-title>.md`)
|
|
296
|
-
bidirectionally. (Non-direct ancestors/descendants are tracked via the
|
|
297
|
-
frontmatter `parent-id` chain.)
|
|
298
|
-
- Each generated brief's `Related Task Graph` should contain the same full
|
|
299
|
-
split topology, not only the current node's direct edges, so downstream
|
|
300
|
-
phases can start from any child brief without losing order or dependency
|
|
301
|
-
context. Use one row per source-backed edge with these columns:
|
|
302
|
-
`From | Relation | To | Direction | Source | Impact`.
|
|
303
|
-
- `From` / `To` use task key, brief id, tracker id, or URL. The edge
|
|
304
|
-
direction is `From` → `To`.
|
|
305
|
-
- `Relation` is one of `parent-of`, `child-of`, `depends-on`, `blocks`,
|
|
306
|
-
`blocked-by`, `follow-up-of`, `split-from`, `duplicates`, `related-to`.
|
|
307
|
-
- `Direction` is `directed` for parentage/ordering relations and
|
|
308
|
-
`undirected` for `duplicates` / `related-to`.
|
|
309
|
-
- `Source` names the evidence for the edge: tracker linked issue,
|
|
310
|
-
markdown task-list checkbox, reporter statement, manual split, or prior
|
|
311
|
-
okstra task.
|
|
312
|
-
- `Impact` states what the next phase must preserve, such as "run after
|
|
313
|
-
API contract" or "avoid duplicate implementation".
|
|
314
|
-
Do not invent graph edges from filename similarity or topic overlap; if a
|
|
315
|
-
relation is unclear, use `related-to` + `undirected` only when the source
|
|
316
|
-
explicitly says the items are related.
|
|
226
|
+
- If the fetched ticket response shows **any** child reference (Linear
|
|
227
|
+
`children`/`subIssues`, Jira `subtasks`/`issuelinks`, GitHub task-list
|
|
228
|
+
checkboxes or tracked/sub-issues, Notion child pages), **read
|
|
229
|
+
`references/tracker-recursion.md` next to this SKILL.md and follow it**
|
|
230
|
+
before writing any brief — it defines per-tracker child discovery
|
|
231
|
+
(including the GitHub GraphQL query and its failure handling), the
|
|
232
|
+
Full tree / Parent only / Selected picker, the cross-run visited-set
|
|
233
|
+
reseed from on-disk brief frontmatter, and the Related Artifacts /
|
|
234
|
+
Related Task Graph topology every emitted brief must carry.
|
|
317
235
|
- If there are no children, proceed with a single brief (depth 0).
|
|
318
236
|
|
|
319
237
|
### 1c. `Link URL`
|
|
@@ -584,13 +502,11 @@ project's domain.
|
|
|
584
502
|
|
|
585
503
|
## Step 4: Fill in missing fields (NO full interview)
|
|
586
504
|
|
|
587
|
-
> **Verbatim-source rule
|
|
588
|
-
>
|
|
589
|
-
>
|
|
590
|
-
>
|
|
591
|
-
>
|
|
592
|
-
> Questions` only.** brief is a pre-discovery artifact, not a PRD —
|
|
593
|
-
> decisions belong to later phases.
|
|
505
|
+
> **Verbatim-source rule** (the first non-negotiable at the top of this
|
|
506
|
+
> file): never modify Source Material by a single byte. **Anything learned
|
|
507
|
+
> by grilling in this step lands in `Augmentation` or `Open Questions`
|
|
508
|
+
> only.** brief is a pre-discovery artifact, not a PRD — decisions belong
|
|
509
|
+
> to later phases.
|
|
594
510
|
|
|
595
511
|
Inspect the synthesized brief draft. For each REQUIRED section below that is
|
|
596
512
|
empty or trivially thin **after** reading Source Material verbatim, ask **at
|
|
@@ -903,72 +819,16 @@ If the list is non-empty, run **one** `AskUserQuestion`:
|
|
|
903
819
|
`implementation-planning`); see each phase profile's "Brief
|
|
904
820
|
consumption" addendum.
|
|
905
821
|
|
|
906
|
-
### 6.5c.
|
|
907
|
-
|
|
908
|
-
For each pending row, formulate one question. Because the
|
|
909
|
-
`AskUserQuestion` tool caps options at 4 per call and questions per call
|
|
910
|
-
also at 4, split into batches of ≤ 4 questions.
|
|
911
|
-
|
|
912
|
-
**Cap — 12 questions per Step 6.5 run.** When the pending list
|
|
913
|
-
exceeds 12 rows, sort by priority and ask only the top 12 this round:
|
|
914
|
-
|
|
915
|
-
1. `conversion-block:` rows first (translation failure — highest
|
|
916
|
-
downstream risk).
|
|
917
|
-
2. `intent-check:` rows next, in the order they appear in `Open
|
|
918
|
-
Questions`.
|
|
919
|
-
|
|
920
|
-
Any rows beyond the cap are left unanswered in this run; set
|
|
921
|
-
`reporter-confirmations: partial` in the frontmatter and tell the user
|
|
922
|
-
which rows remain. The next `okstra-brief` re-run (or the downstream
|
|
923
|
-
phase that consumes `Blocks=next-phase`) handles the remainder.
|
|
924
|
-
|
|
925
|
-
Each question carries:
|
|
926
|
-
|
|
927
|
-
- The reporter-facing phrasing (plain language, no jargon).
|
|
928
|
-
- A recommended answer drawn from the brief's `intent-inference` /
|
|
929
|
-
`conversion-block:` content, marked `(Recommended)`.
|
|
930
|
-
- 2–3 alternative options when the answer space is naturally enumerable;
|
|
931
|
-
otherwise a free-text fallback.
|
|
932
|
-
|
|
933
|
-
### 6.5d. Record verbatim
|
|
934
|
-
|
|
935
|
-
Create a new top-level section `## Reporter Confirmations` in the brief
|
|
936
|
-
(if not present) with one subsection per answered row:
|
|
937
|
-
|
|
938
|
-
```markdown
|
|
939
|
-
## Reporter Confirmations
|
|
940
|
-
|
|
941
|
-
### RC-1 — <intent-check: or conversion-block: row id / topic>
|
|
942
|
-
- asked: <YYYY-MM-DD HH:MM>
|
|
943
|
-
- linked-row: `<exact Open Questions row text>`
|
|
944
|
-
- answer (verbatim):
|
|
945
|
-
|
|
946
|
-
> <reporter's answer, byte-for-byte>
|
|
947
|
-
```
|
|
948
|
-
|
|
949
|
-
Mark the linked `Open Questions` row by appending `[CONFIRMED <YYYY-MM-DD> → RC-N]` to the end of the row's line. Do NOT delete the row — the
|
|
950
|
-
`CONFIRMED` marker keeps the audit trail intact.
|
|
951
|
-
|
|
952
|
-
For every `intent-inference` augmentation whose paired `intent-check:`
|
|
953
|
-
was confirmed, add one new line directly below the `> augmented:
|
|
954
|
-
intent-inference …` blockquote:
|
|
955
|
-
|
|
956
|
-
```
|
|
957
|
-
> confirmed-by-reporter: RC-N — <one-line summary of confirmation>
|
|
958
|
-
```
|
|
959
|
-
|
|
960
|
-
This converts the inference from "unverified hypothesis" to "verified
|
|
961
|
-
hypothesis" without rewriting the original augmentation.
|
|
962
|
-
|
|
963
|
-
### 6.5e. Frontmatter state
|
|
964
|
-
|
|
965
|
-
Update `reporter-confirmations` in the brief frontmatter:
|
|
822
|
+
### 6.5c–e. Collect, record, and set frontmatter state
|
|
966
823
|
|
|
967
|
-
|
|
968
|
-
-
|
|
969
|
-
|
|
970
|
-
-
|
|
971
|
-
|
|
824
|
+
When 6.5b answered "Yes — collect now", **read
|
|
825
|
+
`references/reporter-confirmations.md` next to this SKILL.md and follow it**:
|
|
826
|
+
it defines the ≤ 4-question batching, the 12-question cap with
|
|
827
|
+
`conversion-block:`-first priority, the `## Reporter Confirmations` RC-N
|
|
828
|
+
record shape with `[CONFIRMED <date> → RC-N]` row markers and
|
|
829
|
+
`> confirmed-by-reporter:` blockquote lines, and the final
|
|
830
|
+
`reporter-confirmations` frontmatter value (`complete` / `partial` /
|
|
831
|
+
`skipped`).
|
|
972
832
|
|
|
973
833
|
Step 6.5 ends here. The brief now has either zero pending reporter-only
|
|
974
834
|
rows (`complete` / `partial` with remainder in the same file) or an
|
|
@@ -1038,11 +898,11 @@ started.
|
|
|
1038
898
|
stays under `<PROJECT_ROOT>/.okstra/` — briefs in `.okstra/briefs/`, glossary
|
|
1039
899
|
in `.okstra/glossary.md` (Step 4.5). Paths outside that subtree are read-only
|
|
1040
900
|
source material, and only when the reporter cited them.
|
|
1041
|
-
- **Verbatim source
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
901
|
+
- **Verbatim source** (the two non-negotiables at the top of this file
|
|
902
|
+
govern): no line budget overrides them — if source content is large,
|
|
903
|
+
preserve it exactly as separate `Source Material` entries; if a tool
|
|
904
|
+
returns a truncated body, ask the user for the missing content or emit a
|
|
905
|
+
`conversion-block:` row. Never silently excerpt or summarize.
|
|
1046
906
|
- **No template author-guidance in the artifact body.** The Step 5
|
|
1047
907
|
template carries author guidance in HTML comments (`<!-- ... -->`);
|
|
1048
908
|
**strip every such comment when writing the brief** — the final artifact
|
|
@@ -1061,10 +921,6 @@ started.
|
|
|
1061
921
|
paste.
|
|
1062
922
|
- Never fabricate content for empty sections; use `_(none)_`.
|
|
1063
923
|
- Echo each `AskUserQuestion` outcome on one short line.
|
|
1064
|
-
- No line budget overrides the verbatim-source rule. If source content is
|
|
1065
|
-
large, preserve it exactly as separate `Source Material` entries; if a
|
|
1066
|
-
tool only returns a truncated body, ask the user for the missing content
|
|
1067
|
-
or emit a `conversion-block:` row. Never silently excerpt or summarize.
|
|
1068
924
|
|
|
1069
925
|
## Failure Modes
|
|
1070
926
|
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Reporter batch confirmation — collection procedure (Step 6.5c–e)
|
|
2
|
+
|
|
3
|
+
Read this only when Step 6.5b answered "Yes — collect now" for a non-empty
|
|
4
|
+
pending list of `intent-check:` / `conversion-block:` rows.
|
|
5
|
+
|
|
6
|
+
## 6.5c. Batch the questions
|
|
7
|
+
|
|
8
|
+
For each pending row, formulate one question. Because the `AskUserQuestion`
|
|
9
|
+
tool caps options at 4 per call and questions per call also at 4, split into
|
|
10
|
+
batches of ≤ 4 questions.
|
|
11
|
+
|
|
12
|
+
**Cap — 12 questions per Step 6.5 run.** When the pending list exceeds 12
|
|
13
|
+
rows, sort by priority and ask only the top 12 this round:
|
|
14
|
+
|
|
15
|
+
1. `conversion-block:` rows first (translation failure — highest downstream
|
|
16
|
+
risk).
|
|
17
|
+
2. `intent-check:` rows next, in the order they appear in `Open Questions`.
|
|
18
|
+
|
|
19
|
+
Any rows beyond the cap are left unanswered in this run; set
|
|
20
|
+
`reporter-confirmations: partial` in the frontmatter and tell the user which
|
|
21
|
+
rows remain. The next `okstra-brief` re-run (or the downstream phase that
|
|
22
|
+
consumes `Blocks=next-phase`) handles the remainder.
|
|
23
|
+
|
|
24
|
+
Each question carries:
|
|
25
|
+
|
|
26
|
+
- The reporter-facing phrasing (plain language, no jargon).
|
|
27
|
+
- A recommended answer drawn from the brief's `intent-inference` /
|
|
28
|
+
`conversion-block:` content, marked `(Recommended)`.
|
|
29
|
+
- 2–3 alternative options when the answer space is naturally enumerable;
|
|
30
|
+
otherwise a free-text fallback.
|
|
31
|
+
|
|
32
|
+
## 6.5d. Record verbatim
|
|
33
|
+
|
|
34
|
+
Create a new top-level section `## Reporter Confirmations` in the brief (if
|
|
35
|
+
not present) with one subsection per answered row:
|
|
36
|
+
|
|
37
|
+
```markdown
|
|
38
|
+
## Reporter Confirmations
|
|
39
|
+
|
|
40
|
+
### RC-1 — <intent-check: or conversion-block: row id / topic>
|
|
41
|
+
- asked: <YYYY-MM-DD HH:MM>
|
|
42
|
+
- linked-row: `<exact Open Questions row text>`
|
|
43
|
+
- answer (verbatim):
|
|
44
|
+
|
|
45
|
+
> <reporter's answer, byte-for-byte>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Mark the linked `Open Questions` row by appending
|
|
49
|
+
`[CONFIRMED <YYYY-MM-DD> → RC-N]` to the end of the row's line. Do NOT delete
|
|
50
|
+
the row — the `CONFIRMED` marker keeps the audit trail intact.
|
|
51
|
+
|
|
52
|
+
For every `intent-inference` augmentation whose paired `intent-check:` was
|
|
53
|
+
confirmed, add one new line directly below the `> augmented: intent-inference …`
|
|
54
|
+
blockquote:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
> confirmed-by-reporter: RC-N — <one-line summary of confirmation>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
This converts the inference from "unverified hypothesis" to "verified
|
|
61
|
+
hypothesis" without rewriting the original augmentation.
|
|
62
|
+
|
|
63
|
+
## 6.5e. Frontmatter state
|
|
64
|
+
|
|
65
|
+
Update `reporter-confirmations` in the brief frontmatter:
|
|
66
|
+
|
|
67
|
+
- `complete` — every pending row was answered.
|
|
68
|
+
- `partial` — some rows answered, some skipped within this run.
|
|
69
|
+
- `skipped` — user picked option 2 in 6.5b.
|
|
70
|
+
- `pending` — should never appear at this point; if it does, treat the brief
|
|
71
|
+
as not yet handed off and refuse to proceed.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Sub-ticket / child-issue recursion (tracker sources)
|
|
2
|
+
|
|
3
|
+
Read this only when a fetched tracker ticket shows one or more child references
|
|
4
|
+
(okstra-brief Step 1b sub-step 6). It defines how the child tree is discovered,
|
|
5
|
+
which briefs are emitted, and how re-runs stay idempotent.
|
|
6
|
+
|
|
7
|
+
## 1. Discover child references per tracker
|
|
8
|
+
|
|
9
|
+
- Linear: `children` / `subIssues` field.
|
|
10
|
+
- Jira: `subtasks` (or `issuelinks` with the `is parent of` relation).
|
|
11
|
+
- GitHub: `gh issue view --json title,body,comments,labels,state` only returns
|
|
12
|
+
the issue body and comments — child relations are NOT in that JSON. Resolve
|
|
13
|
+
children via two paths:
|
|
14
|
+
1. **task-list parsing** — scan the fetched body and comments for markdown
|
|
15
|
+
task-list checkboxes referencing other issues (`- [ ] #NNN`,
|
|
16
|
+
`- [x] owner/repo#NNN`, `- [ ] https://github.com/...`). Capture each as a
|
|
17
|
+
child candidate.
|
|
18
|
+
2. **tracked / sub-issue GraphQL** — for GitHub Projects v2 "tracked issues" /
|
|
19
|
+
sub-issue relations, query GraphQL explicitly, e.g.
|
|
20
|
+
`gh api graphql -f query='query($o:String!,$r:String!,$n:Int!){repository(owner:$o,name:$r){issue(number:$n){trackedIssues(first:50){nodes{number repository{nameWithOwner}}} subIssues:trackedInIssues(first:50){nodes{number repository{nameWithOwner}}}}}}' -f o=<owner> -f r=<repo> -F n=<num>`.
|
|
21
|
+
If the GraphQL request fails (auth scope missing, feature unavailable,
|
|
22
|
+
network error), do NOT silently continue with full recursion: disable the
|
|
23
|
+
"Full tree" option for this branch, default to `Parent only`, and surface
|
|
24
|
+
the GraphQL failure to the user in one line so they can decide whether to
|
|
25
|
+
paste child bodies manually.
|
|
26
|
+
- Notion: child pages / sub-pages.
|
|
27
|
+
|
|
28
|
+
## 2. Ask once at the top parent
|
|
29
|
+
|
|
30
|
+
If there is one or more child, `AskUserQuestion` (single-select):
|
|
31
|
+
|
|
32
|
+
- **Label**: `"This ticket has sub-tickets. How should the child tree be handled?"`
|
|
33
|
+
- **Options**:
|
|
34
|
+
1. `Full tree` (recommended) — walk children, grandchildren, … via BFS/DFS
|
|
35
|
+
and emit one brief per node.
|
|
36
|
+
2. `Parent only` — single brief. Children are not fetched; their keys/URLs are
|
|
37
|
+
recorded under Related Artifacts and as `parent-of` rows in Related Task
|
|
38
|
+
Graph.
|
|
39
|
+
3. `Selected` — multi-select the direct children; for each chosen child,
|
|
40
|
+
apply option-1 policy recursively to that branch.
|
|
41
|
+
|
|
42
|
+
For options 1 / 3, recurse into Step 1b sub-steps 3–5 for every descendant. No
|
|
43
|
+
depth limit. Maintain a visited set of `<tracker>:<ticket-id>` to prevent
|
|
44
|
+
cycles; on revisit, do not emit a new brief — only add a link back to the
|
|
45
|
+
existing brief.
|
|
46
|
+
|
|
47
|
+
## 3. Visited-set across re-runs (rebuild from disk)
|
|
48
|
+
|
|
49
|
+
The in-memory visited set is per-run. When this skill runs again over a tree
|
|
50
|
+
that already has briefs on disk, reseed the visited set by scanning
|
|
51
|
+
`<PROJECT_ROOT>/.okstra/briefs/<task-group>/` recursively and reading each
|
|
52
|
+
brief's frontmatter `ticket-id` + `source-type`. Reseed precedence:
|
|
53
|
+
|
|
54
|
+
1. On-disk frontmatter (`ticket-id` ≠ "") populates visited entries as
|
|
55
|
+
`<source-type>:<ticket-id>` — these win.
|
|
56
|
+
2. Step 2c collision policy (`Skip` / `Append timestamp` / `Overwrite`) applies
|
|
57
|
+
to any node whose path is already taken.
|
|
58
|
+
3. The fresh in-memory walk fills any gaps for tickets not yet on disk.
|
|
59
|
+
|
|
60
|
+
A ticket present on disk is NOT refetched unless the user explicitly answers
|
|
61
|
+
`Overwrite` for that path.
|
|
62
|
+
|
|
63
|
+
## 4. Per-node output
|
|
64
|
+
|
|
65
|
+
- Each descendant's brief file at depth N is created under
|
|
66
|
+
`<task-group>/<sub/ nested N times>/<ticket-id>-<file-title>.md` per Step 2b.
|
|
67
|
+
- Each node's `Related Artifacts` lists, bidirectionally:
|
|
68
|
+
- the parent brief's relative path (`../<ticket-id>-<file-title>.md`)
|
|
69
|
+
- all direct children briefs' relative paths
|
|
70
|
+
(`sub/<ticket-id>-<file-title>.md`)
|
|
71
|
+
(Non-direct ancestors/descendants are tracked via the frontmatter
|
|
72
|
+
`parent-id` chain.)
|
|
73
|
+
- Each generated brief's `Related Task Graph` contains the same **full split
|
|
74
|
+
topology**, not only the current node's direct edges, so downstream phases
|
|
75
|
+
can start from any child brief without losing order or dependency context.
|
|
76
|
+
One row per source-backed edge with columns
|
|
77
|
+
`From | Relation | To | Direction | Source | Impact`:
|
|
78
|
+
- `From` / `To` use task key, brief id, tracker id, or URL; edge direction is
|
|
79
|
+
`From` → `To`.
|
|
80
|
+
- `Relation` is one of `parent-of`, `child-of`, `depends-on`, `blocks`,
|
|
81
|
+
`blocked-by`, `follow-up-of`, `split-from`, `duplicates`, `related-to`.
|
|
82
|
+
- `Direction` is `directed` for parentage/ordering relations, `undirected`
|
|
83
|
+
for `duplicates` / `related-to`.
|
|
84
|
+
- `Source` names the evidence for the edge: tracker linked issue, markdown
|
|
85
|
+
task-list checkbox, reporter statement, manual split, or prior okstra task.
|
|
86
|
+
- `Impact` states what the next phase must preserve (e.g. "run after API
|
|
87
|
+
contract", "avoid duplicate implementation").
|
|
88
|
+
Do not invent graph edges from filename similarity or topic overlap; if a
|
|
89
|
+
relation is unclear, use `related-to` + `undirected` only when the source
|
|
90
|
+
explicitly says the items are related.
|
|
@@ -16,18 +16,15 @@ Single entry point for the okstra user-test container runtime. okstra provisions
|
|
|
16
16
|
| `stop-watcher` | Reap the watcher/tail panes only — the containers keep running. |
|
|
17
17
|
| `down` | Tear down the containers (label query) and reap orphan watcher panes; `--all` covers every container group in the project. |
|
|
18
18
|
|
|
19
|
-
## Step 0:
|
|
19
|
+
## Step 0: Preflight (shared)
|
|
20
20
|
|
|
21
|
-
Before any sub-command, run
|
|
21
|
+
Before any sub-command, run one Bash tool call, starting with the literal token `okstra` (never wrapped in `if`/`eval`/`export`/`$(...)`/`VAR=...`/`||`/`&&`/`npx` — a non-literal leading token defeats the `Bash(okstra:*)` permission match):
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
2. `okstra check-project --json`
|
|
27
|
-
Reads the project from the current working directory. Parse the JSON from stdout. The shape is `{ok, projectRoot, projectJsonPath, projectId}`.
|
|
23
|
+
```bash
|
|
24
|
+
okstra preflight --runtime claude-code --json
|
|
25
|
+
```
|
|
28
26
|
|
|
29
|
-
|
|
30
|
-
- `ok: true` → carry `projectRoot` as a literal string and pass it as `--project-root <projectRoot>` to every `okstra container` call below.
|
|
27
|
+
Parse the stdout JSON. `ok: true` → carry `projectRoot` as a literal string and pass it as `--project-root <projectRoot>` to every `okstra container` call below. `ok: false` → tell the user to run `/okstra-setup` first, then stop. If the call fails with `unknown command: preflight`, the `okstra` binary on PATH predates this skill — tell the user to update it (`npm i -g okstra@latest`), then stop (`/okstra-setup` does not update the binary).
|
|
31
28
|
|
|
32
29
|
Docker itself must be installed and running for `up`/`status`/`down` to work. If a sub-command fails with a docker connection error, tell the user to start Docker (Desktop / daemon) and retry — do not try to start docker yourself.
|
|
33
30
|
|
|
@@ -35,7 +32,7 @@ Subsequent `okstra container <subcmd>` calls self-bootstrap their Python path, s
|
|
|
35
32
|
|
|
36
33
|
## Step 1: Dispatch by intent
|
|
37
34
|
|
|
38
|
-
Classify the user's request into one sub-command using the
|
|
35
|
+
Classify the user's request into one sub-command using the sub-command table above.
|
|
39
36
|
|
|
40
37
|
- Clear verbs route directly: "띄워/올려/up" → `up`; "상태/status" → `status`; "로그/logs" → `logs`; "watcher 멈춰/stop-watcher" → `stop-watcher`; "내려/down" → `down`.
|
|
41
38
|
- If the request is ambiguous (e.g. "okstra container 좀 봐줘"), present a numbered picker. Recommend the 1–2 most likely facets first, and make the **last option always "직접 입력"** so the user can name any facet:
|
|
@@ -61,8 +58,6 @@ Every sub-command needs a **task-key** (`<project-id>:<task-group>:<task-id>`)
|
|
|
61
58
|
|
|
62
59
|
## up
|
|
63
60
|
|
|
64
|
-
Trigger phrases: "okstra container up", "컨테이너 띄워", "컨테이너 올려", "유저 테스트 환경 띄워", "docker compose 올려줘", "이 task 컨테이너로 띄워".
|
|
65
|
-
|
|
66
61
|
Brings up the task's container group: integrates the implementation stages into the task worktree, synthesizes the compose env override, runs `docker compose up -d`, polls healthchecks, and attaches a tmux watcher pane.
|
|
67
62
|
|
|
68
63
|
**Preconditions** (state them if unmet, do not guess):
|
|
@@ -84,8 +79,6 @@ After a successful `up`, tell the user how to reach the running build (the compo
|
|
|
84
79
|
|
|
85
80
|
## status
|
|
86
81
|
|
|
87
|
-
Trigger phrases: "okstra container status", "컨테이너 상태", "컨테이너 떠 있어?", "container status".
|
|
88
|
-
|
|
89
82
|
Reports the running containers (queried by run-trace label — the source of truth for "is it up") plus the watcher metadata recorded in the registry.
|
|
90
83
|
|
|
91
84
|
```bash
|
|
@@ -106,8 +99,6 @@ If `containers` is empty, say the group is not running and offer `up`. Treat the
|
|
|
106
99
|
|
|
107
100
|
## logs
|
|
108
101
|
|
|
109
|
-
Trigger phrases: "okstra container logs", "컨테이너 로그", "container logs", "로그 어디서 봐".
|
|
110
|
-
|
|
111
102
|
The live log stream lives in the tmux watcher pane, not in a file. This sub-command points at the watcher findings directory and the per-service watcher state.
|
|
112
103
|
|
|
113
104
|
```bash
|
|
@@ -126,8 +117,6 @@ Parse the stdout JSON (`{watchersDir, watchers}`). Report the `watchersDir` host
|
|
|
126
117
|
|
|
127
118
|
## stop-watcher
|
|
128
119
|
|
|
129
|
-
Trigger phrases: "okstra container stop-watcher", "watcher 멈춰", "감시 종료", "stop watcher", "watcher 만 꺼줘".
|
|
130
|
-
|
|
131
120
|
Reaps the watcher/tail tmux panes for the task **without stopping the containers**. Use when the user wants to silence the monitor but keep the build running.
|
|
132
121
|
|
|
133
122
|
```bash
|
|
@@ -140,8 +129,6 @@ Parse the stdout JSON (`{reapedPanes, note}`). Confirm which panes were reaped a
|
|
|
140
129
|
|
|
141
130
|
## down
|
|
142
131
|
|
|
143
|
-
Trigger phrases: "okstra container down", "컨테이너 내려", "컨테이너 종료", "container down", "전부 내려줘".
|
|
144
|
-
|
|
145
132
|
Tears down the container group (removes containers found by the run-trace label) and reaps orphan watcher panes.
|
|
146
133
|
|
|
147
134
|
Single task:
|
|
@@ -20,17 +20,17 @@ Only `.okstra/**/*.md` (final reports, `decisions/*.md`, `glossary.md`, briefs)
|
|
|
20
20
|
| `wiki` | Agent-crawlable wiki (`index.md` + one article per community). |
|
|
21
21
|
| `mcp` | Start a stdio MCP server exposing the graph to other agents (opt-in — additionally needs `pip install mcp`). |
|
|
22
22
|
|
|
23
|
-
## Step 0:
|
|
23
|
+
## Step 0: Preflight (shared)
|
|
24
24
|
|
|
25
|
-
Before any sub-command, run
|
|
25
|
+
Before any sub-command, run one Bash tool call, starting with the literal token `okstra` (never wrapped in `if`/`eval`/`export`/`$(...)`/`VAR=...`/`||`/`&&`/`npx` — a non-literal leading token defeats the `Bash(okstra:*)` permission match):
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
```bash
|
|
28
|
+
okstra preflight --runtime claude-code --json
|
|
29
|
+
```
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
- `ok: false` → before concluding "no setup", ask whether the user pointed at a specific project directory. If so, re-run `okstra check-project --cwd <that-dir> --json` (the leading `okstra` token keeps the permission match). Only if this **also** returns `ok:false` do you tell the user: "this project has no okstra setup. Run `/okstra-setup` first." Then stop.
|
|
31
|
+
Parse the stdout JSON:
|
|
32
|
+
- `ok: true` → carry `projectRoot` as a literal string; it is the `--project-root` value for every sub-command below.
|
|
33
|
+
- `ok: false` → before concluding "no setup", ask whether the user pointed at a specific project directory. If so, re-run `okstra preflight --runtime claude-code --cwd <that-dir> --json`. Only if this **also** returns `ok:false` do you tell the user: "this project has no okstra setup. Run `/okstra-setup` first." Then stop. If the call fails with `unknown command: preflight`, the `okstra` binary on PATH predates this skill — tell the user to update it (`npm i -g okstra@latest`), then stop (`/okstra-setup` does not update the binary).
|
|
34
34
|
|
|
35
35
|
Every `okstra graphify` call below passes `--project-root <projectRoot>` — `--project-root` is REQUIRED and there is no cwd injection; a bare `okstra graphify build` fails with a usage error.
|
|
36
36
|
|