okstra 0.20.0 → 0.21.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/docs/kr/architecture.md +1 -1
- package/docs/kr/performance-improvement-plan-v2.md +330 -0
- package/docs/kr/performance-improvement-plan.md +125 -0
- package/docs/project-structure-overview.md +386 -0
- package/docs/superpowers/plans/2026-05-14-convergence-queue-pruning.md +1568 -0
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/SKILL.md +7 -1
- package/runtime/agents/workers/codex-worker.md +6 -4
- package/runtime/agents/workers/gemini-worker.md +6 -4
- package/runtime/agents/workers/report-writer-worker.md +4 -0
- package/runtime/bin/okstra-codex-exec.sh +36 -6
- package/runtime/bin/okstra-gemini-exec.sh +6 -8
- package/runtime/prompts/profiles/final-verification.md +8 -2
- package/runtime/prompts/profiles/implementation-planning.md +1 -1
- package/runtime/prompts/profiles/release-handoff.md +26 -28
- package/runtime/prompts/profiles/requirements-discovery.md +1 -1
- package/runtime/python/okstra_ctl/render.py +78 -4
- package/runtime/python/okstra_ctl/run.py +0 -6
- package/runtime/python/okstra_ctl/run_context.py +5 -0
- package/runtime/python/okstra_ctl/workflow.py +8 -7
- package/runtime/python/okstra_ctl/worktree.py +155 -15
- package/runtime/python/okstra_token_usage/blocks.py +0 -2
- package/runtime/python/okstra_token_usage/claude.py +0 -2
- package/runtime/skills/okstra-brief/SKILL.md +523 -0
- package/runtime/skills/okstra-convergence/SKILL.md +149 -37
- package/runtime/skills/okstra-report-writer/SKILL.md +8 -6
- package/runtime/templates/prd/brief.template.md +12 -0
- package/runtime/templates/project-docs/task-index.template.md +12 -0
- package/runtime/templates/reports/error-analysis-input.template.md +12 -0
- package/runtime/templates/reports/final-report.template.md +39 -12
- package/runtime/templates/reports/final-verification-input.template.md +22 -0
- package/runtime/templates/reports/implementation-input.template.md +12 -0
- package/runtime/templates/reports/implementation-planning-input.template.md +12 -0
- package/runtime/templates/reports/quick-input.template.md +12 -0
- package/runtime/templates/reports/release-handoff-input.template.md +23 -10
- package/runtime/templates/reports/schedule.template.md +12 -0
- package/runtime/templates/reports/settings.template.json +83 -30
- package/runtime/templates/reports/task-brief.template.md +12 -0
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: okstra-brief
|
|
3
|
+
description: Use when the user wants to generate a task brief file for okstra from a requirements document, an existing markdown file, an issue-tracker ticket (Linear / Jira / GitHub / Notion), a link URL, conversation context, or short user input. Produces the markdown brief consumed by `okstra-run` Step 5 (task-brief). Trigger words include "okstra brief", "make a brief", "brief 생성", "요구사항 brief 만들어", "okstra 입력 만들어", "task brief 작성", "이 티켓으로 brief", "이 링크로 brief".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# okstra-brief
|
|
7
|
+
|
|
8
|
+
Generate a single `task brief` markdown file under the okstra project domain
|
|
9
|
+
(`.project-docs/okstra/briefs/<task-group>/<task-id>.md`) so it can be fed to
|
|
10
|
+
[`okstra-run`](../okstra-run/SKILL.md) as `--task-brief`.
|
|
11
|
+
|
|
12
|
+
This skill produces **only the brief** — a structured "request slip". It does
|
|
13
|
+
NOT write a PRD, decompose work into vertical slices, or decide modules.
|
|
14
|
+
Those belong to later okstra phases (`requirements-discovery`,
|
|
15
|
+
`implementation-planning`) which use cross-verification and would conflict
|
|
16
|
+
with anything decided here.
|
|
17
|
+
|
|
18
|
+
## Intended chain
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
okstra-brief
|
|
22
|
+
→ okstra-run (requirements-discovery | error-analysis)
|
|
23
|
+
→ okstra-run (implementation-planning)
|
|
24
|
+
→ okstra-run (implementation)
|
|
25
|
+
→ okstra-run (final-verification)
|
|
26
|
+
→ okstra-run (release-handoff)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## When to use
|
|
30
|
+
|
|
31
|
+
- The user pastes / points at a requirements doc, support ticket, bug report,
|
|
32
|
+
or rough description and wants to start the okstra pipeline.
|
|
33
|
+
- The user asks to "make a brief", "okstra 입력 만들어", "brief 생성", etc.
|
|
34
|
+
- A previous okstra task produced findings the user wants to convert into a
|
|
35
|
+
new follow-up task's brief.
|
|
36
|
+
|
|
37
|
+
## When NOT to use
|
|
38
|
+
|
|
39
|
+
- The user already has a brief file at a known path → skip to `okstra-run`.
|
|
40
|
+
- The user wants to write a full PRD with user stories and implementation
|
|
41
|
+
decisions → that's `to-prd`, not this. okstra phases will generate the
|
|
42
|
+
equivalent artifacts with cross-verification.
|
|
43
|
+
- The user wants to split work into issues → that's `to-issues`, and within
|
|
44
|
+
okstra it's the job of `implementation-planning`.
|
|
45
|
+
|
|
46
|
+
## Authority files
|
|
47
|
+
|
|
48
|
+
- `<PROJECT_ROOT>/.project-docs/okstra/project.json` — must exist; if not,
|
|
49
|
+
ask the user to run `okstra-setup` first.
|
|
50
|
+
- `<PROJECT_ROOT>/.project-docs/okstra/briefs/<task-group>/<ticket-id>-<file-title>.md`
|
|
51
|
+
(single / parent) or
|
|
52
|
+
`<PROJECT_ROOT>/.project-docs/okstra/briefs/<task-group>/sub/<ticket-id>-<file-title>.md`
|
|
53
|
+
(tracker child ticket; at depth N, `sub/` is nested N times) — output
|
|
54
|
+
location for this skill. `<ticket-id>` is the raw issue-id when the source
|
|
55
|
+
is a tracker, otherwise free-text supplied by the user. `<file-title>` is
|
|
56
|
+
auto-slugified from the tracker title, otherwise from user input. Never
|
|
57
|
+
write outside this tree. Never use `.scratch/` (that belongs to `to-prd` /
|
|
58
|
+
`to-issues`).
|
|
59
|
+
|
|
60
|
+
## Step 0: Resolve project root
|
|
61
|
+
|
|
62
|
+
Reuse the same disk-only resolution rule as `okstra-run`:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
if command -v okstra >/dev/null 2>&1; then
|
|
66
|
+
OKSTRA_CMD="okstra"
|
|
67
|
+
else
|
|
68
|
+
OKSTRA_CMD="npx -y okstra@latest"
|
|
69
|
+
fi
|
|
70
|
+
$OKSTRA_CMD check-project --cwd "$(pwd)"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
- `ok: true` → use `projectRoot`.
|
|
74
|
+
- `ok: false` → `AskUserQuestion` (free text) for an absolute project root, then
|
|
75
|
+
re-run `okstra check-project --cwd <input>`. If still not ok, tell the user
|
|
76
|
+
to run `okstra-setup` and stop.
|
|
77
|
+
|
|
78
|
+
## Step 1: Choose input source
|
|
79
|
+
|
|
80
|
+
`AskUserQuestion` (tool constraint: max 4 options):
|
|
81
|
+
|
|
82
|
+
- **Label**: "Source of this brief?"
|
|
83
|
+
- **Options** (single-select):
|
|
84
|
+
1. `File` — path to an existing markdown / txt / issue-export file
|
|
85
|
+
2. `Issue tracker ticket` — Linear / Jira / GitHub Issue / Notion key or URL
|
|
86
|
+
3. `Link URL` — general web page, blog, spec doc, design doc, etc.
|
|
87
|
+
4. `User input` — synthesize from the current conversation context, or
|
|
88
|
+
accept a short free-text from the user
|
|
89
|
+
(default: conversation synthesis. If context is thin, fall back to a
|
|
90
|
+
single free-text question.)
|
|
91
|
+
|
|
92
|
+
If the user wants to bundle multiple sources into one brief (e.g. "this
|
|
93
|
+
Linear ticket + this PR link"), repeat this step to collect them. Preserve
|
|
94
|
+
each source's raw content **separately** under the `Source Material
|
|
95
|
+
(verbatim)` section in Step 5.
|
|
96
|
+
|
|
97
|
+
### 1a. `File`
|
|
98
|
+
|
|
99
|
+
Take an absolute or project-relative path via free-text. Read the entire
|
|
100
|
+
file. Re-ask if it doesn't exist. Captured content is preserved **verbatim**
|
|
101
|
+
in Source Material.
|
|
102
|
+
|
|
103
|
+
### 1b. `Issue tracker ticket`
|
|
104
|
+
|
|
105
|
+
Order of operations:
|
|
106
|
+
|
|
107
|
+
1. `AskUserQuestion` (free text):
|
|
108
|
+
`"Ticket key or URL (e.g. LIN-1234, PROJ-42, https://linear.app/..., https://your.atlassian.net/browse/...)"` →
|
|
109
|
+
`ticket_ref`.
|
|
110
|
+
2. Auto-detect the tracker by URL host or key prefix (`linear.app` → Linear,
|
|
111
|
+
`atlassian.net` or `JIRA_*` pattern → Jira, `github.com/.../issues/` →
|
|
112
|
+
GitHub, `notion.so` → Notion). If detection fails, ask once more via
|
|
113
|
+
`AskUserQuestion`.
|
|
114
|
+
3. Check whether the tracker's **MCP tools** are loaded in the current
|
|
115
|
+
session and prefer them when available:
|
|
116
|
+
- Linear → `mcp__linear__*` family (e.g. `get_issue` /
|
|
117
|
+
`getIssueByIdentifier`). If absent, try `ToolSearch` with the keyword
|
|
118
|
+
`linear` — it auto-waits for connecting MCP servers.
|
|
119
|
+
- Jira → `mcp__jira__*` (or `mcp__atlassian__*`). Same `ToolSearch`
|
|
120
|
+
fallback.
|
|
121
|
+
- GitHub → `gh issue view <num> --repo <owner>/<repo> --json title,body,comments,labels,state`
|
|
122
|
+
(an authenticated `gh` CLI is the default path — usable even when MCP
|
|
123
|
+
is present). If `gh` is missing or unauthenticated, try `ToolSearch`
|
|
124
|
+
for `mcp__github` family; otherwise fall through to step 4 (paste /
|
|
125
|
+
skip).
|
|
126
|
+
- Notion → `mcp__notion__API-retrieve-a-page` /
|
|
127
|
+
`API-get-block-children`.
|
|
128
|
+
4. If **no** MCP or CLI path is available:
|
|
129
|
+
- Ask the user via `AskUserQuestion`:
|
|
130
|
+
`"<tracker> MCP is not connected. (a) Paste the ticket body here / (b) Skip this source"`.
|
|
131
|
+
- Never invent ticket content.
|
|
132
|
+
5. Preserve the retrieved fields (summary/title, description body, comments,
|
|
133
|
+
status, labels, assignee, linked issues) **verbatim** in Source Material.
|
|
134
|
+
When format conversion is required (e.g. Jira ADF → MD), **do not
|
|
135
|
+
paraphrase semantics** — format-only conversion is allowed. Note the
|
|
136
|
+
conversion on one line (`format: Jira ADF → Markdown (semantics
|
|
137
|
+
preserved)`).
|
|
138
|
+
|
|
139
|
+
6. **Sub-ticket / child-issue / sub-task handling — recursive**:
|
|
140
|
+
- Look at child references in the fetched ticket response:
|
|
141
|
+
- Linear: `children` / `subIssues` field
|
|
142
|
+
- Jira: `subtasks` (or `issuelinks` with the `is parent of` relation)
|
|
143
|
+
- GitHub: task-list checkbox `#NNN` references + `tracked_issues`
|
|
144
|
+
(when present)
|
|
145
|
+
- Notion: child pages / sub-pages
|
|
146
|
+
- If there is **one or more** child, ask **once at the top parent**:
|
|
147
|
+
- `AskUserQuestion` (single-select)
|
|
148
|
+
- **Label**: `"This ticket has sub-tickets. How should the child tree be handled?"`
|
|
149
|
+
- **Options**:
|
|
150
|
+
1. `Generate the full tree recursively (recommended)` — walk
|
|
151
|
+
children, grandchildren, … via BFS/DFS and emit one brief per
|
|
152
|
+
node.
|
|
153
|
+
2. `Parent only; list children in Related Artifacts` — single
|
|
154
|
+
brief. Children are not fetched, only their keys/URLs are
|
|
155
|
+
recorded.
|
|
156
|
+
3. `Generate selected children only` — multi-select the direct
|
|
157
|
+
children; for each chosen child, apply option-1 policy
|
|
158
|
+
recursively to that branch.
|
|
159
|
+
- For options 1 / 3, **recurse into Step 1b sub-steps 3–5** for every
|
|
160
|
+
descendant. No depth limit. Maintain a visited set of
|
|
161
|
+
`<tracker>:<ticket-id>` to prevent cycles; on revisit, do not emit a
|
|
162
|
+
new brief — only add a link back to the existing brief.
|
|
163
|
+
- Each descendant's brief file at depth N is created under
|
|
164
|
+
`<task-group>/<sub/ nested N times>/<ticket-id>-<file-title>.md` per
|
|
165
|
+
Step 2b.
|
|
166
|
+
- Each node's `Related Artifacts` should list:
|
|
167
|
+
- The parent brief's relative path (`../<ticket-id>-<file-title>.md`)
|
|
168
|
+
- All direct children briefs' relative paths
|
|
169
|
+
(`sub/<ticket-id>-<file-title>.md`)
|
|
170
|
+
bidirectionally. (Non-direct ancestors/descendants are tracked via the
|
|
171
|
+
frontmatter `parent-id` chain.)
|
|
172
|
+
- If there are no children, proceed with a single brief (depth 0).
|
|
173
|
+
|
|
174
|
+
### 1c. `Link URL`
|
|
175
|
+
|
|
176
|
+
Order of operations:
|
|
177
|
+
|
|
178
|
+
1. `AskUserQuestion` (free text): `"Link URL"`.
|
|
179
|
+
2. Fetch directly via `WebFetch`. If `WebFetch` is deferred, load its schema
|
|
180
|
+
first via `ToolSearch` with `select:WebFetch`.
|
|
181
|
+
3. On fetch failure or auth required (login wall, intranet-only, etc.):
|
|
182
|
+
- Ask the user via `AskUserQuestion` to paste the body.
|
|
183
|
+
- Never invent URL content.
|
|
184
|
+
4. Preserve the core content (title + body + quotes/examples) **verbatim**
|
|
185
|
+
in Source Material. For very large pages, respect the ~400-line per-brief
|
|
186
|
+
guideline and **excerpt key paragraphs only**, but do not modify or
|
|
187
|
+
summarize the excerpted text by a single character. Annotate the excerpt
|
|
188
|
+
with `[excerpt — full: <URL>]`.
|
|
189
|
+
|
|
190
|
+
### 1d. `User input`
|
|
191
|
+
|
|
192
|
+
Two sub-modes combined under one option.
|
|
193
|
+
|
|
194
|
+
- **Conversation synthesis**: do not re-interview. Synthesize from the
|
|
195
|
+
current conversation (mirrors `to-prd`'s "synthesize, don't interview").
|
|
196
|
+
Label Source Material as `conversation synthesis` and quote key
|
|
197
|
+
utterances verbatim wherever possible.
|
|
198
|
+
- **Inline input**: if conversation context is empty or thin, take one
|
|
199
|
+
free-text `AskUserQuestion`. The received text is preserved in Source
|
|
200
|
+
Material without changing a character.
|
|
201
|
+
|
|
202
|
+
When both are used, record them as two separate sub-sources under Source
|
|
203
|
+
Material.
|
|
204
|
+
|
|
205
|
+
## Step 2: Identify task key & filename
|
|
206
|
+
|
|
207
|
+
### 2a. Task group
|
|
208
|
+
|
|
209
|
+
`AskUserQuestion` (free text):
|
|
210
|
+
|
|
211
|
+
- `"Task group (e.g. backend-api, INV-1234, refactor)"` → `task_group`
|
|
212
|
+
|
|
213
|
+
Slug rule: same as `okstra-run` Step 3 — slugify, must have at least one
|
|
214
|
+
alphanumeric character.
|
|
215
|
+
|
|
216
|
+
### 2b. Filename per source type
|
|
217
|
+
|
|
218
|
+
Final brief path rule (fixed; one extra `sub/` per depth):
|
|
219
|
+
|
|
220
|
+
```
|
|
221
|
+
depth 0 (parent / single) : <PROJECT_ROOT>/.project-docs/okstra/briefs/<task-group>/<ticket-id>-<file-title>.md
|
|
222
|
+
depth 1 (child) : <PROJECT_ROOT>/.project-docs/okstra/briefs/<task-group>/sub/<ticket-id>-<file-title>.md
|
|
223
|
+
depth 2 (grandchild) : <PROJECT_ROOT>/.project-docs/okstra/briefs/<task-group>/sub/sub/<ticket-id>-<file-title>.md
|
|
224
|
+
depth N : <PROJECT_ROOT>/.project-docs/okstra/briefs/<task-group>/<sub/ nested N times>/<ticket-id>-<file-title>.md
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
`<sub/ nested N times>` is a meta-notation; the actual path concatenates
|
|
228
|
+
`sub/` N times (e.g. depth 3 → `sub/sub/sub/`). Create the directories
|
|
229
|
+
recursively as needed. No upper bound on tree depth. All parent-child
|
|
230
|
+
relations are also tracked via the brief's `parent-id` frontmatter
|
|
231
|
+
(directory layout + frontmatter both).
|
|
232
|
+
|
|
233
|
+
`<ticket-id>` resolution:
|
|
234
|
+
|
|
235
|
+
- **Issue-tracker sources (Step 1b)**: the **raw issue-id / ticket-id**
|
|
236
|
+
assigned by the tracker.
|
|
237
|
+
- Linear `LIN-1234` → `LIN-1234`
|
|
238
|
+
- Jira `PROJ-42` → `PROJ-42`
|
|
239
|
+
- GitHub `owner/repo#123` → `gh-<repo>-123`
|
|
240
|
+
- Notion (no canonical id) → `notion-<8-char-page-short-id>`
|
|
241
|
+
- **File / URL / User-input sources**: `AskUserQuestion` (free text):
|
|
242
|
+
- `"Ticket / identifier (e.g. dev-9043, INV-1234, login-error)"` →
|
|
243
|
+
`ticket_id`
|
|
244
|
+
|
|
245
|
+
`<file-title>` resolution:
|
|
246
|
+
|
|
247
|
+
- **Issue-tracker sources**: auto-generated from the ticket title / summary —
|
|
248
|
+
do not ask the user.
|
|
249
|
+
1. Keep alphanumerics, spaces, Hangul; drop everything else
|
|
250
|
+
2. Replace spaces with `-`
|
|
251
|
+
3. Lowercase (Hangul untouched)
|
|
252
|
+
4. Cut to 60 chars at a word boundary (hard-cut at 60 if no boundary)
|
|
253
|
+
5. Trim leading/trailing `-`
|
|
254
|
+
- Example: Linear `LIN-1234 "Fix flaky login retry on 5xx"` →
|
|
255
|
+
`LIN-1234-fix-flaky-login-retry-on-5xx.md`
|
|
256
|
+
- **Other sources**: `AskUserQuestion` (free text):
|
|
257
|
+
- `"File title (short summary, e.g. fix-login-retry, dev-9043-brief)"` →
|
|
258
|
+
`file_title`
|
|
259
|
+
- Apply rules 1–5 above. Re-ask on empty input.
|
|
260
|
+
|
|
261
|
+
Validate the full `<ticket-id>-<file-title>` slug: must have at least one
|
|
262
|
+
alphanumeric character after slugification. Apply Step 2c on collision.
|
|
263
|
+
|
|
264
|
+
### 2c. Collision handling
|
|
265
|
+
|
|
266
|
+
If a brief file already exists, `AskUserQuestion` with (`Skip if exists` /
|
|
267
|
+
`Append timestamp suffix` / `Overwrite`). Default recommendation: `Skip if
|
|
268
|
+
exists` — protects briefs the user has already edited.
|
|
269
|
+
|
|
270
|
+
When multiple collisions occur in tracker multi-generation mode:
|
|
271
|
+
|
|
272
|
+
- First echo the colliding file list to the user.
|
|
273
|
+
- Ask **once** with `AskUserQuestion` for a bulk policy.
|
|
274
|
+
- **Even when `Overwrite` is selected, confirm one more time for each
|
|
275
|
+
colliding file**, or warn that downgrading to `Append timestamp suffix`
|
|
276
|
+
is safer. Silent bulk overwrite is forbidden.
|
|
277
|
+
|
|
278
|
+
## Step 3: Light context scan (optional but recommended)
|
|
279
|
+
|
|
280
|
+
Only when the source material references project-specific terms or files:
|
|
281
|
+
|
|
282
|
+
- Read `CONTEXT.md` / `docs/adr/` at repo root if present (domain vocabulary).
|
|
283
|
+
- Resolve any file paths or symbols mentioned in the source so the brief uses
|
|
284
|
+
the project's domain language, not generic phrasing.
|
|
285
|
+
|
|
286
|
+
Skip this step for purely external request material.
|
|
287
|
+
|
|
288
|
+
## Step 4: Fill in missing fields (NO full interview)
|
|
289
|
+
|
|
290
|
+
> **Verbatim-source rule**: Source Material collected in Step 1 must never
|
|
291
|
+
> be paraphrased, summarized, or restructured. When supplementing missing
|
|
292
|
+
> information, write only into the dedicated `Augmentation` section (see
|
|
293
|
+
> Step 5); never modify Source Material by a single byte.
|
|
294
|
+
|
|
295
|
+
Inspect the synthesized brief draft. For each REQUIRED section below that is
|
|
296
|
+
empty or trivially thin **after** reading Source Material verbatim, ask **at
|
|
297
|
+
most one** `AskUserQuestion` (free text) to fill it. Never ask about sections
|
|
298
|
+
already covered by the source material.
|
|
299
|
+
|
|
300
|
+
Augmentation content must always be confined to the `Augmentation` section
|
|
301
|
+
or to a `> augmented:` blockquote inside the required section, so it is
|
|
302
|
+
clear that the content is the skill's / user's added interpretation rather
|
|
303
|
+
than the original source.
|
|
304
|
+
|
|
305
|
+
### Step 4 policy under multi-brief (tracker recursion) mode
|
|
306
|
+
|
|
307
|
+
When emitting a parent + N children at once, repeating the Step 4 interview
|
|
308
|
+
per brief ruins the UX. In this mode:
|
|
309
|
+
|
|
310
|
+
- **Run Step 4 interview only on the parent (depth 0) brief.**
|
|
311
|
+
- **Skip Step 4 prompts for children (depth ≥ 1)** — fill only their Source
|
|
312
|
+
Material. If required sections are empty, leave them as `_(none)_`. The
|
|
313
|
+
safer default is to let `requirements-discovery` fill child gaps later.
|
|
314
|
+
- Only when the user explicitly says "interview the children too" do we run
|
|
315
|
+
per-child Step 4.
|
|
316
|
+
|
|
317
|
+
Required sections:
|
|
318
|
+
|
|
319
|
+
- **Context** — background; what system/feature, who's affected, why now.
|
|
320
|
+
- **Problem / Symptom** — current state. For bugs: repro + observed/expected;
|
|
321
|
+
for greenfield: gap between current and desired.
|
|
322
|
+
- **Desired Outcome** — success shape, not a solution prescription.
|
|
323
|
+
- **Constraints** — deadlines, compatibility, technical/operational limits.
|
|
324
|
+
- **Related Artifacts** — files, URLs, issues, prior task-keys.
|
|
325
|
+
- **Open Questions** — anything the user already flagged as undecided
|
|
326
|
+
(becomes raw material for `requirements-discovery`).
|
|
327
|
+
|
|
328
|
+
Sections **deliberately omitted** (do NOT add them, do NOT prompt for them):
|
|
329
|
+
|
|
330
|
+
- User stories
|
|
331
|
+
- Module decomposition / implementation decisions
|
|
332
|
+
- Testing strategy
|
|
333
|
+
- Vertical-slice breakdown
|
|
334
|
+
|
|
335
|
+
Those belong to later okstra phases.
|
|
336
|
+
|
|
337
|
+
## Step 5: Write the brief(s)
|
|
338
|
+
|
|
339
|
+
Use the same template per brief file. In tracker mode producing a parent
|
|
340
|
+
plus N children, you write **N+1 files** (each carries only its own Source
|
|
341
|
+
Material).
|
|
342
|
+
|
|
343
|
+
Use this exact template. Leave a section's body as `_(none)_` rather than
|
|
344
|
+
fabricating content. (The outer fence uses 4 backticks so it does not
|
|
345
|
+
collide with the inner 3-backtick code block.)
|
|
346
|
+
|
|
347
|
+
````markdown
|
|
348
|
+
---
|
|
349
|
+
type: brief
|
|
350
|
+
brief-id: <ticket-id>-<file-title> # equals the filename stem
|
|
351
|
+
parent-id: self # `self` at root, otherwise parent's brief-id
|
|
352
|
+
ticket-id: <LIN-1234 | PROJ-42 | gh-repo-123 | notion-abcdef12 | "">
|
|
353
|
+
source-type: <file | linear | jira | github | notion | url | user-input>
|
|
354
|
+
task-group: <task-group>
|
|
355
|
+
depth: 0 # 0=parent/single, 1=child, 2=grandchild, ...
|
|
356
|
+
created: <YYYY-MM-DD>
|
|
357
|
+
generator: okstra-brief
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
# Task Brief: <task_group>/<filename-without-ext>
|
|
361
|
+
|
|
362
|
+
> Generated: okstra-brief · <YYYY-MM-DD>
|
|
363
|
+
> Source type: <file | linear | jira | github | notion | url | user-input>
|
|
364
|
+
> Tracker key (if any): <LIN-1234 | PROJ-42 | gh-repo-123 | notion-abcdef12>
|
|
365
|
+
> Parent brief (child briefs only): <relative path>
|
|
366
|
+
> Recommended next phase: <requirements-discovery | error-analysis> ← from Step 6
|
|
367
|
+
|
|
368
|
+
## Source Material (verbatim — do not modify)
|
|
369
|
+
|
|
370
|
+
Paste each source separately and as-is. No paraphrasing, summarizing, or
|
|
371
|
+
restructuring. Format conversion (e.g. Jira ADF → Markdown) is allowed and
|
|
372
|
+
must be annotated in the header meta.
|
|
373
|
+
|
|
374
|
+
### Source 1 — <type: file | linear | jira | github | notion | url | user-input>
|
|
375
|
+
|
|
376
|
+
- ref: <abs file path | LIN-1234 | https://... | "conversation synthesis">
|
|
377
|
+
- fetched-via: <Read | mcp__linear__getIssue | mcp__notion__... | gh issue view | WebFetch | user-paste>
|
|
378
|
+
- fetched-at: <YYYY-MM-DD HH:MM>
|
|
379
|
+
- format: <as-is | "Jira ADF → Markdown (semantics preserved)" | "excerpt — full: <URL>">
|
|
380
|
+
|
|
381
|
+
```
|
|
382
|
+
<Paste the raw source here without changing a single character.>
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### Source 2 — ...
|
|
386
|
+
|
|
387
|
+
(Repeat as needed.)
|
|
388
|
+
|
|
389
|
+
## Context
|
|
390
|
+
|
|
391
|
+
<Background / scope / why now. If self-evident from Source Material, quote
|
|
392
|
+
it briefly and stop. Use the blockquote below when augmentation is needed.>
|
|
393
|
+
|
|
394
|
+
> augmented: <Interpretation added by the skill or user. Do NOT add any
|
|
395
|
+
> extra interpretation outside this blockquote.>
|
|
396
|
+
|
|
397
|
+
## Problem / Symptom
|
|
398
|
+
|
|
399
|
+
<Current state. For bugs: repro / observed / expected. For greenfield: gap
|
|
400
|
+
between current and desired. Same source-quote + `> augmented:` rule as
|
|
401
|
+
above.>
|
|
402
|
+
|
|
403
|
+
## Desired Outcome
|
|
404
|
+
|
|
405
|
+
<Shape of success. Do NOT prescribe a solution — that belongs to
|
|
406
|
+
implementation-planning.>
|
|
407
|
+
|
|
408
|
+
## Constraints
|
|
409
|
+
|
|
410
|
+
<Deadlines, compatibility, technical/operational limits. Use _(none)_ if
|
|
411
|
+
none.>
|
|
412
|
+
|
|
413
|
+
## Related Artifacts
|
|
414
|
+
|
|
415
|
+
- <file path / URL / issue / prior task-key>
|
|
416
|
+
|
|
417
|
+
## Open Questions
|
|
418
|
+
|
|
419
|
+
- <Unresolved questions the user flagged. _(none)_ if none.>
|
|
420
|
+
|
|
421
|
+
## Augmentation
|
|
422
|
+
|
|
423
|
+
Cross-references / interpretation / context added by the user or skill that
|
|
424
|
+
is not in the original source. May be empty. Keep this section visually
|
|
425
|
+
separated from Source Material — never inline it inside Source Material.
|
|
426
|
+
|
|
427
|
+
- _(none)_ or `- <augmentation>`
|
|
428
|
+
````
|
|
429
|
+
|
|
430
|
+
### Frontmatter rules
|
|
431
|
+
|
|
432
|
+
- Every brief starts on line 1 with a YAML frontmatter delimited by `---`.
|
|
433
|
+
- `type: brief` is a fixed value.
|
|
434
|
+
- `brief-id` must match the filename stem (`<ticket-id>-<file-title>`)
|
|
435
|
+
exactly. If the file is moved/renamed, update both.
|
|
436
|
+
- `parent-id`:
|
|
437
|
+
- The root (depth 0) brief uses `self` (or its own `brief-id`).
|
|
438
|
+
- Descendant briefs use the direct parent's `brief-id`.
|
|
439
|
+
- `depth` must equal the number of `sub/` segments in the path (consistency
|
|
440
|
+
check point). On mismatch, the file location wins — correct the
|
|
441
|
+
frontmatter.
|
|
442
|
+
- `ticket-id` is populated only for tracker sources; leave it as an empty
|
|
443
|
+
string otherwise.
|
|
444
|
+
|
|
445
|
+
Echo the file path back on one line. Show the rendered brief to the user
|
|
446
|
+
inline and ask:
|
|
447
|
+
|
|
448
|
+
`AskUserQuestion`: `"Proceed with this brief?"` — options `Save` / `Edit`.
|
|
449
|
+
On `Edit`, return to Step 4 for the section to revise.
|
|
450
|
+
|
|
451
|
+
## Step 6: Recommend next okstra phase
|
|
452
|
+
|
|
453
|
+
In multi-brief mode, **evaluate each brief independently** with the rules
|
|
454
|
+
below (parent and child recommendations may differ).
|
|
455
|
+
|
|
456
|
+
Inspect the finalized brief and recommend the next `okstra-run` task-type:
|
|
457
|
+
|
|
458
|
+
| Heuristic | Recommendation |
|
|
459
|
+
|---|---|
|
|
460
|
+
| `Problem / Symptom` describes a repro / log / stack trace / observable error | `error-analysis` |
|
|
461
|
+
| `Open Questions` is large or `Desired Outcome` is ambiguous / needs classification | `requirements-discovery` |
|
|
462
|
+
| Both / ambiguous | `requirements-discovery` (safe default — the phase itself decides branching) |
|
|
463
|
+
|
|
464
|
+
Write the chosen recommendation into the `Recommended next phase:` header
|
|
465
|
+
line of the brief file (Step 5). Do NOT auto-spawn `okstra-run` — leave the
|
|
466
|
+
trigger to the user.
|
|
467
|
+
|
|
468
|
+
## Step 7: Hand off
|
|
469
|
+
|
|
470
|
+
Single brief:
|
|
471
|
+
|
|
472
|
+
```
|
|
473
|
+
brief saved: <abs-path>
|
|
474
|
+
next: /okstra-run (recommended task-type: <…>)
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
Multi-brief (tracker parent + children) — echo all in one block. Keep the
|
|
478
|
+
`sub/` prefix visible by emitting the absolute path verbatim:
|
|
479
|
+
|
|
480
|
+
```
|
|
481
|
+
briefs saved (N):
|
|
482
|
+
- <abs>/<task-group>/<ticket-id>-<title>.md (depth 0 · parent · recommended: <…>)
|
|
483
|
+
- <abs>/<task-group>/sub/<ticket-id>-<title>.md (depth 1 · child · recommended: <…>)
|
|
484
|
+
- <abs>/<task-group>/sub/sub/<ticket-id>-<title>.md (depth 2 · grand · recommended: <…>)
|
|
485
|
+
next: /okstra-run (run a separate task-key per brief — use the filename stem as task-id)
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
Then stop. Do not invoke `okstra-run` directly — the user chooses when to
|
|
489
|
+
proceed, and they may want to edit the brief externally first. In the
|
|
490
|
+
multi-brief case the user also decides the order in which tasks are
|
|
491
|
+
started.
|
|
492
|
+
|
|
493
|
+
## Output Rules
|
|
494
|
+
|
|
495
|
+
- Never write outside `<PROJECT_ROOT>/.project-docs/okstra/briefs/`.
|
|
496
|
+
- Never write to `.scratch/` — that path belongs to `to-prd` / `to-issues`.
|
|
497
|
+
- **Verbatim source**: never paraphrase, summarize, restructure, or reorder
|
|
498
|
+
the Source Material section. Only format conversion (ADF → MD, HTML → MD)
|
|
499
|
+
is allowed, and the conversion must be annotated in the `format:` meta.
|
|
500
|
+
Augmentation / interpretation goes only into the `Augmentation` section
|
|
501
|
+
or a `> augmented:` blockquote inside the required section.
|
|
502
|
+
- If the tracker MCP is not connected, do not guess — ask the user to paste
|
|
503
|
+
the body or skip the source.
|
|
504
|
+
- If a URL fetch fails or hits an auth wall, do not guess — ask for a
|
|
505
|
+
paste.
|
|
506
|
+
- Never fabricate content for empty sections; use `_(none)_`.
|
|
507
|
+
- Echo each `AskUserQuestion` outcome on one short line.
|
|
508
|
+
- Aim for ~400 lines per brief total. If the source body is longer, **do
|
|
509
|
+
not modify** it — instead excerpt key paragraphs with the
|
|
510
|
+
`[excerpt — full: <URL>]` marker and record the original location in
|
|
511
|
+
`Related Artifacts`.
|
|
512
|
+
|
|
513
|
+
## Failure Modes
|
|
514
|
+
|
|
515
|
+
| Symptom | Cause | Fix |
|
|
516
|
+
|---|---|---|
|
|
517
|
+
| `project.json not found` | okstra not set up in this project | Tell user to run `okstra-setup`; stop. |
|
|
518
|
+
| `briefs/<group>/<id>.md already exists` | duplicate task-key | Step 2c overwrite prompt. |
|
|
519
|
+
| Source file not found | bad path in Step 1 | Re-ask. |
|
|
520
|
+
| Linear/Jira MCP not connected | tracker MCP missing from the session | Try `ToolSearch` once → if still missing, ask the user to paste the body. Never guess. |
|
|
521
|
+
| URL fetch fails or 401 / login wall | intranet, paywall, JS-rendered page | Ask the user to paste the core body. Never guess. |
|
|
522
|
+
| Tracker body is in non-MD format (ADF / HTML) | Jira description, Notion blocks | Convert format only, preserve semantics. Annotate the conversion in the `format:` meta. |
|
|
523
|
+
| Brief comes out skeletal after synthesis | source too thin AND user picked `User input` with little context | Switch to inline input mode and ask one or two targeted questions. |
|